Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: lib/compiler/implementation/native_handler.dart

Issue 10558023: New treatment of native methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #library('native'); 5 #library('native');
6 #import('dart:uri'); 6 #import('dart:uri');
7 #import('leg.dart'); 7 #import('leg.dart');
8 #import('elements/elements.dart'); 8 #import('elements/elements.dart');
9 #import('scanner/scannerlib.dart'); 9 #import('scanner/scannerlib.dart');
10 #import('ssa/ssa.dart'); 10 #import('ssa/ssa.dart');
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 } 73 }
74 74
75 void maybeEnableNative(Compiler compiler, 75 void maybeEnableNative(Compiler compiler,
76 LibraryElement library, 76 LibraryElement library,
77 Uri uri) { 77 Uri uri) {
78 String libraryName = uri.toString(); 78 String libraryName = uri.toString();
79 if (library.script.name.contains('dart/tests/compiler/dart2js_native') 79 if (library.script.name.contains('dart/tests/compiler/dart2js_native')
80 || libraryName == 'dart:dom_deprecated' 80 || libraryName == 'dart:dom_deprecated'
81 || libraryName == 'dart:isolate' 81 || libraryName == 'dart:isolate'
82 || libraryName == 'dart:html') { 82 || libraryName == 'dart:html') {
83 library.define(new ForeignElement(
84 const SourceString('native'), library), compiler);
85 library.canUseNative = true; 83 library.canUseNative = true;
86 if (compiler.jsIndexingBehaviorInterface !== null) { 84 if (compiler.jsIndexingBehaviorInterface !== null) {
87 library.define(compiler.jsIndexingBehaviorInterface, compiler); 85 library.define(compiler.jsIndexingBehaviorInterface, compiler);
88 } 86 }
89 } 87 }
90 88
91 // Additionaly, if this is a test, we allow access to foreign functions. 89 // Additionaly, if this is a test, we allow access to foreign functions.
92 if (library.script.name.contains('dart/tests/compiler/dart2js_native')) { 90 if (library.script.name.contains('dart/tests/compiler/dart2js_native')) {
93 library.define(compiler.findHelper(const SourceString('JS')), compiler); 91 library.define(compiler.findHelper(const SourceString('JS')), compiler);
94 } 92 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 checkAllowedLibrary(listener, token); 132 checkAllowedLibrary(listener, token);
135 token = token.next; 133 token = token.next;
136 if (token.kind !== STRING_TOKEN) { 134 if (token.kind !== STRING_TOKEN) {
137 listener.unexpected(token); 135 listener.unexpected(token);
138 } else { 136 } else {
139 token = token.next; 137 token = token.next;
140 } 138 }
141 return token; 139 return token;
142 } 140 }
143 141
144 RegExp nativeRedirectionRegExp = const RegExp(@'^[a-zA-Z][a-zA-Z_$0-9]*$');
145
146 Token handleNativeFunctionBody(ElementListener listener, Token token) { 142 Token handleNativeFunctionBody(ElementListener listener, Token token) {
147 checkAllowedLibrary(listener, token); 143 checkAllowedLibrary(listener, token);
148 Token begin = token; 144 Token begin = token;
149 listener.beginExpressionStatement(token); 145 listener.beginReturnStatement(token);
150 listener.handleIdentifier(token);
151 token = token.next; 146 token = token.next;
147 bool hasExpression = false;
152 if (token.kind === STRING_TOKEN) { 148 if (token.kind === STRING_TOKEN) {
149 hasExpression = true;
153 listener.beginLiteralString(token); 150 listener.beginLiteralString(token);
154 listener.endLiteralString(0); 151 listener.endLiteralString(0);
155 LiteralString str = listener.popNode();
156 listener.pushNode(new NodeList.singleton(str));
157 listener.endSend(token);
158 token = token.next; 152 token = token.next;
159 // If this native method is just redirecting to another method,
160 // we add a return node to match the SSA builder expectations.
161 if (nativeRedirectionRegExp.hasMatch(str.dartString.slowToString())) {
162 listener.endReturnStatement(true, begin, token);
163 } else {
164 listener.endExpressionStatement(token);
Anton Muhin 2012/06/18 10:04:52 now we treat all natives as returns, even though t
sra1 2012/06/20 18:29:05 I'm not sure that makes sense; some of the native
Anton Muhin 2012/06/20 18:51:49 Stephen, both Peter and me are well aware of this
165 }
166 } else {
167 listener.pushNode(new NodeList.empty());
168 listener.endSend(token);
169 listener.endReturnStatement(true, begin, token);
170 } 153 }
171 listener.endFunctionBody(1, begin, token); 154 listener.endReturnStatement(hasExpression, begin, token);
172 // TODO(ngeoffray): expect a ';'. 155 /* Fails thanks to lib/isolate/frog/isolateimpl.dart:143 --- native method w/ Dart body.
Anton Muhin 2012/06/18 10:04:52 is it valid Dart? I mean code in isolateimpl.dart
ahe 2012/06/18 10:37:39 No. Nothing about "native" is valid Dart.
sra1 2012/06/20 18:29:05 Native methods with both a string JavaScript body
Anton Muhin 2012/06/20 18:51:49 Thanks a lot for clarifications. I wonder if it w
156 if (';' !== token.stringValue) {
157 return listener.expected(';', token);
158 }
159 */
173 return token.next; 160 return token.next;
174 } 161 }
175 162
176 SourceString checkForNativeClass(ElementListener listener) { 163 SourceString checkForNativeClass(ElementListener listener) {
177 SourceString nativeName; 164 SourceString nativeName;
178 Node node = listener.nodes.head; 165 Node node = listener.nodes.head;
179 if (node != null 166 if (node != null
180 && node.asIdentifier() != null 167 && node.asIdentifier() != null
181 && node.asIdentifier().source.stringValue == 'native') { 168 && node.asIdentifier().source.stringValue == 'native') {
182 nativeName = node.asIdentifier().token.next.value; 169 nativeName = node.asIdentifier().token.next.value;
183 listener.popNode(); 170 listener.popNode();
184 } 171 }
185 return nativeName; 172 return nativeName;
186 } 173 }
187 174
188 bool isOverriddenMethod(FunctionElement element, 175 bool isOverriddenMethod(FunctionElement element,
189 ClassElement cls, 176 ClassElement cls,
190 NativeEmitter nativeEmitter) { 177 NativeEmitter nativeEmitter) {
191 List<ClassElement> subtypes = nativeEmitter.subtypes[cls]; 178 List<ClassElement> subtypes = nativeEmitter.subtypes[cls];
192 if (subtypes == null) return false; 179 if (subtypes == null) return false;
193 for (ClassElement subtype in subtypes) { 180 for (ClassElement subtype in subtypes) {
194 if (subtype.lookupLocalMember(element.name) != null) return true; 181 if (subtype.lookupLocalMember(element.name) != null) return true;
195 } 182 }
196 return false; 183 return false;
197 } 184 }
198 185
199 void handleSsaNative(SsaBuilder builder, Send node) { 186 void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
200 Compiler compiler = builder.compiler; 187 Compiler compiler = builder.compiler;
201 FunctionElement element = builder.work.element; 188 FunctionElement element = builder.work.element;
202 element.setNative(); 189 element.setNative();
203 NativeEmitter nativeEmitter = builder.emitter.nativeEmitter; 190 NativeEmitter nativeEmitter = builder.emitter.nativeEmitter;
204 // If what we're compiling is a getter named 'typeName' and the native 191 // If what we're compiling is a getter named 'typeName' and the native
205 // class is named 'DOMType', we generate a call to the typeNameOf 192 // class is named 'DOMType', we generate a call to the typeNameOf
206 // function attached on the isolate. 193 // function attached on the isolate.
207 // The DOM classes assume that their 'typeName' property, which is 194 // The DOM classes assume that their 'typeName' property, which is
208 // not a JS property on the DOM types, returns the type name. 195 // not a JS property on the DOM types, returns the type name.
209 if (element.name == const SourceString('typeName') 196 if (element.name == const SourceString('typeName')
210 && element.isGetter() 197 && element.isGetter()
211 && nativeEmitter.toNativeName(element.enclosingElement) == 'DOMType') { 198 && nativeEmitter.toNativeName(element.enclosingElement) == 'DOMType') {
212 Element methodElement = 199 Element methodElement =
213 compiler.findHelper(const SourceString('getTypeNameOf')); 200 compiler.findHelper(const SourceString('getTypeNameOf'));
214 HStatic method = new HStatic(methodElement); 201 HStatic method = new HStatic(methodElement);
215 builder.add(method); 202 builder.add(method);
216 builder.push(new HInvokeStatic(Selector.INVOCATION_1, 203 builder.push(new HInvokeStatic(Selector.INVOCATION_1,
217 <HInstruction>[method, builder.localsHandler.readThis()])); 204 <HInstruction>[method, builder.localsHandler.readThis()]));
218 return; 205 return true;
219 } 206 }
220 207
221 HInstruction convertDartClosure(Element parameter, FunctionType type) { 208 HInstruction convertDartClosure(Element parameter, FunctionType type) {
222 HInstruction local = builder.localsHandler.readLocal(parameter); 209 HInstruction local = builder.localsHandler.readLocal(parameter);
223 // TODO(ngeoffray): For static methods, we could pass a method with a 210 // TODO(ngeoffray): For static methods, we could pass a method with a
224 // defined arity. 211 // defined arity.
225 builder.push(new HStatic(builder.interceptors.getClosureConverter())); 212 builder.push(new HStatic(builder.interceptors.getClosureConverter()));
226 HInstruction arity = builder.graph.addConstantInt(type.computeArity()); 213 HInstruction arity = builder.graph.addConstantInt(type.computeArity());
227 List<HInstruction> callInputs = <HInstruction>[builder.pop(), local, arity]; 214 List<HInstruction> callInputs = <HInstruction>[builder.pop(), local, arity];
228 HInstruction closure = new HInvokeStatic(Selector.INVOCATION_1, callInputs); 215 HInstruction closure = new HInvokeStatic(Selector.INVOCATION_1, callInputs);
229 builder.add(closure); 216 builder.add(closure);
230 return closure; 217 return closure;
231 } 218 }
232 219
233
234 // Check which pattern this native method follows: 220 // Check which pattern this native method follows:
235 // 1) foo() native; hasBody = false, isRedirecting = false 221 // 1) foo() native; hasBody = false, isRedirecting = false
236 // 2) foo() native "bar"; hasBody = false, isRedirecting = true 222 // 2) foo() native "bar"; hasBody = false, isRedirecting = true
237 // 3) foo() native "return 42"; hasBody = true, isRedirecting = false 223 // 3) foo() native "return 42"; hasBody = true, isRedirecting = false
224 RegExp nativeRedirectionRegExp = const RegExp(@'^[a-zA-Z][a-zA-Z_$0-9]*$');
238 bool hasBody = false; 225 bool hasBody = false;
239 bool isRedirecting = false; 226 bool isRedirecting = false;
240 String nativeMethodName = element.name.slowToString(); 227 String nativeMethodName = element.name.slowToString();
241 if (!node.arguments.isEmpty()) { 228 if (nativeBody !== null) {
242 if (!node.arguments.tail.isEmpty()) { 229 LiteralString jsCode = nativeBody.asLiteralString();
243 builder.compiler.cancel('More than one argument to native');
244 }
245 LiteralString jsCode = node.arguments.head;
246 String str = jsCode.dartString.slowToString(); 230 String str = jsCode.dartString.slowToString();
247 if (nativeRedirectionRegExp.hasMatch(str)) { 231 if (nativeRedirectionRegExp.hasMatch(str)) {
248 nativeMethodName = str; 232 nativeMethodName = str;
249 isRedirecting = true; 233 isRedirecting = true;
250 nativeEmitter.addRedirectingMethod(element, nativeMethodName); 234 nativeEmitter.addRedirectingMethod(element, nativeMethodName);
251 } else { 235 } else {
252 hasBody = true; 236 hasBody = true;
253 } 237 }
254 } 238 }
255 239
(...skipping 27 matching lines...) Expand all
283 } else if (element.kind == ElementKind.SETTER) { 267 } else if (element.kind == ElementKind.SETTER) {
284 nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters'; 268 nativeMethodCall = '$receiver$nativeMethodName = $foreignParameters';
285 } else { 269 } else {
286 builder.compiler.internalError('unexpected kind: "${element.kind}"', 270 builder.compiler.internalError('unexpected kind: "${element.kind}"',
287 element: element); 271 element: element);
288 } 272 }
289 273
290 DartString jsCode = new DartString.literal(nativeMethodCall); 274 DartString jsCode = new DartString.literal(nativeMethodCall);
291 builder.push( 275 builder.push(
292 new HForeign(jsCode, const LiteralDartString('Object'), inputs)); 276 new HForeign(jsCode, const LiteralDartString('Object'), inputs));
277 return true;
293 } else { 278 } else {
294 // This is JS code written in a Dart file with the construct 279 // This is JS code written in a Dart file with the construct
295 // native """ ... """;. It does not work well with mangling, 280 // native """ ... """;. It does not work well with mangling,
296 // but there should currently be no clash between leg mangling 281 // but there should currently be no clash between leg mangling
297 // and the library where this construct is being used. This 282 // and the library where this construct is being used. This
298 // mangling problem will go away once we switch these libraries 283 // mangling problem will go away once we switch these libraries
299 // to use Leg's 'JS' function. 284 // to use Leg's 'JS' function.
300 parameters.forEachParameter((Element parameter) { 285 parameters.forEachParameter((Element parameter) {
301 Type type = parameter.computeType(compiler); 286 Type type = parameter.computeType(compiler);
302 if (type is FunctionType) { 287 if (type is FunctionType) {
303 HInstruction jsClosure = convertDartClosure(parameter, type); 288 HInstruction jsClosure = convertDartClosure(parameter, type);
304 // Because the JS code references the argument name directly, 289 // Because the JS code references the argument name directly,
305 // we must keep the name and assign the JS closure to it. 290 // we must keep the name and assign the JS closure to it.
306 builder.add(new HForeign( 291 builder.add(new HForeign(
307 new DartString.literal('${parameter.name.slowToString()} = #'), 292 new DartString.literal('${parameter.name.slowToString()} = #'),
308 const LiteralDartString('void'), 293 const LiteralDartString('void'),
309 <HInstruction>[jsClosure])); 294 <HInstruction>[jsClosure]));
310 } 295 }
311 }); 296 });
312 LiteralString jsCode = node.arguments.head; 297 LiteralString jsCode = nativeBody.asLiteralString();
313 builder.push(new HForeign(jsCode.dartString, 298 builder.push(new HForeign(jsCode.dartString,
314 const LiteralDartString('Object'), 299 const LiteralDartString('Object'),
315 <HInstruction>[])); 300 <HInstruction>[]));
301 return false;
316 } 302 }
317 } 303 }
318 304
319 void generateMethodWithPrototypeCheckForElement(Compiler compiler, 305 void generateMethodWithPrototypeCheckForElement(Compiler compiler,
320 StringBuffer buffer, 306 StringBuffer buffer,
321 FunctionElement element, 307 FunctionElement element,
322 String code, 308 String code,
323 String parameters) { 309 String parameters) {
324 String methodName; 310 String methodName;
325 Namer namer = compiler.namer; 311 Namer namer = compiler.namer;
(...skipping 27 matching lines...) Expand all
353 String parameters) { 339 String parameters) {
354 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty"); 340 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty");
355 buffer.add("('$methodName')) {\n"); 341 buffer.add("('$methodName')) {\n");
356 buffer.add(" $code"); 342 buffer.add(" $code");
357 buffer.add(" } else {\n"); 343 buffer.add(" } else {\n");
358 buffer.add(" return Object.prototype.$methodName.call(this"); 344 buffer.add(" return Object.prototype.$methodName.call(this");
359 buffer.add(parameters == '' ? '' : ', $parameters'); 345 buffer.add(parameters == '' ? '' : ', $parameters');
360 buffer.add(");\n"); 346 buffer.add(");\n");
361 buffer.add(" }\n"); 347 buffer.add(" }\n");
362 } 348 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/scanner/parser.dart » ('j') | lib/compiler/implementation/ssa/builder.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698