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 computeRequiredTypeChecks() { | 133 void computeRequiredTypeChecks() { |
122 assert(checkedClasses == null); | 134 assert(checkedClasses == null && checkedTypedefs == null); |
135 | |
136 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); | |
137 | |
123 checkedClasses = new Set<ClassElement>(); | 138 checkedClasses = new Set<ClassElement>(); |
124 checkedTypedefs = new Set<TypedefElement>(); | 139 checkedTypedefs = new Set<TypedefElement>(); |
125 compiler.codegenWorld.isChecks.forEach((DartType t) { | 140 compiler.codegenWorld.isChecks.forEach((DartType t) { |
126 if (t is InterfaceType) { | 141 if (t is InterfaceType) { |
127 checkedClasses.add(t.element); | 142 checkedClasses.add(t.element); |
128 } else if (t is TypedefType) { | 143 } else if (t is TypedefType) { |
129 checkedTypedefs.add(t.element); | 144 checkedTypedefs.add(t.element); |
130 } | 145 } |
131 }); | 146 }); |
132 } | 147 } |
(...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1068 includeSuperMembers: false); | 1083 includeSuperMembers: false); |
1069 }); | 1084 }); |
1070 | 1085 |
1071 classElement.implementation.forEachMember( | 1086 classElement.implementation.forEachMember( |
1072 visitMember, | 1087 visitMember, |
1073 includeBackendMembers: true, | 1088 includeBackendMembers: true, |
1074 includeSuperMembers: false); | 1089 includeSuperMembers: false); |
1075 | 1090 |
1076 void generateIsTest(Element other) { | 1091 void generateIsTest(Element other) { |
1077 jsAst.Expression code; | 1092 jsAst.Expression code; |
1078 if (compiler.objectClass == other) return; | 1093 if (other == compiler.objectClass && other != classElement) { |
1094 » // Avoid emitting [:$isObject:] on all classes but [Object]. | |
ngeoffray
2013/02/27 12:36:28
But will we? We're not adding anything on a class
karlklose
2013/02/27 16:11:32
We need this check, since we do not track the is-c
| |
1095 » return; | |
ngeoffray
2013/02/27 12:36:28
Remove tabs.
karlklose
2013/02/27 16:11:32
Done.
| |
1096 } | |
1079 if (nativeEmitter.requiresNativeIsCheck(other)) { | 1097 if (nativeEmitter.requiresNativeIsCheck(other)) { |
1080 code = js.fun([], [js.return_(true)]); | 1098 code = js.fun([], [js.return_(true)]); |
1081 } else { | 1099 } else { |
1082 code = new jsAst.LiteralBool(true); | 1100 code = new jsAst.LiteralBool(true); |
1083 } | 1101 } |
1084 builder.addProperty(namer.operatorIs(other), code); | 1102 builder.addProperty(namer.operatorIs(other), code); |
1085 } | 1103 } |
1086 | 1104 |
1087 void generateSubstitution(Element other, {bool emitNull: false}) { | 1105 void generateSubstitution(Element other, {bool emitNull: false}) { |
1088 RuntimeTypeInformation rti = backend.rti; | 1106 RuntimeTypeInformation rti = backend.rti; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1129 String name = backend.namer.publicInstanceMethodNameByArity( | 1147 String name = backend.namer.publicInstanceMethodNameByArity( |
1130 const SourceString('=='), 1); | 1148 const SourceString('=='), 1); |
1131 Function kind = (classElement == backend.jsNullClass) | 1149 Function kind = (classElement == backend.jsNullClass) |
1132 ? js.equals | 1150 ? js.equals |
1133 : js.strictEquals; | 1151 : js.strictEquals; |
1134 builder.addProperty(name, js.fun(['receiver', 'a'], | 1152 builder.addProperty(name, js.fun(['receiver', 'a'], |
1135 js.block(js.return_(kind(js['receiver'], js['a']))))); | 1153 js.block(js.return_(kind(js['receiver'], js['a']))))); |
1136 } | 1154 } |
1137 } | 1155 } |
1138 | 1156 |
1139 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 1157 void emitRuntimeTypeSupport(CodeBuffer buffer) { |
1140 RuntimeTypeInformation rti = backend.rti; | 1158 RuntimeTypeInformation rti = backend.rti; |
1141 TypeChecks typeChecks = rti.getRequiredChecks(); | 1159 TypeChecks typeChecks = rti.getRequiredChecks(); |
1142 | 1160 |
1161 /// Classes that are not instantiated and native classes need a holder | |
1162 /// object for their checks, because there will be no class defined for | |
1163 /// them. | |
1143 bool needsHolder(ClassElement cls) { | 1164 bool needsHolder(ClassElement cls) { |
1144 return !neededClasses.contains(cls) || cls.isNative() || | 1165 return !neededClasses.contains(cls) || cls.isNative(); |
1145 rti.isJsNative(cls); | |
1146 } | 1166 } |
1147 | 1167 |
1148 /** | 1168 /** |
1149 * Generates a holder object if it is needed. A holder is a JavaScript | 1169 * Generates a holder object if it is needed. A holder is a JavaScript |
1150 * object literal with a field [builtin$cls] that contains the name of the | 1170 * object literal with a field [builtin$cls] that contains the name of the |
1151 * class as a string (just like object constructors do). The is-checks for | 1171 * class as a string (just like object constructors do). The is-checks for |
1152 * the class are are added to the holder object later. | 1172 * the class are are added to the holder object later. |
1153 */ | 1173 */ |
1154 void maybeGenerateHolder(ClassElement cls) { | 1174 void maybeGenerateHolder(ClassElement cls) { |
1155 if (!needsHolder(cls)) return; | 1175 if (!needsHolder(cls)) return; |
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1558 // substitutions for all checks and make emitSubstitution a NOP for the | 1578 // substitutions for all checks and make emitSubstitution a NOP for the |
1559 // rest of this function. | 1579 // rest of this function. |
1560 Set<ClassElement> emitted = new Set<ClassElement>(); | 1580 Set<ClassElement> emitted = new Set<ClassElement>(); |
1561 // TODO(karlklose): move the computation of these checks to | 1581 // TODO(karlklose): move the computation of these checks to |
1562 // RuntimeTypeInformation. | 1582 // RuntimeTypeInformation. |
1563 if (compiler.world.needsRti(cls)) { | 1583 if (compiler.world.needsRti(cls)) { |
1564 emitSubstitution(superclass, emitNull: true); | 1584 emitSubstitution(superclass, emitNull: true); |
1565 emitted.add(superclass); | 1585 emitted.add(superclass); |
1566 } | 1586 } |
1567 for (DartType supertype in cls.allSupertypes) { | 1587 for (DartType supertype in cls.allSupertypes) { |
1588 ClassElement superclass = supertype.element; | |
1589 if (classesUsingTypeVariableTests.contains(superclass)) { | |
1590 emitSubstitution(superclass, emitNull: true); | |
1591 emitted.add(superclass); | |
1592 } | |
1568 for (ClassElement check in checkedClasses) { | 1593 for (ClassElement check in checkedClasses) { |
1569 if (supertype.element == check && !emitted.contains(check)) { | 1594 if (supertype.element == check && !emitted.contains(check)) { |
1570 // Generate substitution. If no substitution is necessary, emit | 1595 // Generate substitution. If no substitution is necessary, emit |
1571 // [:null:] to overwrite a (possibly) existing substitution from the | 1596 // [:null:] to overwrite a (possibly) existing substitution from the |
1572 // super classes. | 1597 // super classes. |
1573 emitSubstitution(check, emitNull: true); | 1598 emitSubstitution(check, emitNull: true); |
1574 emitted.add(check); | 1599 emitted.add(check); |
1575 } | 1600 } |
1576 } | 1601 } |
1577 } | 1602 } |
(...skipping 997 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2575 ..addAll(buildFinishIsolateConstructor()) | 2600 ..addAll(buildFinishIsolateConstructor()) |
2576 ); | 2601 ); |
2577 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( | 2602 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( |
2578 new jsAst.VariableDeclaration('init'), fun); | 2603 new jsAst.VariableDeclaration('init'), fun); |
2579 buffer.add(jsAst.prettyPrint(decl, compiler).getText()); | 2604 buffer.add(jsAst.prettyPrint(decl, compiler).getText()); |
2580 } | 2605 } |
2581 | 2606 |
2582 String assembleProgram() { | 2607 String assembleProgram() { |
2583 measure(() { | 2608 measure(() { |
2584 computeNeededClasses(); | 2609 computeNeededClasses(); |
2585 | |
2586 mainBuffer.add(GENERATED_BY); | 2610 mainBuffer.add(GENERATED_BY); |
2587 if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE); | 2611 if (!compiler.enableMinification) mainBuffer.add(HOOKS_API_USAGE); |
2588 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); | 2612 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); |
2589 mainBuffer.add('init()$N$n'); | 2613 mainBuffer.add('init()$N$n'); |
2590 // Shorten the code by using "$$" as temporary. | 2614 // Shorten the code by using "$$" as temporary. |
2591 classesCollector = r"$$"; | 2615 classesCollector = r"$$"; |
2592 mainBuffer.add('var $classesCollector$_=$_{}$N'); | 2616 mainBuffer.add('var $classesCollector$_=$_{}$N'); |
2593 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. | 2617 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
2594 isolateProperties = namer.CURRENT_ISOLATE; | 2618 isolateProperties = namer.CURRENT_ISOLATE; |
2595 mainBuffer.add( | 2619 mainBuffer.add( |
2596 'var $isolateProperties$_=$_$isolatePropertiesName$N'); | 2620 'var $isolateProperties$_=$_$isolatePropertiesName$N'); |
2597 emitClasses(mainBuffer); | 2621 emitClasses(mainBuffer); |
2598 mainBuffer.add(boundClosureBuffer); | 2622 mainBuffer.add(boundClosureBuffer); |
2599 // Clear the buffer, so that we can reuse it for the native classes. | 2623 // Clear the buffer, so that we can reuse it for the native classes. |
2600 boundClosureBuffer.clear(); | 2624 boundClosureBuffer.clear(); |
2601 emitStaticFunctions(mainBuffer); | 2625 emitStaticFunctions(mainBuffer); |
2602 emitStaticFunctionGetters(mainBuffer); | 2626 emitStaticFunctionGetters(mainBuffer); |
2603 // We need to finish the classes before we construct compile time | 2627 // We need to finish the classes before we construct compile time |
2604 // constants. | 2628 // constants. |
2605 emitFinishClassesInvocationIfNecessary(mainBuffer); | 2629 emitFinishClassesInvocationIfNecessary(mainBuffer); |
2606 emitRuntimeClassesAndTests(mainBuffer); | 2630 emitRuntimeTypeSupport(mainBuffer); |
2607 emitCompileTimeConstants(mainBuffer); | 2631 emitCompileTimeConstants(mainBuffer); |
2608 // Static field initializations require the classes and compile-time | 2632 // Static field initializations require the classes and compile-time |
2609 // constants to be set up. | 2633 // constants to be set up. |
2610 emitStaticNonFinalFieldInitializations(mainBuffer); | 2634 emitStaticNonFinalFieldInitializations(mainBuffer); |
2611 emitOneShotInterceptors(mainBuffer); | 2635 emitOneShotInterceptors(mainBuffer); |
2612 emitGetInterceptorMethods(mainBuffer); | 2636 emitGetInterceptorMethods(mainBuffer); |
2613 emitLazilyInitializedStaticFields(mainBuffer); | 2637 emitLazilyInitializedStaticFields(mainBuffer); |
2614 | 2638 |
2615 isolateProperties = isolatePropertiesName; | 2639 isolateProperties = isolatePropertiesName; |
2616 // The following code should not use the short-hand for the | 2640 // The following code should not use the short-hand for the |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2676 """; | 2700 """; |
2677 const String HOOKS_API_USAGE = """ | 2701 const String HOOKS_API_USAGE = """ |
2678 // The code supports the following hooks: | 2702 // The code supports the following hooks: |
2679 // dartPrint(message) - if this function is defined it is called | 2703 // dartPrint(message) - if this function is defined it is called |
2680 // instead of the Dart [print] method. | 2704 // instead of the Dart [print] method. |
2681 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2705 // dartMainRunner(main) - if this function is defined, the Dart [main] |
2682 // method will not be invoked directly. | 2706 // method will not be invoked directly. |
2683 // Instead, a closure that will invoke [main] is | 2707 // Instead, a closure that will invoke [main] is |
2684 // passed to [dartMainRunner]. | 2708 // passed to [dartMainRunner]. |
2685 """; | 2709 """; |
OLD | NEW |