| OLD | NEW |
| 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 class NativeEmitter { | 5 class NativeEmitter { |
| 6 | 6 |
| 7 Compiler compiler; | 7 Compiler compiler; |
| 8 StringBuffer buffer; | 8 StringBuffer buffer; |
| 9 | 9 |
| 10 // Classes that participate in dynamic dispatch. These are the | 10 // Classes that participate in dynamic dispatch. These are the |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 | 62 |
| 63 void generateNativeLiteral(ClassElement classElement) { | 63 void generateNativeLiteral(ClassElement classElement) { |
| 64 String quotedNative = classElement.nativeName.slowToString(); | 64 String quotedNative = classElement.nativeName.slowToString(); |
| 65 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); | 65 String nativeCode = quotedNative.substring(2, quotedNative.length - 1); |
| 66 String className = compiler.namer.getName(classElement); | 66 String className = compiler.namer.getName(classElement); |
| 67 buffer.add(className); | 67 buffer.add(className); |
| 68 buffer.add(' = '); | 68 buffer.add(' = '); |
| 69 buffer.add(nativeCode); | 69 buffer.add(nativeCode); |
| 70 buffer.add(';\n'); | 70 buffer.add(';\n'); |
| 71 | 71 |
| 72 String isolatePrototype = '${compiler.namer.ISOLATE}.prototype'; |
| 72 String attachTo(name) => "$className.$name"; | 73 String attachTo(name) => "$className.$name"; |
| 73 | 74 |
| 74 for (Element member in classElement.members) { | 75 for (Element member in classElement.members) { |
| 75 if (member.isInstanceMember()) { | 76 if (member.isInstanceMember()) { |
| 76 compiler.emitter.addInstanceMember( | 77 compiler.emitter.addInstanceMember( |
| 77 member, attachTo, buffer, isNative: true); | 78 member, attachTo, buffer, isolatePrototype, isNative: true); |
| 78 } | 79 } |
| 79 } | 80 } |
| 80 } | 81 } |
| 81 | 82 |
| 82 bool isNativeLiteral(String quotedName) { | 83 bool isNativeLiteral(String quotedName) { |
| 83 return quotedName[1] === '='; | 84 return quotedName[1] === '='; |
| 84 } | 85 } |
| 85 | 86 |
| 86 bool isNativeGlobal(String quotedName) { | 87 bool isNativeGlobal(String quotedName) { |
| 87 return quotedName[1] === '@'; | 88 return quotedName[1] === '@'; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 110 } | 111 } |
| 111 | 112 |
| 112 String nativeName = toNativeName(classElement); | 113 String nativeName = toNativeName(classElement); |
| 113 bool hasUsedSelectors = false; | 114 bool hasUsedSelectors = false; |
| 114 | 115 |
| 115 String attachTo(String name) { | 116 String attachTo(String name) { |
| 116 hasUsedSelectors = true; | 117 hasUsedSelectors = true; |
| 117 return "$dynamicName('$name').$nativeName"; | 118 return "$dynamicName('$name').$nativeName"; |
| 118 } | 119 } |
| 119 | 120 |
| 121 String isolatePrototype = '${compiler.namer.ISOLATE}.prototype'; |
| 120 for (Element member in classElement.members) { | 122 for (Element member in classElement.members) { |
| 121 if (member.isInstanceMember()) { | 123 if (member.isInstanceMember()) { |
| 122 compiler.emitter.addInstanceMember( | 124 compiler.emitter.addInstanceMember( |
| 123 member, attachTo, buffer, isNative: true); | 125 member, attachTo, buffer, isolatePrototype, isNative: true); |
| 124 } | 126 } |
| 125 } | 127 } |
| 126 | 128 |
| 127 compiler.emitter.generateTypeTests(classElement, (Element other) { | 129 compiler.emitter.generateTypeTests(classElement, (Element other) { |
| 128 assert(requiresNativeIsCheck(other)); | 130 assert(requiresNativeIsCheck(other)); |
| 129 buffer.add('${attachTo(compiler.namer.operatorIs(other))} = '); | 131 buffer.add('${attachTo(compiler.namer.operatorIs(other))} = '); |
| 130 buffer.add('function() { return true; };\n'); | 132 buffer.add('function() { return true; };\n'); |
| 131 }); | 133 }); |
| 132 | 134 |
| 133 if (hasUsedSelectors) classesWithDynamicDispatch.add(classElement); | 135 if (hasUsedSelectors) classesWithDynamicDispatch.add(classElement); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 buffer.add(Strings.join(entries, ',')); | 297 buffer.add(Strings.join(entries, ',')); |
| 296 buffer.add('];\n'); | 298 buffer.add('];\n'); |
| 297 buffer.add('$dynamicSetMetadataName(table);\n'); | 299 buffer.add('$dynamicSetMetadataName(table);\n'); |
| 298 | 300 |
| 299 buffer.add('})();\n'); | 301 buffer.add('})();\n'); |
| 300 } | 302 } |
| 301 } | 303 } |
| 302 | 304 |
| 303 bool isSupertypeOfNativeClass(Element element) { | 305 bool isSupertypeOfNativeClass(Element element) { |
| 304 if (element.isTypeVariable()) { | 306 if (element.isTypeVariable()) { |
| 305 compiler.cancel("Is check for type variable", element: work.element); | 307 compiler.cancel("Is check for type variable", element: element); |
| 306 return false; | 308 return false; |
| 307 } | 309 } |
| 308 if (element.computeType(compiler) is FunctionType) return false; | 310 if (element.computeType(compiler) is FunctionType) return false; |
| 309 | 311 |
| 310 if (!element.isClass()) { | 312 if (!element.isClass()) { |
| 311 compiler.cancel("Is check does not handle element", element: element); | 313 compiler.cancel("Is check does not handle element", element: element); |
| 312 return false; | 314 return false; |
| 313 } | 315 } |
| 314 | 316 |
| 315 return subtypes[element] !== null; | 317 return subtypes[element] !== null; |
| 316 } | 318 } |
| 317 | 319 |
| 318 bool requiresNativeIsCheck(Element element) { | 320 bool requiresNativeIsCheck(Element element) { |
| 319 if (!element.isClass()) return false; | 321 if (!element.isClass()) return false; |
| 320 ClassElement cls = element; | 322 ClassElement cls = element; |
| 321 if (cls.isNative()) return true; | 323 if (cls.isNative()) return true; |
| 322 return isSupertypeOfNativeClass(element); | 324 return isSupertypeOfNativeClass(element); |
| 323 } | 325 } |
| 324 | 326 |
| 325 void emitIsChecks(StringBuffer buffer) { | 327 void emitIsChecks(StringBuffer checkBuffer) { |
| 326 for (Element type in compiler.universe.isChecks) { | 328 for (Element type in compiler.universe.isChecks) { |
| 327 if (!requiresNativeIsCheck(type)) continue; | 329 if (!requiresNativeIsCheck(type)) continue; |
| 328 String name = compiler.namer.operatorIs(type); | 330 String name = compiler.namer.operatorIs(type); |
| 329 buffer.add("$defPropName(Object.prototype, '$name', "); | 331 checkBuffer.add("$defPropName(Object.prototype, '$name', "); |
| 330 buffer.add('function() { return false; });\n'); | 332 checkBuffer.add('function() { return false; });\n'); |
| 331 } | 333 } |
| 332 } | 334 } |
| 333 | 335 |
| 334 void assembleCode(StringBuffer targetBuffer) { | 336 void assembleCode(StringBuffer targetBuffer) { |
| 335 if (nativeClasses.isEmpty()) return; | 337 if (nativeClasses.isEmpty()) return; |
| 336 | 338 |
| 337 // Because of native classes, we have to generate some is checks | 339 // Because of native classes, we have to generate some is checks |
| 338 // by calling a method, instead of accessing a property. So we | 340 // by calling a method, instead of accessing a property. So we |
| 339 // attach to the JS Object prototype these methods that return | 341 // attach to the JS Object prototype these methods that return |
| 340 // false, and will be overridden by subclasses when they have to | 342 // false, and will be overridden by subclasses when they have to |
| 341 // return true. | 343 // return true. |
| 342 StringBuffer objectProperties = new StringBuffer(); | 344 StringBuffer objectProperties = new StringBuffer(); |
| 343 emitIsChecks(objectProperties); | 345 emitIsChecks(objectProperties); |
| 344 | 346 |
| 345 // In order to have the toString method on every native class, | 347 // In order to have the toString method on every native class, |
| 346 // we must patch the JS Object prototype with a helper method. | 348 // we must patch the JS Object prototype with a helper method. |
| 347 String toStringName = compiler.namer.instanceMethodName( | 349 String toStringName = compiler.namer.instanceMethodName( |
| 348 null, const SourceString('toString'), 0); | 350 null, const SourceString('toString'), 0); |
| 349 objectProperties.add("$defPropName(Object.prototype, '$toStringName', "); | 351 objectProperties.add("$defPropName(Object.prototype, '$toStringName', "); |
| 350 objectProperties.add( | 352 objectProperties.add( |
| 351 'function() { return $toStringHelperName(this); });\n'); | 353 'function() { return $toStringHelperName(this); });\n'); |
| 352 | 354 |
| 353 // Finally, emit the code in the main buffer. | 355 // Finally, emit the code in the main buffer. |
| 354 targetBuffer.add('(function() {\n$objectProperties$buffer\n})();\n'); | 356 targetBuffer.add('(function() {\n$objectProperties$buffer\n})();\n'); |
| 355 } | 357 } |
| 356 } | 358 } |
| OLD | NEW |