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

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

Issue 11416257: Revert "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
34 // Do we need the native emitter to take care of handling 37 // Do we need the native emitter to take care of handling
35 // noSuchMethod for us? This flag is set to true in the emitter if 38 // noSuchMethod for us? This flag is set to true in the emitter if
36 // it finds any native class that needs noSuchMethod handling. 39 // it finds any native class that needs noSuchMethod handling.
37 bool handleNoSuchMethod = false; 40 bool handleNoSuchMethod = false;
38 41
39 NativeEmitter(this.emitter) 42 NativeEmitter(this.emitter)
40 : classesWithDynamicDispatch = new Set<ClassElement>(), 43 : classesWithDynamicDispatch = new Set<ClassElement>(),
41 nativeClasses = new Set<ClassElement>(), 44 nativeClasses = new Set<ClassElement>(),
42 subtypes = new Map<ClassElement, List<ClassElement>>(), 45 subtypes = new Map<ClassElement, List<ClassElement>>(),
43 directSubtypes = new Map<ClassElement, List<ClassElement>>(), 46 directSubtypes = new Map<ClassElement, List<ClassElement>>(),
44 overriddenMethods = new Set<FunctionElement>(), 47 overriddenMethods = new Set<FunctionElement>(),
45 nativeMethods = new Set<FunctionElement>(), 48 nativeMethods = new Set<FunctionElement>(),
49 redirectingMethods = new Map<FunctionElement, String>(),
46 nativeBuffer = new CodeBuffer(); 50 nativeBuffer = new CodeBuffer();
47 51
48 Compiler get compiler => emitter.compiler; 52 Compiler get compiler => emitter.compiler;
49 JavaScriptBackend get backend => compiler.backend; 53 JavaScriptBackend get backend => compiler.backend;
50 54
55 void addRedirectingMethod(FunctionElement element, String name) {
56 redirectingMethods[element] = name;
57 }
58
51 String get dynamicName { 59 String get dynamicName {
52 Element element = compiler.findHelper( 60 Element element = compiler.findHelper(
53 const SourceString('dynamicFunction')); 61 const SourceString('dynamicFunction'));
54 return backend.namer.isolateAccess(element); 62 return backend.namer.isolateAccess(element);
55 } 63 }
56 64
57 String get dynamicSetMetadataName { 65 String get dynamicSetMetadataName {
58 Element element = compiler.findHelper( 66 Element element = compiler.findHelper(
59 const SourceString('dynamicSetMetadata')); 67 const SourceString('dynamicSetMetadata'));
60 return backend.namer.isolateAccess(element); 68 return backend.namer.isolateAccess(element);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 if (method !== '') { 108 if (method !== '') {
101 if (hasOwnProperty.call(desc, method)) { 109 if (hasOwnProperty.call(desc, method)) {
102 $dynamicName(method)[cls] = desc[method]; 110 $dynamicName(method)[cls] = desc[method];
103 } 111 }
104 } 112 }
105 } 113 }
106 }"""; 114 }""";
107 } 115 }
108 116
109 void generateNativeLiteral(ClassElement classElement) { 117 void generateNativeLiteral(ClassElement classElement) {
110 String quotedNative = classElement.nativeTagInfo.slowToString(); 118 String quotedNative = classElement.nativeName.slowToString();
111 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); 119 String nativeCode = quotedNative.substring(2, quotedNative.length - 1);
112 String className = backend.namer.getName(classElement); 120 String className = backend.namer.getName(classElement);
113 nativeBuffer.add(className); 121 nativeBuffer.add(className);
114 nativeBuffer.add(' = '); 122 nativeBuffer.add(' = ');
115 nativeBuffer.add(nativeCode); 123 nativeBuffer.add(nativeCode);
116 nativeBuffer.add(';\n'); 124 nativeBuffer.add(';\n');
117 125
118 void defineInstanceMember(String name, CodeBuffer value) { 126 void defineInstanceMember(String name, CodeBuffer value) {
119 nativeBuffer.add("$className.$name = $value;\n"); 127 nativeBuffer.add("$className.$name = $value;\n");
120 } 128 }
121 129
122 classElement.implementation.forEachMember((_, Element member) { 130 classElement.implementation.forEachMember((_, Element member) {
123 if (member.isInstanceMember()) { 131 if (member.isInstanceMember()) {
124 emitter.addInstanceMember(member, defineInstanceMember); 132 emitter.addInstanceMember(member, defineInstanceMember);
125 } 133 }
126 }); 134 });
127 } 135 }
128 136
129 bool isNativeLiteral(String quotedName) { 137 bool isNativeLiteral(String quotedName) {
130 return identical(quotedName[1], '='); 138 return identical(quotedName[1], '=');
131 } 139 }
132 140
133 bool isNativeGlobal(String quotedName) { 141 bool isNativeGlobal(String quotedName) {
134 return identical(quotedName[1], '@'); 142 return identical(quotedName[1], '@');
135 } 143 }
136 144
137 String toNativeTag(ClassElement cls) { 145 String toNativeName(ClassElement cls) {
138 String quotedName = cls.nativeTagInfo.slowToString(); 146 String quotedName = cls.nativeName.slowToString();
139 if (isNativeGlobal(quotedName)) { 147 if (isNativeGlobal(quotedName)) {
140 // Global object, just be like the other types for now. 148 // Global object, just be like the other types for now.
141 return quotedName.substring(3, quotedName.length - 1); 149 return quotedName.substring(3, quotedName.length - 1);
142 } else { 150 } else {
143 return quotedName.substring(2, quotedName.length - 1); 151 return quotedName.substring(2, quotedName.length - 1);
144 } 152 }
145 } 153 }
146 154
147 void generateNativeClass(ClassElement classElement) { 155 void generateNativeClass(ClassElement classElement) {
148 nativeClasses.add(classElement); 156 nativeClasses.add(classElement);
149 157
150 assert(classElement.backendMembers.isEmpty); 158 assert(classElement.backendMembers.isEmpty);
151 String quotedName = classElement.nativeTagInfo.slowToString(); 159 String quotedName = classElement.nativeName.slowToString();
152 if (isNativeLiteral(quotedName)) { 160 if (isNativeLiteral(quotedName)) {
153 generateNativeLiteral(classElement); 161 generateNativeLiteral(classElement);
154 // The native literal kind needs to be dealt with specially when 162 // The native literal kind needs to be dealt with specially when
155 // generating code for it. 163 // generating code for it.
156 return; 164 return;
157 } 165 }
158 166
159 CodeBuffer fieldBuffer = new CodeBuffer(); 167 CodeBuffer fieldBuffer = new CodeBuffer();
160 CodeBuffer getterSetterBuffer = new CodeBuffer(); 168 CodeBuffer getterSetterBuffer = new CodeBuffer();
161 CodeBuffer methodBuffer = new CodeBuffer(); 169 CodeBuffer methodBuffer = new CodeBuffer();
162 170
163 emitter.emitClassFields(classElement, fieldBuffer, false); 171 emitter.emitClassFields(classElement, fieldBuffer, false);
164 emitter.emitClassGettersSetters(classElement, getterSetterBuffer, false); 172 emitter.emitClassGettersSetters(classElement, getterSetterBuffer, false);
165 emitter.emitInstanceMembers(classElement, methodBuffer, false); 173 emitter.emitInstanceMembers(classElement, methodBuffer, false);
166 174
167 if (methodBuffer.isEmpty 175 if (methodBuffer.isEmpty
168 && fieldBuffer.isEmpty 176 && fieldBuffer.isEmpty
169 && getterSetterBuffer.isEmpty) { 177 && getterSetterBuffer.isEmpty) {
170 return; 178 return;
171 } 179 }
172 180
173 String nativeTag = toNativeTag(classElement); 181 String nativeName = toNativeName(classElement);
174 nativeBuffer.add("$defineNativeClassName('$nativeTag', "); 182 nativeBuffer.add("$defineNativeClassName('$nativeName', ");
175 nativeBuffer.add('{'); 183 nativeBuffer.add('{');
176 bool firstInMap = true; 184 bool firstInMap = true;
177 if (!fieldBuffer.isEmpty) { 185 if (!fieldBuffer.isEmpty) {
178 firstInMap = false; 186 firstInMap = false;
179 nativeBuffer.add(fieldBuffer); 187 nativeBuffer.add(fieldBuffer);
180 } 188 }
181 if (!getterSetterBuffer.isEmpty) { 189 if (!getterSetterBuffer.isEmpty) {
182 if (!firstInMap) nativeBuffer.add(","); 190 if (!firstInMap) nativeBuffer.add(",");
183 firstInMap = false; 191 firstInMap = false;
184 nativeBuffer.add("\n "); 192 nativeBuffer.add("\n ");
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 // foo([x, y, z]); 240 // foo([x, y, z]);
233 // The call: 241 // The call:
234 // foo(y: 1) 242 // foo(y: 1)
235 // must be turned into a JS call to: 243 // must be turned into a JS call to:
236 // foo(null, y). 244 // foo(null, y).
237 245
238 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange( 246 List<String> nativeArgumentsBuffer = argumentsBuffer.getRange(
239 0, indexOfLastOptionalArgumentInParameters + 1); 247 0, indexOfLastOptionalArgumentInParameters + 1);
240 248
241 ClassElement classElement = member.enclosingElement; 249 ClassElement classElement = member.enclosingElement;
242 String nativeTagInfo = classElement.nativeTagInfo.slowToString(); 250 String nativeName = classElement.nativeName.slowToString();
243 String nativeArguments = Strings.join(nativeArgumentsBuffer, ","); 251 String nativeArguments = Strings.join(nativeArgumentsBuffer, ",");
244 252
245 CodeBuffer code = new CodeBuffer(); 253 CodeBuffer code = new CodeBuffer();
246 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer); 254 potentiallyConvertDartClosuresToJs(code, member, argumentsBuffer);
247 255
248 if (!nativeMethods.contains(member)) { 256 if (!nativeMethods.contains(member)) {
249 // When calling a method that has a native body, we call it 257 // When calling a method that has a native body, we call it
250 // with our calling conventions. 258 // with our calling conventions.
251 String arguments = Strings.join(argumentsBuffer, ","); 259 String arguments = Strings.join(argumentsBuffer, ",");
252 code.add(' return this.${backend.namer.getName(member)}($arguments)'); 260 code.add(' return this.${backend.namer.getName(member)}($arguments)');
253 } else { 261 } else {
254 // When calling a JS method, we call it with the native name. 262 // When calling a JS method, we call it with the native name.
255 String name = member.nativeName(); 263 String name = redirectingMethods[member];
264 if (name == null) name = member.name.slowToString();
256 code.add(' return this.$name($nativeArguments);'); 265 code.add(' return this.$name($nativeArguments);');
257 } 266 }
258 267
259 if (isNativeLiteral(nativeTagInfo) || !overriddenMethods.contains(member)) { 268 if (isNativeLiteral(nativeName) || !overriddenMethods.contains(member)) {
260 // Call the method directly. 269 // Call the method directly.
261 buffer.add(code.toString()); 270 buffer.add(code.toString());
262 } else { 271 } else {
263 native.generateMethodWithPrototypeCheck( 272 native.generateMethodWithPrototypeCheck(
264 compiler, buffer, invocationName, code.toString(), stubParameters); 273 compiler, buffer, invocationName, code.toString(), stubParameters);
265 } 274 }
266 } 275 }
267 276
268 void emitDynamicDispatchMetadata() { 277 void emitDynamicDispatchMetadata() {
269 if (classesWithDynamicDispatch.isEmpty) return; 278 if (classesWithDynamicDispatch.isEmpty) return;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 // Expression to compute tags string for a class. The expression will 320 // Expression to compute tags string for a class. The expression will
312 // initially be a string or expression building a string, but may be 321 // initially be a string or expression building a string, but may be
313 // replaced with a variable reference to the common substring. 322 // replaced with a variable reference to the common substring.
314 Map<ClassElement, js.Expression> tagDefns = 323 Map<ClassElement, js.Expression> tagDefns =
315 new Map<ClassElement, js.Expression>(); 324 new Map<ClassElement, js.Expression>();
316 325
317 js.Expression makeExpression(ClassElement classElement) { 326 js.Expression makeExpression(ClassElement classElement) {
318 // Expression fragments for this set of cls keys. 327 // Expression fragments for this set of cls keys.
319 List<js.Expression> expressions = <js.Expression>[]; 328 List<js.Expression> expressions = <js.Expression>[];
320 // TODO: Remove if cls is abstract. 329 // TODO: Remove if cls is abstract.
321 List<String> subtags = [toNativeTag(classElement)]; 330 List<String> subtags = [toNativeName(classElement)];
322 void walk(ClassElement cls) { 331 void walk(ClassElement cls) {
323 for (final ClassElement subclass in getDirectSubclasses(cls)) { 332 for (final ClassElement subclass in getDirectSubclasses(cls)) {
324 ClassElement tag = subclass; 333 ClassElement tag = subclass;
325 js.Expression existing = tagDefns[tag]; 334 js.Expression existing = tagDefns[tag];
326 if (existing == null) { 335 if (existing == null) {
327 // [subclass] is still within the subtree between dispatch classes. 336 // [subclass] is still within the subtree between dispatch classes.
328 subtags.add(toNativeTag(tag)); 337 subtags.add(toNativeName(tag));
329 walk(subclass); 338 walk(subclass);
330 } else { 339 } else {
331 // [subclass] is one of the preorderDispatchClasses, so CSE this 340 // [subclass] is one of the preorderDispatchClasses, so CSE this
332 // reference with the previous reference. 341 // reference with the previous reference.
333 if (existing is js.VariableUse && 342 if (existing is js.VariableUse &&
334 varDefns.containsKey(existing.name)) { 343 varDefns.containsKey(existing.name)) {
335 // We end up here if the subclasses have a DAG structure. We 344 // We end up here if the subclasses have a DAG structure. We
336 // don't have DAGs yet, but if the dispatch is used for mixins 345 // don't have DAGs yet, but if the dispatch is used for mixins
337 // that will be a possibility. 346 // that will be a possibility.
338 // Re-use the previously created temporary variable. 347 // Re-use the previously created temporary variable.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 } 397 }
389 398
390 // [table] is a list of lists, each inner list of the form: 399 // [table] is a list of lists, each inner list of the form:
391 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] 400 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag]
392 // E.g. 401 // E.g.
393 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] 402 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...]
394 js.Expression table = 403 js.Expression table =
395 new js.ArrayInitializer.from( 404 new js.ArrayInitializer.from(
396 preorderDispatchClasses.map((cls) => 405 preorderDispatchClasses.map((cls) =>
397 new js.ArrayInitializer.from([ 406 new js.ArrayInitializer.from([
398 new js.LiteralString("'${toNativeTag(cls)}'"), 407 new js.LiteralString("'${toNativeName(cls)}'"),
399 tagDefns[cls]]))); 408 tagDefns[cls]])));
400 409
401 // $.dynamicSetMetadata(table); 410 // $.dynamicSetMetadata(table);
402 statements.add( 411 statements.add(
403 new js.ExpressionStatement( 412 new js.ExpressionStatement(
404 new js.Call( 413 new js.Call(
405 new js.VariableUse(dynamicSetMetadataName), 414 new js.VariableUse(dynamicSetMetadataName),
406 [table]))); 415 [table])));
407 416
408 // (function(){statements})(); 417 // (function(){statements})();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 if (!first) targetBuffer.add(",\n"); 506 if (!first) targetBuffer.add(",\n");
498 targetBuffer.add(" $name: $function"); 507 targetBuffer.add(" $name: $function");
499 first = false; 508 first = false;
500 }); 509 });
501 targetBuffer.add("\n});\n\n"); 510 targetBuffer.add("\n});\n\n");
502 } 511 }
503 targetBuffer.add(nativeBuffer); 512 targetBuffer.add(nativeBuffer);
504 targetBuffer.add('\n'); 513 targetBuffer.add('\n');
505 } 514 }
506 } 515 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698