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

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

Issue 11299220: Add @JSName annotation for native fields and methods. (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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 // foo([x, y, z]); 232 // foo([x, y, z]);
241 // The call: 233 // The call:
242 // foo(y: 1) 234 // foo(y: 1)
243 // must be turned into a JS call to: 235 // must be turned into a JS call to:
244 // foo(null, y). 236 // foo(null, y).
245 237
246 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( 238 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange(
247 0, indexOfLastOptionalArgumentInParameters + 1); 239 0, indexOfLastOptionalArgumentInParameters + 1);
248 240
249 ClassElement classElement = member.enclosingElement; 241 ClassElement classElement = member.enclosingElement;
250 String nativeName = classElement.nativeName.slowToString(); 242 String nativeTagInfo = classElement.nativeTagInfo.slowToString();
251 String nativeArguments = Strings.join(nativeArgumentsBuffer, ","); 243 String nativeArguments = Strings.join(nativeArgumentsBuffer, ",");
252 244
253 CodeBuffer code = new CodeBuffer(); 245 CodeBuffer code = new CodeBuffer();
254 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer); 246 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer);
255 247
256 if (!nativeMethods.contains(member)) { 248 if (!nativeMethods.contains(member)) {
257 // When calling a method that has a native body, we call it 249 // When calling a method that has a native body, we call it
258 // with our calling conventions. 250 // with our calling conventions.
259 String arguments = Strings.join(argumentsBuffer, ","); 251 String arguments = Strings.join(argumentsBuffer, ",");
260 code.add(' return this.${backend.namer.getName(member)}($arguments)'); 252 code.add(' return this.${backend.namer.getName(member)}($arguments)');
261 } else { 253 } else {
262 // When calling a JS method, we call it with the native name. 254 // When calling a JS method, we call it with the native name.
263 String name = redirectingMethods[member]; 255 String name = member.nativeName();
264 if (name == null) name = member.name.slowToString();
265 code.add(' return this.$name($nativeArguments);'); 256 code.add(' return this.$name($nativeArguments);');
266 } 257 }
267 258
268 if (isNativeLiteral(nativeName) || !overriddenMethods.contains(member)) { 259 if (isNativeLiteral(nativeTagInfo) || !overriddenMethods.contains(member)) {
269 // Call the method directly. 260 // Call the method directly.
270 buffer.add(code.toString()); 261 buffer.add(code.toString());
271 } else { 262 } else {
272 native.generateMethodWithPrototypeCheck( 263 native.generateMethodWithPrototypeCheck(
273 compiler, buffer, invocationName, code.toString(), stubParameters); 264 compiler, buffer, invocationName, code.toString(), stubParameters);
274 } 265 }
275 } 266 }
276 267
277 void emitDynamicDispatchMetadata() { 268 void emitDynamicDispatchMetadata() {
278 if (classesWithDynamicDispatch.isEmpty) return; 269 if (classesWithDynamicDispatch.isEmpty) return;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 // Expression to compute tags string for a class. The expression will 311 // Expression to compute tags string for a class. The expression will
321 // initially be a string or expression building a string, but may be 312 // initially be a string or expression building a string, but may be
322 // replaced with a variable reference to the common substring. 313 // replaced with a variable reference to the common substring.
323 Map<ClassElement, js.Expression> tagDefns = 314 Map<ClassElement, js.Expression> tagDefns =
324 new Map<ClassElement, js.Expression>(); 315 new Map<ClassElement, js.Expression>();
325 316
326 js.Expression makeExpression(ClassElement classElement) { 317 js.Expression makeExpression(ClassElement classElement) {
327 // Expression fragments for this set of cls keys. 318 // Expression fragments for this set of cls keys.
328 List<js.Expression> expressions = <js.Expression>[]; 319 List<js.Expression> expressions = <js.Expression>[];
329 // TODO: Remove if cls is abstract. 320 // TODO: Remove if cls is abstract.
330 List<String> subtags = [toNativeName(classElement)]; 321 List<String> subtags = [toNativeTag(classElement)];
331 void walk(ClassElement cls) { 322 void walk(ClassElement cls) {
332 for (final ClassElement subclass in getDirectSubclasses(cls)) { 323 for (final ClassElement subclass in getDirectSubclasses(cls)) {
333 ClassElement tag = subclass; 324 ClassElement tag = subclass;
334 js.Expression existing = tagDefns[tag]; 325 js.Expression existing = tagDefns[tag];
335 if (existing == null) { 326 if (existing == null) {
336 // [subclass] is still within the subtree between dispatch classes. 327 // [subclass] is still within the subtree between dispatch classes.
337 subtags.add(toNativeName(tag)); 328 subtags.add(toNativeTag(tag));
338 walk(subclass); 329 walk(subclass);
339 } else { 330 } else {
340 // [subclass] is one of the preorderDispatchClasses, so CSE this 331 // [subclass] is one of the preorderDispatchClasses, so CSE this
341 // reference with the previous reference. 332 // reference with the previous reference.
342 if (existing is js.VariableUse && 333 if (existing is js.VariableUse &&
343 varDefns.containsKey(existing.name)) { 334 varDefns.containsKey(existing.name)) {
344 // We end up here if the subclasses have a DAG structure. We 335 // We end up here if the subclasses have a DAG structure. We
345 // don't have DAGs yet, but if the dispatch is used for mixins 336 // don't have DAGs yet, but if the dispatch is used for mixins
346 // that will be a possibility. 337 // that will be a possibility.
347 // Re-use the previously created temporary variable. 338 // Re-use the previously created temporary variable.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 } 388 }
398 389
399 // [table] is a list of lists, each inner list of the form: 390 // [table] is a list of lists, each inner list of the form:
400 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] 391 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag]
401 // E.g. 392 // E.g.
402 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] 393 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...]
403 js.Expression table = 394 js.Expression table =
404 new js.ArrayInitializer.from( 395 new js.ArrayInitializer.from(
405 preorderDispatchClasses.map((cls) => 396 preorderDispatchClasses.map((cls) =>
406 new js.ArrayInitializer.from([ 397 new js.ArrayInitializer.from([
407 new js.LiteralString("'${toNativeName(cls)}'"), 398 new js.LiteralString("'${toNativeTag(cls)}'"),
408 tagDefns[cls]]))); 399 tagDefns[cls]])));
409 400
410 // $.dynamicSetMetadata(table); 401 // $.dynamicSetMetadata(table);
411 statements.add( 402 statements.add(
412 new js.ExpressionStatement( 403 new js.ExpressionStatement(
413 new js.Call( 404 new js.Call(
414 new js.VariableUse(dynamicSetMetadataName), 405 new js.VariableUse(dynamicSetMetadataName),
415 [table]))); 406 [table])));
416 407
417 // (function(){statements})(); 408 // (function(){statements})();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 if (!first) targetBuffer.add(",\n"); 497 if (!first) targetBuffer.add(",\n");
507 targetBuffer.add(" $name: $function"); 498 targetBuffer.add(" $name: $function");
508 first = false; 499 first = false;
509 }); 500 });
510 targetBuffer.add("\n});\n\n"); 501 targetBuffer.add("\n});\n\n");
511 } 502 }
512 targetBuffer.add(nativeBuffer); 503 targetBuffer.add(nativeBuffer);
513 targetBuffer.add('\n'); 504 targetBuffer.add('\n');
514 } 505 }
515 } 506 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698