| 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 library dart2js.js_emitter.native_emitter; | 5 library dart2js.js_emitter.native_emitter; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../elements/types.dart' show DartType, FunctionType; | 9 import '../elements/types.dart' show DartType, FunctionType; |
| 10 import '../elements/entities.dart'; | 10 import '../elements/entities.dart'; |
| 11 import '../js/js.dart' as jsAst; | 11 import '../js/js.dart' as jsAst; |
| 12 import '../js/js.dart' show js; | 12 import '../js/js.dart' show js; |
| 13 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 13 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 14 import '../js_backend/js_backend.dart' show JavaScriptBackend; | 14 import '../js_backend/js_backend.dart' show JavaScriptBackend, Namer; |
| 15 import '../js_backend/interceptor_data.dart'; |
| 16 import '../js_backend/native_data.dart'; |
| 15 import '../universe/world_builder.dart' show CodegenWorldBuilder; | 17 import '../universe/world_builder.dart' show CodegenWorldBuilder; |
| 16 | 18 |
| 17 import 'code_emitter_task.dart' show CodeEmitterTask; | 19 import 'code_emitter_task.dart' show CodeEmitterTask; |
| 18 import 'model.dart'; | 20 import 'model.dart'; |
| 19 | 21 |
| 20 class NativeEmitter { | 22 class NativeEmitter { |
| 21 final CodeEmitterTask emitterTask; | 23 final CodeEmitterTask emitterTask; |
| 22 | 24 |
| 23 // Whether the application contains native classes. | 25 // Whether the application contains native classes. |
| 24 bool hasNativeClasses = false; | 26 bool hasNativeClasses = false; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 37 NativeEmitter(CodeEmitterTask emitterTask) : this.emitterTask = emitterTask; | 39 NativeEmitter(CodeEmitterTask emitterTask) : this.emitterTask = emitterTask; |
| 38 | 40 |
| 39 Compiler get compiler => emitterTask.compiler; | 41 Compiler get compiler => emitterTask.compiler; |
| 40 | 42 |
| 41 JavaScriptBackend get backend => compiler.backend; | 43 JavaScriptBackend get backend => compiler.backend; |
| 42 | 44 |
| 43 BackendHelpers get helpers => backend.helpers; | 45 BackendHelpers get helpers => backend.helpers; |
| 44 | 46 |
| 45 CodegenWorldBuilder get worldBuilder => compiler.codegenWorldBuilder; | 47 CodegenWorldBuilder get worldBuilder => compiler.codegenWorldBuilder; |
| 46 | 48 |
| 49 NativeData get nativeData => backend.nativeData; |
| 50 |
| 51 InterceptorData get interceptorData => backend.interceptorData; |
| 52 |
| 53 Namer get namer => backend.namer; |
| 54 |
| 47 /** | 55 /** |
| 48 * Prepares native classes for emission. Returns the unneeded classes. | 56 * Prepares native classes for emission. Returns the unneeded classes. |
| 49 * | 57 * |
| 50 * Removes trivial classes (that can be represented by a super type) and | 58 * Removes trivial classes (that can be represented by a super type) and |
| 51 * generates properties that have to be added to classes (native or not). | 59 * generates properties that have to be added to classes (native or not). |
| 52 * | 60 * |
| 53 * Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions` | 61 * Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions` |
| 54 * fields of the given classes. This data must be emitted with the | 62 * fields of the given classes. This data must be emitted with the |
| 55 * corresponding classes. | 63 * corresponding classes. |
| 56 * | 64 * |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 needed = true; | 142 needed = true; |
| 135 } else if (interceptorClassesNeededByConstants.contains(classElement)) { | 143 } else if (interceptorClassesNeededByConstants.contains(classElement)) { |
| 136 needed = true; | 144 needed = true; |
| 137 } else if (classesModifiedByEmitRTISupport.contains(classElement)) { | 145 } else if (classesModifiedByEmitRTISupport.contains(classElement)) { |
| 138 // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer | 146 // TODO(9556): Remove this test when [emitRuntimeTypeSupport] no longer |
| 139 // adds information to a class prototype or constructor. | 147 // adds information to a class prototype or constructor. |
| 140 needed = true; | 148 needed = true; |
| 141 } else if (extensionPoints.containsKey(cls)) { | 149 } else if (extensionPoints.containsKey(cls)) { |
| 142 needed = true; | 150 needed = true; |
| 143 } | 151 } |
| 144 if (backend.isJsInteropClass(classElement)) { | 152 if (nativeData.isJsInteropClass(classElement)) { |
| 145 needed = true; // TODO(jacobr): we don't need all interop classes. | 153 needed = true; // TODO(jacobr): we don't need all interop classes. |
| 146 } else if (cls.isNative && | 154 } else if (cls.isNative && |
| 147 backend.nativeData.hasNativeTagsForcedNonLeaf(classElement)) { | 155 nativeData.hasNativeTagsForcedNonLeaf(classElement)) { |
| 148 needed = true; | 156 needed = true; |
| 149 nonLeafClasses.add(cls); | 157 nonLeafClasses.add(cls); |
| 150 } | 158 } |
| 151 | 159 |
| 152 if (needed || neededClasses.contains(cls)) { | 160 if (needed || neededClasses.contains(cls)) { |
| 153 neededClasses.add(cls); | 161 neededClasses.add(cls); |
| 154 neededClasses.add(cls.superclass); | 162 neededClasses.add(cls.superclass); |
| 155 nonLeafClasses.add(cls.superclass); | 163 nonLeafClasses.add(cls.superclass); |
| 156 } | 164 } |
| 157 } | 165 } |
| 158 | 166 |
| 159 // Collect all the tags that map to each native class. | 167 // Collect all the tags that map to each native class. |
| 160 | 168 |
| 161 Map<Class, Set<String>> leafTags = new Map<Class, Set<String>>(); | 169 Map<Class, Set<String>> leafTags = new Map<Class, Set<String>>(); |
| 162 Map<Class, Set<String>> nonleafTags = new Map<Class, Set<String>>(); | 170 Map<Class, Set<String>> nonleafTags = new Map<Class, Set<String>>(); |
| 163 | 171 |
| 164 for (Class cls in classes) { | 172 for (Class cls in classes) { |
| 165 if (!cls.isNative) continue; | 173 if (!cls.isNative) continue; |
| 166 ClassEntity element = cls.element; | 174 ClassEntity element = cls.element; |
| 167 if (backend.isJsInteropClass(element)) continue; | 175 if (nativeData.isJsInteropClass(element)) continue; |
| 168 List<String> nativeTags = | 176 List<String> nativeTags = nativeData.getNativeTagsOfClass(cls.element); |
| 169 backend.nativeData.getNativeTagsOfClass(cls.element); | |
| 170 | 177 |
| 171 if (nonLeafClasses.contains(cls) || extensionPoints.containsKey(cls)) { | 178 if (nonLeafClasses.contains(cls) || extensionPoints.containsKey(cls)) { |
| 172 nonleafTags | 179 nonleafTags |
| 173 .putIfAbsent(cls, () => new Set<String>()) | 180 .putIfAbsent(cls, () => new Set<String>()) |
| 174 .addAll(nativeTags); | 181 .addAll(nativeTags); |
| 175 } else { | 182 } else { |
| 176 Class sufficingInterceptor = cls; | 183 Class sufficingInterceptor = cls; |
| 177 while (!neededClasses.contains(sufficingInterceptor)) { | 184 while (!neededClasses.contains(sufficingInterceptor)) { |
| 178 sufficingInterceptor = sufficingInterceptor.superclass; | 185 sufficingInterceptor = sufficingInterceptor.superclass; |
| 179 } | 186 } |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 List<jsAst.Statement> statements = <jsAst.Statement>[]; | 313 List<jsAst.Statement> statements = <jsAst.Statement>[]; |
| 307 potentiallyConvertDartClosuresToJs(statements, member, stubParameters); | 314 potentiallyConvertDartClosuresToJs(statements, member, stubParameters); |
| 308 | 315 |
| 309 String target; | 316 String target; |
| 310 jsAst.Expression receiver; | 317 jsAst.Expression receiver; |
| 311 List<jsAst.Expression> arguments; | 318 List<jsAst.Expression> arguments; |
| 312 | 319 |
| 313 assert(invariant(member, nativeMethods.contains(member))); | 320 assert(invariant(member, nativeMethods.contains(member))); |
| 314 // When calling a JS method, we call it with the native name, and only the | 321 // When calling a JS method, we call it with the native name, and only the |
| 315 // arguments up until the last one provided. | 322 // arguments up until the last one provided. |
| 316 target = backend.nativeData.getFixedBackendName(member); | 323 target = nativeData.getFixedBackendName(member); |
| 317 | 324 |
| 318 if (isInterceptedMethod) { | 325 if (isInterceptedMethod) { |
| 319 receiver = argumentsBuffer[0]; | 326 receiver = argumentsBuffer[0]; |
| 320 arguments = argumentsBuffer.sublist( | 327 arguments = argumentsBuffer.sublist( |
| 321 1, indexOfLastOptionalArgumentInParameters + 1); | 328 1, indexOfLastOptionalArgumentInParameters + 1); |
| 322 } else { | 329 } else { |
| 323 // Native methods that are not intercepted must be static. | 330 // Native methods that are not intercepted must be static. |
| 324 assert(invariant(member, member.isStatic)); | 331 assert(invariant(member, member.isStatic)); |
| 325 arguments = argumentsBuffer.sublist( | 332 arguments = argumentsBuffer.sublist( |
| 326 0, indexOfLastOptionalArgumentInParameters + 1); | 333 0, indexOfLastOptionalArgumentInParameters + 1); |
| 327 if (backend.isJsInteropMethod(member)) { | 334 if (nativeData.isJsInteropMethod(member)) { |
| 328 // fixedBackendPath is allowed to have the form foo.bar.baz for | 335 // fixedBackendPath is allowed to have the form foo.bar.baz for |
| 329 // interop. This template is uncached to avoid possibly running out of | 336 // interop. This template is uncached to avoid possibly running out of |
| 330 // memory when Dart2Js is run in server mode. In reality the risk of | 337 // memory when Dart2Js is run in server mode. In reality the risk of |
| 331 // caching these templates causing an issue is very low as each class | 338 // caching these templates causing an issue is very low as each class |
| 332 // and library that uses typed JavaScript interop will create only 1 | 339 // and library that uses typed JavaScript interop will create only 1 |
| 333 // unique template. | 340 // unique template. |
| 334 receiver = js | 341 receiver = js |
| 335 .uncachedExpressionTemplate( | 342 .uncachedExpressionTemplate(namer.fixedBackendMethodPath(member)) |
| 336 backend.namer.fixedBackendMethodPath(member)) | |
| 337 .instantiate([]); | 343 .instantiate([]); |
| 338 } else { | 344 } else { |
| 339 receiver = js('this'); | 345 receiver = js('this'); |
| 340 } | 346 } |
| 341 } | 347 } |
| 342 statements | 348 statements |
| 343 .add(js.statement('return #.#(#)', [receiver, target, arguments])); | 349 .add(js.statement('return #.#(#)', [receiver, target, arguments])); |
| 344 | 350 |
| 345 return statements; | 351 return statements; |
| 346 } | 352 } |
| 347 | 353 |
| 348 bool isSupertypeOfNativeClass(ClassEntity element) { | 354 bool isSupertypeOfNativeClass(ClassEntity element) { |
| 349 if (backend.interceptorData.isMixedIntoInterceptedClass(element)) { | 355 if (interceptorData.isMixedIntoInterceptedClass(element)) { |
| 350 return true; | 356 return true; |
| 351 } | 357 } |
| 352 | 358 |
| 353 return subtypes[element] != null; | 359 return subtypes[element] != null; |
| 354 } | 360 } |
| 355 | 361 |
| 356 bool requiresNativeIsCheck(ClassEntity element) { | 362 bool requiresNativeIsCheck(ClassEntity element) { |
| 357 // TODO(sra): Remove this function. It determines if a native type may | 363 // TODO(sra): Remove this function. It determines if a native type may |
| 358 // satisfy a check against [element], in which case an interceptor must be | 364 // satisfy a check against [element], in which case an interceptor must be |
| 359 // used. We should also use an interceptor if the check can't be satisfied | 365 // used. We should also use an interceptor if the check can't be satisfied |
| 360 // by a native class in case we get a native instance that tries to spoof | 366 // by a native class in case we get a native instance that tries to spoof |
| 361 // the type info. i.e the criteria for whether or not to use an interceptor | 367 // the type info. i.e the criteria for whether or not to use an interceptor |
| 362 // is whether the receiver can be native, not the type of the test. | 368 // is whether the receiver can be native, not the type of the test. |
| 363 ClassEntity cls = element; | 369 ClassEntity cls = element; |
| 364 if (backend.nativeData.isNativeOrExtendsNative(cls)) return true; | 370 if (nativeData.isNativeOrExtendsNative(cls)) return true; |
| 365 return isSupertypeOfNativeClass(element); | 371 return isSupertypeOfNativeClass(element); |
| 366 } | 372 } |
| 367 } | 373 } |
| OLD | NEW |