| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 | 7 |
| 8 class OldEmitter implements Emitter { | 8 class OldEmitter implements Emitter { |
| 9 final Compiler compiler; | 9 final Compiler compiler; |
| 10 final CodeEmitterTask task; | 10 final CodeEmitterTask task; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 String get generateAccessorHolder | 152 String get generateAccessorHolder |
| 153 => '$isolatePropertiesName.\$generateAccessor'; | 153 => '$isolatePropertiesName.\$generateAccessor'; |
| 154 String get finishClassesProperty | 154 String get finishClassesProperty |
| 155 => r'$finishClasses'; | 155 => r'$finishClasses'; |
| 156 String get finishClassesName | 156 String get finishClassesName |
| 157 => '${namer.isolateName}.$finishClassesProperty'; | 157 => '${namer.isolateName}.$finishClassesProperty'; |
| 158 String get finishIsolateConstructorName | 158 String get finishIsolateConstructorName |
| 159 => '${namer.isolateName}.\$finishIsolateConstructor'; | 159 => '${namer.isolateName}.\$finishIsolateConstructor'; |
| 160 String get isolatePropertiesName | 160 String get isolatePropertiesName |
| 161 => '${namer.isolateName}.${namer.isolatePropertiesName}'; | 161 => '${namer.isolateName}.${namer.isolatePropertiesName}'; |
| 162 String get lazyInitializerProperty |
| 163 => r'$lazy'; |
| 162 String get lazyInitializerName | 164 String get lazyInitializerName |
| 163 => '${namer.isolateName}.\$lazy'; | 165 => '${namer.isolateName}.${lazyInitializerProperty}'; |
| 164 String get initName => 'init'; | 166 String get initName => 'init'; |
| 165 String get makeConstListProperty | 167 String get makeConstListProperty |
| 166 => namer.getMappedInstanceName('makeConstantList'); | 168 => namer.getMappedInstanceName('makeConstantList'); |
| 167 | 169 |
| 168 /// The name of the property that contains all field names. | 170 /// The name of the property that contains all field names. |
| 169 /// | 171 /// |
| 170 /// This property is added to constructors when isolate support is enabled. | 172 /// This property is added to constructors when isolate support is enabled. |
| 171 static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__"; | 173 static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__"; |
| 172 | 174 |
| 173 /// For deferred loading we communicate the initializers via this global var. | 175 /// For deferred loading we communicate the initializers via this global var. |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 'leafTagsAccess': leafTagsAccess, | 683 'leafTagsAccess': leafTagsAccess, |
| 682 'allowNativesSubclassing': true}); | 684 'allowNativesSubclassing': true}); |
| 683 } | 685 } |
| 684 | 686 |
| 685 jsAst.Fun get finishIsolateConstructorFunction { | 687 jsAst.Fun get finishIsolateConstructorFunction { |
| 686 // We replace the old Isolate function with a new one that initializes | 688 // We replace the old Isolate function with a new one that initializes |
| 687 // all its fields with the initial (and often final) value of all globals. | 689 // all its fields with the initial (and often final) value of all globals. |
| 688 // | 690 // |
| 689 // We also copy over old values like the prototype, and the | 691 // We also copy over old values like the prototype, and the |
| 690 // isolateProperties themselves. | 692 // isolateProperties themselves. |
| 691 return js(''' | 693 return js( |
| 694 """ |
| 692 function (oldIsolate) { | 695 function (oldIsolate) { |
| 693 var isolateProperties = oldIsolate.#; // isolatePropertiesName | 696 var isolateProperties = oldIsolate.#isolatePropertiesName; |
| 694 function Isolate() { | 697 function Isolate() { |
| 695 var hasOwnProperty = Object.prototype.hasOwnProperty; | 698 var hasOwnProperty = Object.prototype.hasOwnProperty; |
| 696 for (var staticName in isolateProperties) | 699 for (var staticName in isolateProperties) |
| 697 if (hasOwnProperty.call(isolateProperties, staticName)) | 700 if (hasOwnProperty.call(isolateProperties, staticName)) |
| 698 this[staticName] = isolateProperties[staticName]; | 701 this[staticName] = isolateProperties[staticName]; |
| 699 | 702 |
| 700 // Reset lazy initializers to null. | 703 // Reset lazy initializers to null. |
| 701 // When forcing the object to fast mode (below) v8 will consider | 704 // When forcing the object to fast mode (below) v8 will consider |
| 702 // functions as part the object's map. Since we will change them | 705 // functions as part the object's map. Since we will change them |
| 703 // (after the first call to the getter), we would have a map | 706 // (after the first call to the getter), we would have a map |
| (...skipping 11 matching lines...) Expand all Loading... |
| 715 new ForceEfficientMap(); | 718 new ForceEfficientMap(); |
| 716 | 719 |
| 717 // Now, after being a fast map we can set the lazies again. | 720 // Now, after being a fast map we can set the lazies again. |
| 718 for (var lazyInit in lazies) { | 721 for (var lazyInit in lazies) { |
| 719 var lazyInitName = lazies[lazyInit]; | 722 var lazyInitName = lazies[lazyInit]; |
| 720 this[lazyInitName] = isolateProperties[lazyInitName]; | 723 this[lazyInitName] = isolateProperties[lazyInitName]; |
| 721 } | 724 } |
| 722 } | 725 } |
| 723 Isolate.prototype = oldIsolate.prototype; | 726 Isolate.prototype = oldIsolate.prototype; |
| 724 Isolate.prototype.constructor = Isolate; | 727 Isolate.prototype.constructor = Isolate; |
| 725 Isolate.# = isolateProperties; // isolatePropertiesName | 728 Isolate.#isolatePropertiesName = isolateProperties; |
| 726 if (#) // needsDefineClass. | 729 if (#needsDefineClass) |
| 727 Isolate.# = oldIsolate.#; // finishClassesProperty * 2 | 730 Isolate.#finishClassesProperty = oldIsolate.#finishClassesProperty; |
| 728 if (#) // outputContainsConstantList | 731 if (#outputContainsConstantList) |
| 729 Isolate.# = oldIsolate.#; // makeConstListProperty * 2 | 732 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty; |
| 730 return Isolate; | 733 if (#hasIncrementalSupport) |
| 731 }''', | 734 Isolate.#lazyInitializerProperty = |
| 732 [namer.isolatePropertiesName, namer.isolatePropertiesName, | 735 oldIsolate.#lazyInitializerProperty; |
| 733 needsDefineClass, finishClassesProperty, finishClassesProperty, | 736 return Isolate; |
| 734 task.outputContainsConstantList, | 737 } |
| 735 makeConstListProperty, makeConstListProperty ]); | 738 """, |
| 739 { 'isolatePropertiesName': namer.isolatePropertiesName, |
| 740 'needsDefineClass': needsDefineClass, |
| 741 'finishClassesProperty': finishClassesProperty, |
| 742 'outputContainsConstantList': task.outputContainsConstantList, |
| 743 'makeConstListProperty': makeConstListProperty, |
| 744 'hasIncrementalSupport': compiler.hasIncrementalSupport, |
| 745 'lazyInitializerProperty': lazyInitializerProperty, |
| 746 }); |
| 736 } | 747 } |
| 737 | 748 |
| 738 jsAst.Fun get lazyInitializerFunction { | 749 jsAst.Fun get lazyInitializerFunction { |
| 739 String isolate = namer.currentIsolate; | 750 String isolate = namer.currentIsolate; |
| 740 jsAst.Expression cyclicThrow = | 751 jsAst.Expression cyclicThrow = |
| 741 staticFunctionAccess(backend.getCyclicThrowHelper()); | 752 staticFunctionAccess(backend.getCyclicThrowHelper()); |
| 742 jsAst.Expression laziesAccess = | 753 jsAst.Expression laziesAccess = |
| 743 generateEmbeddedGlobalAccess(embeddedNames.LAZIES); | 754 generateEmbeddedGlobalAccess(embeddedNames.LAZIES); |
| 744 | 755 |
| 745 return js(''' | 756 return js(''' |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1016 } | 1027 } |
| 1017 } | 1028 } |
| 1018 | 1029 |
| 1019 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { | 1030 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { |
| 1020 JavaScriptConstantCompiler handler = backend.constants; | 1031 JavaScriptConstantCompiler handler = backend.constants; |
| 1021 List<VariableElement> lazyFields = | 1032 List<VariableElement> lazyFields = |
| 1022 handler.getLazilyInitializedFieldsForEmission(); | 1033 handler.getLazilyInitializedFieldsForEmission(); |
| 1023 if (!lazyFields.isEmpty) { | 1034 if (!lazyFields.isEmpty) { |
| 1024 needsLazyInitializer = true; | 1035 needsLazyInitializer = true; |
| 1025 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { | 1036 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { |
| 1026 jsAst.Expression code = backend.generatedCode[element]; | 1037 jsAst.Expression init = |
| 1027 // The code is null if we ended up not needing the lazily | 1038 buildLazilyInitializedStaticField(element, isolateProperties); |
| 1028 // initialized field after all because of constant folding | 1039 if (init == null) continue; |
| 1029 // before code generation. | 1040 buffer.write( |
| 1030 if (code == null) continue; | 1041 jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask)); |
| 1031 // The code only computes the initial value. We build the lazy-check | |
| 1032 // here: | |
| 1033 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); | |
| 1034 // The name is used for error reporting. The 'initial' must be a | |
| 1035 // closure that constructs the initial value. | |
| 1036 jsAst.Expression init = js('#(#,#,#,#,#)', | |
| 1037 [js(lazyInitializerName), | |
| 1038 js(isolateProperties), | |
| 1039 js.string(element.name), | |
| 1040 js.string(namer.getNameX(element)), | |
| 1041 js.string(namer.getLazyInitializerName(element)), | |
| 1042 code]); | |
| 1043 buffer.write(jsAst.prettyPrint(init, compiler, | |
| 1044 monitor: compiler.dumpInfoTask)); | |
| 1045 buffer.write("$N"); | 1042 buffer.write("$N"); |
| 1046 } | 1043 } |
| 1047 } | 1044 } |
| 1048 } | 1045 } |
| 1049 | 1046 |
| 1047 jsAst.Expression buildLazilyInitializedStaticField( |
| 1048 VariableElement element, String isolateProperties) { |
| 1049 jsAst.Expression code = backend.generatedCode[element]; |
| 1050 // The code is null if we ended up not needing the lazily |
| 1051 // initialized field after all because of constant folding |
| 1052 // before code generation. |
| 1053 if (code == null) return null; |
| 1054 // The code only computes the initial value. We build the lazy-check |
| 1055 // here: |
| 1056 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); |
| 1057 // The name is used for error reporting. The 'initial' must be a |
| 1058 // closure that constructs the initial value. |
| 1059 return js('#(#,#,#,#,#)', |
| 1060 [js(lazyInitializerName), |
| 1061 js(isolateProperties), |
| 1062 js.string(element.name), |
| 1063 js.string(namer.getNameX(element)), |
| 1064 js.string(namer.getLazyInitializerName(element)), |
| 1065 code]); |
| 1066 } |
| 1067 |
| 1050 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { | 1068 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { |
| 1051 if (constant.isFunction) return true; // Already emitted. | 1069 if (constant.isFunction) return true; // Already emitted. |
| 1052 if (constant.isPrimitive) return true; // Inlined. | 1070 if (constant.isPrimitive) return true; // Inlined. |
| 1053 if (constant.isDummy) return true; // Inlined. | 1071 if (constant.isDummy) return true; // Inlined. |
| 1054 // The name is null when the constant is already a JS constant. | 1072 // The name is null when the constant is already a JS constant. |
| 1055 // TODO(floitsch): every constant should be registered, so that we can | 1073 // TODO(floitsch): every constant should be registered, so that we can |
| 1056 // share the ones that take up too much space (like some strings). | 1074 // share the ones that take up too much space (like some strings). |
| 1057 if (namer.constantName(constant) == null) return true; | 1075 if (namer.constantName(constant) == null) return true; |
| 1058 return false; | 1076 return false; |
| 1059 } | 1077 } |
| (...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1591 .write('${globalsHolder}.${namer.isolateName}$_=$_' | 1609 .write('${globalsHolder}.${namer.isolateName}$_=$_' |
| 1592 '${namer.isolateName}$N' | 1610 '${namer.isolateName}$N' |
| 1593 '${globalsHolder}.$initName$_=${_}$initName$N'); | 1611 '${globalsHolder}.$initName$_=${_}$initName$N'); |
| 1594 } | 1612 } |
| 1595 mainBuffer.add('init()$N$n'); | 1613 mainBuffer.add('init()$N$n'); |
| 1596 mainBuffer.add('$isolateProperties$_=$_$isolatePropertiesName$N'); | 1614 mainBuffer.add('$isolateProperties$_=$_$isolatePropertiesName$N'); |
| 1597 | 1615 |
| 1598 emitStaticFunctions(task.outputStaticLists[mainOutputUnit]); | 1616 emitStaticFunctions(task.outputStaticLists[mainOutputUnit]); |
| 1599 | 1617 |
| 1600 // Only output the classesCollector if we actually have any classes. | 1618 // Only output the classesCollector if we actually have any classes. |
| 1601 if (!(nativeClasses.isEmpty && | 1619 if (needsDefineClass || |
| 1620 !(nativeClasses.isEmpty && |
| 1602 compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty && | 1621 compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty && |
| 1603 outputClassLists.values.every((classList) => classList.isEmpty) && | 1622 outputClassLists.values.every((classList) => classList.isEmpty) && |
| 1604 typedefsNeededForReflection.isEmpty)) { | 1623 typedefsNeededForReflection.isEmpty)) { |
| 1605 // Shorten the code by using "$$" as temporary. | 1624 // Shorten the code by using "$$" as temporary. |
| 1606 classesCollector = r"$$"; | 1625 classesCollector = r"$$"; |
| 1607 mainBuffer.add('var $classesCollector$_=${_}Object.create(null)$N$n'); | 1626 mainBuffer.add('var $classesCollector$_=${_}Object.create(null)$N$n'); |
| 1608 } | 1627 } |
| 1609 | 1628 |
| 1610 if (!nativeClasses.isEmpty) { | 1629 if (!nativeClasses.isEmpty) { |
| 1611 addComment('Native classes', mainBuffer); | 1630 addComment('Native classes', mainBuffer); |
| (...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2197 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 2216 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { |
| 2198 if (element.isInstanceMember) { | 2217 if (element.isInstanceMember) { |
| 2199 cachedClassBuilders.remove(element.enclosingClass); | 2218 cachedClassBuilders.remove(element.enclosingClass); |
| 2200 | 2219 |
| 2201 nativeEmitter.cachedBuilders.remove(element.enclosingClass); | 2220 nativeEmitter.cachedBuilders.remove(element.enclosingClass); |
| 2202 | 2221 |
| 2203 } | 2222 } |
| 2204 } | 2223 } |
| 2205 } | 2224 } |
| 2206 } | 2225 } |
| OLD | NEW |