| 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 part of js_backend; | 5 part of js_backend; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
| 9 * from the given element. | 9 * from the given element. |
| 10 */ | 10 */ |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 | 100 |
| 101 /** | 101 /** |
| 102 * Raw Typedef symbols occuring in is-checks and type assertions. If the | 102 * Raw Typedef symbols occuring in is-checks and type assertions. If the |
| 103 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement | 103 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement |
| 104 * `F` will occur once in [checkedTypedefs]. | 104 * `F` will occur once in [checkedTypedefs]. |
| 105 */ | 105 */ |
| 106 Set<TypedefElement> checkedTypedefs; | 106 Set<TypedefElement> checkedTypedefs; |
| 107 | 107 |
| 108 final bool generateSourceMap; | 108 final bool generateSourceMap; |
| 109 | 109 |
| 110 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; |
| 111 |
| 112 Iterable<ClassElement> get classesUsingTypeVariableTests { |
| 113 if (cachedClassesUsingTypeVariableTests == null) { |
| 114 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks |
| 115 .where((DartType t) => t is TypeVariableType) |
| 116 .map((TypeVariableType v) => v.element.getEnclosingClass()) |
| 117 .toList(); |
| 118 } |
| 119 return cachedClassesUsingTypeVariableTests; |
| 120 } |
| 121 |
| 110 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) | 122 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) |
| 111 : boundClosureBuffer = new CodeBuffer(), | 123 : boundClosureBuffer = new CodeBuffer(), |
| 112 mainBuffer = new CodeBuffer(), | 124 mainBuffer = new CodeBuffer(), |
| 113 this.namer = namer, | 125 this.namer = namer, |
| 114 boundClosureCache = new Map<int, String>(), | 126 boundClosureCache = new Map<int, String>(), |
| 115 interceptorClosureCache = new Map<int, String>(), | 127 interceptorClosureCache = new Map<int, String>(), |
| 116 constantEmitter = new ConstantEmitter(compiler, namer), | 128 constantEmitter = new ConstantEmitter(compiler, namer), |
| 117 super(compiler) { | 129 super(compiler) { |
| 118 nativeEmitter = new NativeEmitter(this); | 130 nativeEmitter = new NativeEmitter(this); |
| 119 } | 131 } |
| 120 | 132 |
| 121 void addComment(String comment, CodeBuffer buffer) { | 133 void addComment(String comment, CodeBuffer buffer) { |
| 122 buffer.add(jsAst.prettyPrint(js.comment(comment), compiler)); | 134 buffer.add(jsAst.prettyPrint(js.comment(comment), compiler)); |
| 123 } | 135 } |
| 124 | 136 |
| 125 void computeRequiredTypeChecks() { | 137 void computeRequiredTypeChecks() { |
| 126 assert(checkedClasses == null); | 138 assert(checkedClasses == null && checkedTypedefs == null); |
| 139 |
| 140 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); |
| 141 |
| 127 checkedClasses = new Set<ClassElement>(); | 142 checkedClasses = new Set<ClassElement>(); |
| 128 checkedTypedefs = new Set<TypedefElement>(); | 143 checkedTypedefs = new Set<TypedefElement>(); |
| 129 compiler.codegenWorld.isChecks.forEach((DartType t) { | 144 compiler.codegenWorld.isChecks.forEach((DartType t) { |
| 130 if (t is InterfaceType) { | 145 if (t is InterfaceType) { |
| 131 checkedClasses.add(t.element); | 146 checkedClasses.add(t.element); |
| 132 } else if (t is TypedefType) { | 147 } else if (t is TypedefType) { |
| 133 checkedTypedefs.add(t.element); | 148 checkedTypedefs.add(t.element); |
| 134 } | 149 } |
| 135 }); | 150 }); |
| 136 } | 151 } |
| (...skipping 788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 925 includeSuperMembers: false); | 940 includeSuperMembers: false); |
| 926 }); | 941 }); |
| 927 | 942 |
| 928 classElement.implementation.forEachMember( | 943 classElement.implementation.forEachMember( |
| 929 visitMember, | 944 visitMember, |
| 930 includeBackendMembers: true, | 945 includeBackendMembers: true, |
| 931 includeSuperMembers: false); | 946 includeSuperMembers: false); |
| 932 | 947 |
| 933 void generateIsTest(Element other) { | 948 void generateIsTest(Element other) { |
| 934 jsAst.Expression code; | 949 jsAst.Expression code; |
| 935 if (compiler.objectClass == other) return; | 950 if (other == compiler.objectClass && other != classElement) { |
| 951 // Avoid emitting [:$isObject:] on all classes but [Object]. |
| 952 return; |
| 953 } |
| 936 if (nativeEmitter.requiresNativeIsCheck(other)) { | 954 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 937 code = js.fun([], [js.return_(true)]); | 955 code = js.fun([], [js.return_(true)]); |
| 938 } else { | 956 } else { |
| 939 code = new jsAst.LiteralBool(true); | 957 code = new jsAst.LiteralBool(true); |
| 940 } | 958 } |
| 941 builder.addProperty(namer.operatorIs(other), code); | 959 builder.addProperty(namer.operatorIs(other), code); |
| 942 } | 960 } |
| 943 | 961 |
| 944 void generateSubstitution(Element other, {bool emitNull: false}) { | 962 void generateSubstitution(Element other, {bool emitNull: false}) { |
| 945 RuntimeTypeInformation rti = backend.rti; | 963 RuntimeTypeInformation rti = backend.rti; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 986 String name = backend.namer.publicInstanceMethodNameByArity( | 1004 String name = backend.namer.publicInstanceMethodNameByArity( |
| 987 const SourceString('=='), 1); | 1005 const SourceString('=='), 1); |
| 988 Function kind = (classElement == backend.jsNullClass) | 1006 Function kind = (classElement == backend.jsNullClass) |
| 989 ? js.equals | 1007 ? js.equals |
| 990 : js.strictEquals; | 1008 : js.strictEquals; |
| 991 builder.addProperty(name, js.fun(['receiver', 'a'], | 1009 builder.addProperty(name, js.fun(['receiver', 'a'], |
| 992 js.block(js.return_(kind(js['receiver'], js['a']))))); | 1010 js.block(js.return_(kind(js['receiver'], js['a']))))); |
| 993 } | 1011 } |
| 994 } | 1012 } |
| 995 | 1013 |
| 996 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 1014 void emitRuntimeTypeSupport(CodeBuffer buffer) { |
| 997 RuntimeTypeInformation rti = backend.rti; | 1015 RuntimeTypeInformation rti = backend.rti; |
| 998 TypeChecks typeChecks = rti.getRequiredChecks(); | 1016 TypeChecks typeChecks = rti.getRequiredChecks(); |
| 999 | 1017 |
| 1018 /// Classes that are not instantiated and native classes need a holder |
| 1019 /// object for their checks, because there will be no class defined for |
| 1020 /// them. |
| 1000 bool needsHolder(ClassElement cls) { | 1021 bool needsHolder(ClassElement cls) { |
| 1001 return !neededClasses.contains(cls) || cls.isNative() || | 1022 return !neededClasses.contains(cls) || cls.isNative() || |
| 1002 rti.isJsNative(cls); | 1023 rti.isJsNative(cls); |
| 1003 } | 1024 } |
| 1004 | 1025 |
| 1005 /** | 1026 /** |
| 1006 * Generates a holder object if it is needed. A holder is a JavaScript | 1027 * Generates a holder object if it is needed. A holder is a JavaScript |
| 1007 * object literal with a field [builtin$cls] that contains the name of the | 1028 * object literal with a field [builtin$cls] that contains the name of the |
| 1008 * class as a string (just like object constructors do). The is-checks for | 1029 * class as a string (just like object constructors do). The is-checks for |
| 1009 * the class are are added to the holder object later. | 1030 * the class are are added to the holder object later. |
| 1010 */ | 1031 */ |
| 1011 void maybeGenerateHolder(ClassElement cls) { | 1032 void maybeGenerateHolder(ClassElement cls) { |
| 1012 if (!needsHolder(cls)) return; | 1033 if (!needsHolder(cls)) return; |
| (...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1415 // substitutions for all checks and make emitSubstitution a NOP for the | 1436 // substitutions for all checks and make emitSubstitution a NOP for the |
| 1416 // rest of this function. | 1437 // rest of this function. |
| 1417 Set<ClassElement> emitted = new Set<ClassElement>(); | 1438 Set<ClassElement> emitted = new Set<ClassElement>(); |
| 1418 // TODO(karlklose): move the computation of these checks to | 1439 // TODO(karlklose): move the computation of these checks to |
| 1419 // RuntimeTypeInformation. | 1440 // RuntimeTypeInformation. |
| 1420 if (compiler.world.needsRti(cls)) { | 1441 if (compiler.world.needsRti(cls)) { |
| 1421 emitSubstitution(superclass, emitNull: true); | 1442 emitSubstitution(superclass, emitNull: true); |
| 1422 emitted.add(superclass); | 1443 emitted.add(superclass); |
| 1423 } | 1444 } |
| 1424 for (DartType supertype in cls.allSupertypes) { | 1445 for (DartType supertype in cls.allSupertypes) { |
| 1446 ClassElement superclass = supertype.element; |
| 1447 if (classesUsingTypeVariableTests.contains(superclass)) { |
| 1448 emitSubstitution(superclass, emitNull: true); |
| 1449 emitted.add(superclass); |
| 1450 } |
| 1425 for (ClassElement check in checkedClasses) { | 1451 for (ClassElement check in checkedClasses) { |
| 1426 if (supertype.element == check && !emitted.contains(check)) { | 1452 if (supertype.element == check && !emitted.contains(check)) { |
| 1427 // Generate substitution. If no substitution is necessary, emit | 1453 // Generate substitution. If no substitution is necessary, emit |
| 1428 // [:null:] to overwrite a (possibly) existing substitution from the | 1454 // [:null:] to overwrite a (possibly) existing substitution from the |
| 1429 // super classes. | 1455 // super classes. |
| 1430 emitSubstitution(check, emitNull: true); | 1456 emitSubstitution(check, emitNull: true); |
| 1431 emitted.add(check); | 1457 emitted.add(check); |
| 1432 } | 1458 } |
| 1433 } | 1459 } |
| 1434 } | 1460 } |
| (...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2552 ..addAll(buildFinishIsolateConstructor()) | 2578 ..addAll(buildFinishIsolateConstructor()) |
| 2553 ); | 2579 ); |
| 2554 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( | 2580 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( |
| 2555 new jsAst.VariableDeclaration('init'), fun); | 2581 new jsAst.VariableDeclaration('init'), fun); |
| 2556 buffer.add(jsAst.prettyPrint(decl, compiler).getText()); | 2582 buffer.add(jsAst.prettyPrint(decl, compiler).getText()); |
| 2557 } | 2583 } |
| 2558 | 2584 |
| 2559 String assembleProgram() { | 2585 String assembleProgram() { |
| 2560 measure(() { | 2586 measure(() { |
| 2561 computeNeededClasses(); | 2587 computeNeededClasses(); |
| 2562 | |
| 2563 mainBuffer.add(GENERATED_BY); | 2588 mainBuffer.add(GENERATED_BY); |
| 2564 addComment(HOOKS_API_USAGE, mainBuffer); | 2589 addComment(HOOKS_API_USAGE, mainBuffer); |
| 2565 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); | 2590 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); |
| 2566 mainBuffer.add('init()$N$n'); | 2591 mainBuffer.add('init()$N$n'); |
| 2567 // Shorten the code by using "$$" as temporary. | 2592 // Shorten the code by using "$$" as temporary. |
| 2568 classesCollector = r"$$"; | 2593 classesCollector = r"$$"; |
| 2569 mainBuffer.add('var $classesCollector$_=$_{}$N'); | 2594 mainBuffer.add('var $classesCollector$_=$_{}$N'); |
| 2570 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. | 2595 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
| 2571 isolateProperties = namer.CURRENT_ISOLATE; | 2596 isolateProperties = namer.CURRENT_ISOLATE; |
| 2572 mainBuffer.add( | 2597 mainBuffer.add( |
| 2573 'var $isolateProperties$_=$_$isolatePropertiesName$N'); | 2598 'var $isolateProperties$_=$_$isolatePropertiesName$N'); |
| 2574 emitClasses(mainBuffer); | 2599 emitClasses(mainBuffer); |
| 2575 mainBuffer.add(boundClosureBuffer); | 2600 mainBuffer.add(boundClosureBuffer); |
| 2576 // Clear the buffer, so that we can reuse it for the native classes. | 2601 // Clear the buffer, so that we can reuse it for the native classes. |
| 2577 boundClosureBuffer.clear(); | 2602 boundClosureBuffer.clear(); |
| 2578 emitStaticFunctions(mainBuffer); | 2603 emitStaticFunctions(mainBuffer); |
| 2579 emitStaticFunctionGetters(mainBuffer); | 2604 emitStaticFunctionGetters(mainBuffer); |
| 2580 // We need to finish the classes before we construct compile time | 2605 // We need to finish the classes before we construct compile time |
| 2581 // constants. | 2606 // constants. |
| 2582 emitFinishClassesInvocationIfNecessary(mainBuffer); | 2607 emitFinishClassesInvocationIfNecessary(mainBuffer); |
| 2583 emitRuntimeClassesAndTests(mainBuffer); | 2608 emitRuntimeTypeSupport(mainBuffer); |
| 2584 emitCompileTimeConstants(mainBuffer); | 2609 emitCompileTimeConstants(mainBuffer); |
| 2585 // Static field initializations require the classes and compile-time | 2610 // Static field initializations require the classes and compile-time |
| 2586 // constants to be set up. | 2611 // constants to be set up. |
| 2587 emitStaticNonFinalFieldInitializations(mainBuffer); | 2612 emitStaticNonFinalFieldInitializations(mainBuffer); |
| 2588 emitOneShotInterceptors(mainBuffer); | 2613 emitOneShotInterceptors(mainBuffer); |
| 2589 emitGetInterceptorMethods(mainBuffer); | 2614 emitGetInterceptorMethods(mainBuffer); |
| 2590 emitLazilyInitializedStaticFields(mainBuffer); | 2615 emitLazilyInitializedStaticFields(mainBuffer); |
| 2591 | 2616 |
| 2592 isolateProperties = isolatePropertiesName; | 2617 isolateProperties = isolatePropertiesName; |
| 2593 // The following code should not use the short-hand for the | 2618 // The following code should not use the short-hand for the |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2691 """; | 2716 """; |
| 2692 const String HOOKS_API_USAGE = """ | 2717 const String HOOKS_API_USAGE = """ |
| 2693 // The code supports the following hooks: | 2718 // The code supports the following hooks: |
| 2694 // dartPrint(message) - if this function is defined it is called | 2719 // dartPrint(message) - if this function is defined it is called |
| 2695 // instead of the Dart [print] method. | 2720 // instead of the Dart [print] method. |
| 2696 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2721 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2697 // method will not be invoked directly. | 2722 // method will not be invoked directly. |
| 2698 // Instead, a closure that will invoke [main] is | 2723 // Instead, a closure that will invoke [main] is |
| 2699 // passed to [dartMainRunner]. | 2724 // passed to [dartMainRunner]. |
| 2700 """; | 2725 """; |
| OLD | NEW |