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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart

Issue 11419250: Add @JSName annotation for native fields and methods - second try. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years 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 part of js_backend; 5 part of js_backend;
6 6
7 class NativeEmitter { 7 class NativeEmitter {
8 8
9 CodeEmitterTask emitter; 9 CodeEmitterTask emitter;
10 CodeBuffer nativeBuffer; 10 CodeBuffer nativeBuffer;
(...skipping 13 matching lines...) Expand all
24 24
25 // Caches the native methods that are overridden by a native class. 25 // Caches the native methods that are overridden by a native class.
26 // Note that the method that overrides does not have to be native: 26 // Note that the method that overrides does not have to be native:
27 // it's the overridden method that must make sure it will dispatch 27 // it's the overridden method that must make sure it will dispatch
28 // to its subclass if it sees an instance whose class is a subclass. 28 // to its subclass if it sees an instance whose class is a subclass.
29 Set<FunctionElement> overriddenMethods; 29 Set<FunctionElement> overriddenMethods;
30 30
31 // Caches the methods that have a native body. 31 // Caches the methods that have a native body.
32 Set<FunctionElement> nativeMethods; 32 Set<FunctionElement> nativeMethods;
33 33
34 // Caches the methods that redirect to a JS method.
35 Map<FunctionElement, String> redirectingMethods;
36
37 // Do we need the native emitter to take care of handling 34 // Do we need the native emitter to take care of handling
38 // noSuchMethod for us? This flag is set to true in the emitter if 35 // noSuchMethod for us? This flag is set to true in the emitter if
39 // it finds any native class that needs noSuchMethod handling. 36 // it finds any native class that needs noSuchMethod handling.
40 bool handleNoSuchMethod = false; 37 bool handleNoSuchMethod = false;
41 38
42 NativeEmitter(this.emitter) 39 NativeEmitter(this.emitter)
43 : classesWithDynamicDispatch = new Set<ClassElement>(), 40 : classesWithDynamicDispatch = new Set<ClassElement>(),
44 nativeClasses = new Set<ClassElement>(), 41 nativeClasses = new Set<ClassElement>(),
45 subtypes = new Map<ClassElement, List<ClassElement>>(), 42 subtypes = new Map<ClassElement, List<ClassElement>>(),
46 directSubtypes = new Map<ClassElement, List<ClassElement>>(), 43 directSubtypes = new Map<ClassElement, List<ClassElement>>(),
47 overriddenMethods = new Set<FunctionElement>(), 44 overriddenMethods = new Set<FunctionElement>(),
48 nativeMethods = new Set<FunctionElement>(), 45 nativeMethods = new Set<FunctionElement>(),
49 redirectingMethods = new Map<FunctionElement, String>(),
50 nativeBuffer = new CodeBuffer(); 46 nativeBuffer = new CodeBuffer();
51 47
52 Compiler get compiler => emitter.compiler; 48 Compiler get compiler => emitter.compiler;
53 JavaScriptBackend get backend => compiler.backend; 49 JavaScriptBackend get backend => compiler.backend;
54 50
55 void addRedirectingMethod(FunctionElement element, String name) {
56 redirectingMethods[element] = name;
57 }
58
59 String get dynamicName { 51 String get dynamicName {
60 Element element = compiler.findHelper( 52 Element element = compiler.findHelper(
61 const SourceString('dynamicFunction')); 53 const SourceString('dynamicFunction'));
62 return backend.namer.isolateAccess(element); 54 return backend.namer.isolateAccess(element);
63 } 55 }
64 56
65 String get dynamicSetMetadataName { 57 String get dynamicSetMetadataName {
66 Element element = compiler.findHelper( 58 Element element = compiler.findHelper(
67 const SourceString('dynamicSetMetadata')); 59 const SourceString('dynamicSetMetadata'));
68 return backend.namer.isolateAccess(element); 60 return backend.namer.isolateAccess(element);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 if (method !== '') { 100 if (method !== '') {
109 if (hasOwnProperty.call(desc, method)) { 101 if (hasOwnProperty.call(desc, method)) {
110 $dynamicName(method)[cls] = desc[method]; 102 $dynamicName(method)[cls] = desc[method];
111 } 103 }
112 } 104 }
113 } 105 }
114 }"""; 106 }""";
115 } 107 }
116 108
117 void generateNativeLiteral(ClassElement classElement) { 109 void generateNativeLiteral(ClassElement classElement) {
118 String quotedNative = classElement.nativeName.slowToString(); 110 String quotedNative = classElement.nativeTagInfo.slowToString();
119 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); 111 String nativeCode = quotedNative.substring(2, quotedNative.length - 1);
120 String className = backend.namer.getName(classElement); 112 String className = backend.namer.getName(classElement);
121 nativeBuffer.add(className); 113 nativeBuffer.add(className);
122 nativeBuffer.add(' = '); 114 nativeBuffer.add(' = ');
123 nativeBuffer.add(nativeCode); 115 nativeBuffer.add(nativeCode);
124 nativeBuffer.add(';\n'); 116 nativeBuffer.add(';\n');
125 117
126 void defineInstanceMember(String name, CodeBuffer value) { 118 void defineInstanceMember(String name, CodeBuffer value) {
127 nativeBuffer.add("$className.$name = $value;\n"); 119 nativeBuffer.add("$className.$name = $value;\n");
128 } 120 }
129 121
130 classElement.implementation.forEachMember((_, Element member) { 122 classElement.implementation.forEachMember((_, Element member) {
131 if (member.isInstanceMember()) { 123 if (member.isInstanceMember()) {
132 emitter.addInstanceMember(member, defineInstanceMember); 124 emitter.addInstanceMember(member, defineInstanceMember);
133 } 125 }
134 }); 126 });
135 } 127 }
136 128
137 bool isNativeLiteral(String quotedName) { 129 bool isNativeLiteral(String quotedName) {
138 return identical(quotedName[1], '='); 130 return identical(quotedName[1], '=');
139 } 131 }
140 132
141 bool isNativeGlobal(String quotedName) { 133 bool isNativeGlobal(String quotedName) {
142 return identical(quotedName[1], '@'); 134 return identical(quotedName[1], '@');
143 } 135 }
144 136
145 String toNativeName(ClassElement cls) { 137 String toNativeTag(ClassElement cls) {
146 String quotedName = cls.nativeName.slowToString(); 138 String quotedName = cls.nativeTagInfo.slowToString();
147 if (isNativeGlobal(quotedName)) { 139 if (isNativeGlobal(quotedName)) {
148 // Global object, just be like the other types for now. 140 // Global object, just be like the other types for now.
149 return quotedName.substring(3, quotedName.length - 1); 141 return quotedName.substring(3, quotedName.length - 1);
150 } else { 142 } else {
151 return quotedName.substring(2, quotedName.length - 1); 143 return quotedName.substring(2, quotedName.length - 1);
152 } 144 }
153 } 145 }
154 146
155 void generateNativeClass(ClassElement classElement) { 147 void generateNativeClass(ClassElement classElement) {
156 nativeClasses.add(classElement); 148 nativeClasses.add(classElement);
157 149
158 assert(classElement.backendMembers.isEmpty); 150 assert(classElement.backendMembers.isEmpty);
159 String quotedName = classElement.nativeName.slowToString(); 151 String quotedName = classElement.nativeTagInfo.slowToString();
160 if (isNativeLiteral(quotedName)) { 152 if (isNativeLiteral(quotedName)) {
161 generateNativeLiteral(classElement); 153 generateNativeLiteral(classElement);
162 // The native literal kind needs to be dealt with specially when 154 // The native literal kind needs to be dealt with specially when
163 // generating code for it. 155 // generating code for it.
164 return; 156 return;
165 } 157 }
166 158
167 CodeBuffer fieldBuffer = new CodeBuffer(); 159 CodeBuffer fieldBuffer = new CodeBuffer();
168 CodeBuffer getterSetterBuffer = new CodeBuffer(); 160 CodeBuffer getterSetterBuffer = new CodeBuffer();
169 CodeBuffer methodBuffer = new CodeBuffer(); 161 CodeBuffer methodBuffer = new CodeBuffer();
170 162
171 emitter.emitClassFields(classElement, fieldBuffer, false); 163 emitter.emitClassFields(classElement, fieldBuffer, false);
172 emitter.emitClassGettersSetters(classElement, getterSetterBuffer, false); 164 emitter.emitClassGettersSetters(classElement, getterSetterBuffer, false);
173 emitter.emitInstanceMembers(classElement, methodBuffer, false); 165 emitter.emitInstanceMembers(classElement, methodBuffer, false);
174 166
175 if (methodBuffer.isEmpty 167 if (methodBuffer.isEmpty
176 && fieldBuffer.isEmpty 168 && fieldBuffer.isEmpty
177 && getterSetterBuffer.isEmpty) { 169 && getterSetterBuffer.isEmpty) {
178 return; 170 return;
179 } 171 }
180 172
181 String nativeName = toNativeName(classElement); 173 String nativeTag = toNativeTag(classElement);
182 nativeBuffer.add("$defineNativeClassName('$nativeName', "); 174 nativeBuffer.add("$defineNativeClassName('$nativeTag', ");
183 nativeBuffer.add('{'); 175 nativeBuffer.add('{');
184 bool firstInMap = true; 176 bool firstInMap = true;
185 if (!fieldBuffer.isEmpty) { 177 if (!fieldBuffer.isEmpty) {
186 firstInMap = false; 178 firstInMap = false;
187 nativeBuffer.add(fieldBuffer); 179 nativeBuffer.add(fieldBuffer);
188 } 180 }
189 if (!getterSetterBuffer.isEmpty) { 181 if (!getterSetterBuffer.isEmpty) {
190 if (!firstInMap) nativeBuffer.add(","); 182 if (!firstInMap) nativeBuffer.add(",");
191 firstInMap = false; 183 firstInMap = false;
192 nativeBuffer.add("\n "); 184 nativeBuffer.add("\n ");
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 // The target JS function may check arguments.length so we need to 242 // The target JS function may check arguments.length so we need to
251 // make sure not to pass any unspecified optional arguments to it. 243 // make sure not to pass any unspecified optional arguments to it.
252 // For example, for the following Dart method: 244 // For example, for the following Dart method:
253 // foo([x, y, z]); 245 // foo([x, y, z]);
254 // The call: 246 // The call:
255 // foo(y: 1) 247 // foo(y: 1)
256 // must be turned into a JS call to: 248 // must be turned into a JS call to:
257 // foo(null, y). 249 // foo(null, y).
258 250
259 ClassElement classElement = member.enclosingElement; 251 ClassElement classElement = member.enclosingElement;
260 String nativeTagInfo = classElement.nativeName.slowToString(); 252 //String nativeTagInfo = classElement.nativeName.slowToString();
253 String nativeTagInfo = classElement.nativeTagInfo.slowToString();
261 254
262 List<js.Statement> statements = <js.Statement>[]; 255 List<js.Statement> statements = <js.Statement>[];
263 potentiallyConvertDartClosuresToJs(statements, member, stubParameters); 256 potentiallyConvertDartClosuresToJs(statements, member, stubParameters);
264 257
265 String target; 258 String target;
266 List<js.Expression> arguments; 259 List<js.Expression> arguments;
267 260
268 if (!nativeMethods.contains(member)) { 261 if (!nativeMethods.contains(member)) {
269 // When calling a method that has a native body, we call it with our 262 // When calling a method that has a native body, we call it with our
270 // calling conventions. 263 // calling conventions.
271 target = backend.namer.getName(member); 264 target = backend.namer.getName(member);
272 arguments = argumentsBuffer; 265 arguments = argumentsBuffer;
273 } else { 266 } else {
274 // When calling a JS method, we call it with the native name, and only the 267 // When calling a JS method, we call it with the native name, and only the
275 // arguments up until the last one provided. 268 // arguments up until the last one provided.
276 target = redirectingMethods[member]; 269 target = member.nativeName();
277 if (target == null) target = member.name.slowToString();
278 arguments = argumentsBuffer.getRange( 270 arguments = argumentsBuffer.getRange(
279 0, indexOfLastOptionalArgumentInParameters + 1); 271 0, indexOfLastOptionalArgumentInParameters + 1);
280 } 272 }
281 statements.add( 273 statements.add(
282 new js.Return( 274 new js.Return(
283 new js.VariableUse('this').dot(target).callWith(arguments))); 275 new js.VariableUse('this').dot(target).callWith(arguments)));
284 276
285 if (isNativeLiteral(nativeTagInfo) || !overriddenMethods.contains(member)) { 277 if (isNativeLiteral(nativeTagInfo) || !overriddenMethods.contains(member)) {
286 // Call the method directly. 278 // Call the method directly.
287 return statements; 279 return statements;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 // Expression to compute tags string for a class. The expression will 380 // Expression to compute tags string for a class. The expression will
389 // initially be a string or expression building a string, but may be 381 // initially be a string or expression building a string, but may be
390 // replaced with a variable reference to the common substring. 382 // replaced with a variable reference to the common substring.
391 Map<ClassElement, js.Expression> tagDefns = 383 Map<ClassElement, js.Expression> tagDefns =
392 new Map<ClassElement, js.Expression>(); 384 new Map<ClassElement, js.Expression>();
393 385
394 js.Expression makeExpression(ClassElement classElement) { 386 js.Expression makeExpression(ClassElement classElement) {
395 // Expression fragments for this set of cls keys. 387 // Expression fragments for this set of cls keys.
396 List<js.Expression> expressions = <js.Expression>[]; 388 List<js.Expression> expressions = <js.Expression>[];
397 // TODO: Remove if cls is abstract. 389 // TODO: Remove if cls is abstract.
398 List<String> subtags = [toNativeName(classElement)]; 390 List<String> subtags = [toNativeTag(classElement)];
399 void walk(ClassElement cls) { 391 void walk(ClassElement cls) {
400 for (final ClassElement subclass in getDirectSubclasses(cls)) { 392 for (final ClassElement subclass in getDirectSubclasses(cls)) {
401 ClassElement tag = subclass; 393 ClassElement tag = subclass;
402 js.Expression existing = tagDefns[tag]; 394 js.Expression existing = tagDefns[tag];
403 if (existing == null) { 395 if (existing == null) {
404 // [subclass] is still within the subtree between dispatch classes. 396 // [subclass] is still within the subtree between dispatch classes.
405 subtags.add(toNativeName(tag)); 397 subtags.add(toNativeTag(tag));
406 walk(subclass); 398 walk(subclass);
407 } else { 399 } else {
408 // [subclass] is one of the preorderDispatchClasses, so CSE this 400 // [subclass] is one of the preorderDispatchClasses, so CSE this
409 // reference with the previous reference. 401 // reference with the previous reference.
410 if (existing is js.VariableUse && 402 if (existing is js.VariableUse &&
411 varDefns.containsKey(existing.name)) { 403 varDefns.containsKey(existing.name)) {
412 // We end up here if the subclasses have a DAG structure. We 404 // We end up here if the subclasses have a DAG structure. We
413 // don't have DAGs yet, but if the dispatch is used for mixins 405 // don't have DAGs yet, but if the dispatch is used for mixins
414 // that will be a possibility. 406 // that will be a possibility.
415 // Re-use the previously created temporary variable. 407 // Re-use the previously created temporary variable.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 } 457 }
466 458
467 // [table] is a list of lists, each inner list of the form: 459 // [table] is a list of lists, each inner list of the form:
468 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] 460 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag]
469 // E.g. 461 // E.g.
470 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] 462 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...]
471 js.Expression table = 463 js.Expression table =
472 new js.ArrayInitializer.from( 464 new js.ArrayInitializer.from(
473 preorderDispatchClasses.map((cls) => 465 preorderDispatchClasses.map((cls) =>
474 new js.ArrayInitializer.from([ 466 new js.ArrayInitializer.from([
475 new js.LiteralString("'${toNativeName(cls)}'"), 467 new js.LiteralString("'${toNativeTag(cls)}'"),
476 tagDefns[cls]]))); 468 tagDefns[cls]])));
477 469
478 // $.dynamicSetMetadata(table); 470 // $.dynamicSetMetadata(table);
479 statements.add( 471 statements.add(
480 new js.ExpressionStatement( 472 new js.ExpressionStatement(
481 new js.Call( 473 new js.Call(
482 new js.VariableUse(dynamicSetMetadataName), 474 new js.VariableUse(dynamicSetMetadataName),
483 [table]))); 475 [table])));
484 476
485 // (function(){statements})(); 477 // (function(){statements})();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 if (!first) targetBuffer.add(",\n"); 566 if (!first) targetBuffer.add(",\n");
575 targetBuffer.add(" $name: $function"); 567 targetBuffer.add(" $name: $function");
576 first = false; 568 first = false;
577 }); 569 });
578 targetBuffer.add("\n});\n\n"); 570 targetBuffer.add("\n});\n\n");
579 } 571 }
580 targetBuffer.add(nativeBuffer); 572 targetBuffer.add(nativeBuffer);
581 targetBuffer.add('\n'); 573 targetBuffer.add('\n');
582 } 574 }
583 } 575 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698