| 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 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 : mainBuffer = new CodeBuffer(), | 128 : mainBuffer = new CodeBuffer(), |
| 129 this.namer = namer, | 129 this.namer = namer, |
| 130 boundClosureCache = new Map<int, String>(), | 130 boundClosureCache = new Map<int, String>(), |
| 131 interceptorClosureCache = new Map<int, String>(), | 131 interceptorClosureCache = new Map<int, String>(), |
| 132 constantEmitter = new ConstantEmitter(compiler, namer), | 132 constantEmitter = new ConstantEmitter(compiler, namer), |
| 133 super(compiler) { | 133 super(compiler) { |
| 134 nativeEmitter = new NativeEmitter(this); | 134 nativeEmitter = new NativeEmitter(this); |
| 135 } | 135 } |
| 136 | 136 |
| 137 void addComment(String comment, CodeBuffer buffer) { | 137 void addComment(String comment, CodeBuffer buffer) { |
| 138 buffer.add(jsAst.prettyPrint(js.comment(comment), compiler)); | 138 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); |
| 139 } | 139 } |
| 140 | 140 |
| 141 void computeRequiredTypeChecks() { | 141 void computeRequiredTypeChecks() { |
| 142 assert(checkedClasses == null && checkedTypedefs == null); | 142 assert(checkedClasses == null && checkedTypedefs == null); |
| 143 | 143 |
| 144 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); | 144 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); |
| 145 | 145 |
| 146 checkedClasses = new Set<ClassElement>(); | 146 checkedClasses = new Set<ClassElement>(); |
| 147 checkedTypedefs = new Set<TypedefElement>(); | 147 checkedTypedefs = new Set<TypedefElement>(); |
| 148 compiler.codegenWorld.isChecks.forEach((DartType t) { | 148 compiler.codegenWorld.isChecks.forEach((DartType t) { |
| (...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 | 611 |
| 612 List buildFinishIsolateConstructor() { | 612 List buildFinishIsolateConstructor() { |
| 613 return [ | 613 return [ |
| 614 // $finishIsolateConstructorName = $finishIsolateConstructorFunction | 614 // $finishIsolateConstructorName = $finishIsolateConstructorFunction |
| 615 js[finishIsolateConstructorName].assign(finishIsolateConstructorFunction) | 615 js[finishIsolateConstructorName].assign(finishIsolateConstructorFunction) |
| 616 ]; | 616 ]; |
| 617 } | 617 } |
| 618 | 618 |
| 619 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { | 619 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { |
| 620 String isolate = namer.isolateName; | 620 String isolate = namer.isolateName; |
| 621 buffer.add("$isolate = $finishIsolateConstructorName($isolate)$N"); | 621 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N"); |
| 622 } | 622 } |
| 623 | 623 |
| 624 /** | 624 /** |
| 625 * Generate stubs to handle invocation of methods with optional | 625 * Generate stubs to handle invocation of methods with optional |
| 626 * arguments. | 626 * arguments. |
| 627 * | 627 * |
| 628 * A method like [: foo([x]) :] may be invoked by the following | 628 * A method like [: foo([x]) :] may be invoked by the following |
| 629 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this | 629 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this |
| 630 * function for detailed examples. | 630 * function for detailed examples. |
| 631 */ | 631 */ |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1018 /** | 1018 /** |
| 1019 * Generates a holder object if it is needed. A holder is a JavaScript | 1019 * Generates a holder object if it is needed. A holder is a JavaScript |
| 1020 * object literal with a field [builtin$cls] that contains the name of the | 1020 * object literal with a field [builtin$cls] that contains the name of the |
| 1021 * class as a string (just like object constructors do). The is-checks for | 1021 * class as a string (just like object constructors do). The is-checks for |
| 1022 * the class are are added to the holder object later. | 1022 * the class are are added to the holder object later. |
| 1023 */ | 1023 */ |
| 1024 void maybeGenerateHolder(ClassElement cls) { | 1024 void maybeGenerateHolder(ClassElement cls) { |
| 1025 if (!needsHolder(cls)) return; | 1025 if (!needsHolder(cls)) return; |
| 1026 String holder = namer.isolateAccess(cls); | 1026 String holder = namer.isolateAccess(cls); |
| 1027 String name = namer.getName(cls); | 1027 String name = namer.getName(cls); |
| 1028 buffer.add('$holder$_=$_{builtin\$cls:$_"$name"'); | 1028 buffer.write('$holder$_=$_{builtin\$cls:$_"$name"'); |
| 1029 buffer.add('}$N'); | 1029 buffer.write('}$N'); |
| 1030 } | 1030 } |
| 1031 | 1031 |
| 1032 // Create representation objects for classes that we do not have a class | 1032 // Create representation objects for classes that we do not have a class |
| 1033 // definition for (because they are uninstantiated or native). | 1033 // definition for (because they are uninstantiated or native). |
| 1034 for (ClassElement cls in rti.allArguments) { | 1034 for (ClassElement cls in rti.allArguments) { |
| 1035 maybeGenerateHolder(cls); | 1035 maybeGenerateHolder(cls); |
| 1036 } | 1036 } |
| 1037 | 1037 |
| 1038 // Add checks to the constructors of instantiated classes or to the created | 1038 // Add checks to the constructors of instantiated classes or to the created |
| 1039 // holder object. | 1039 // holder object. |
| 1040 for (ClassElement cls in typeChecks) { | 1040 for (ClassElement cls in typeChecks) { |
| 1041 String holder = namer.isolateAccess(cls); | 1041 String holder = namer.isolateAccess(cls); |
| 1042 for (ClassElement check in typeChecks[cls]) { | 1042 for (ClassElement check in typeChecks[cls]) { |
| 1043 buffer.add('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 1043 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
| 1044 String body = rti.getSupertypeSubstitution(cls, check); | 1044 String body = rti.getSupertypeSubstitution(cls, check); |
| 1045 if (body != null) { | 1045 if (body != null) { |
| 1046 buffer.add('$holder.${namer.substitutionName(check)}$_=${_}$body$N'); | 1046 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N')
; |
| 1047 } | 1047 } |
| 1048 }; | 1048 }; |
| 1049 } | 1049 } |
| 1050 } | 1050 } |
| 1051 | 1051 |
| 1052 void visitNativeMixins(ClassElement classElement, | 1052 void visitNativeMixins(ClassElement classElement, |
| 1053 void visit(MixinApplicationElement mixinApplication)) { | 1053 void visit(MixinApplicationElement mixinApplication)) { |
| 1054 if (!classElement.isNative()) return; | 1054 if (!classElement.isNative()) return; |
| 1055 // Use recursion to make sure to visit the superclasses before the | 1055 // Use recursion to make sure to visit the superclasses before the |
| 1056 // subclasses. Once we start keeping track of the emitted fields | 1056 // subclasses. Once we start keeping track of the emitted fields |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1346 | 1346 |
| 1347 emitClassConstructor(classElement, builder); | 1347 emitClassConstructor(classElement, builder); |
| 1348 emitSuper(superName, builder); | 1348 emitSuper(superName, builder); |
| 1349 emitClassFields(classElement, builder, | 1349 emitClassFields(classElement, builder, |
| 1350 superClass: superName, classIsNative: false); | 1350 superClass: superName, classIsNative: false); |
| 1351 emitClassGettersSetters(classElement, builder); | 1351 emitClassGettersSetters(classElement, builder); |
| 1352 emitInstanceMembers(classElement, builder); | 1352 emitInstanceMembers(classElement, builder); |
| 1353 | 1353 |
| 1354 jsAst.Expression init = | 1354 jsAst.Expression init = |
| 1355 js[classesCollector][className].assign(builder.toObjectInitializer()); | 1355 js[classesCollector][className].assign(builder.toObjectInitializer()); |
| 1356 buffer.add(jsAst.prettyPrint(init, compiler)); | 1356 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 1357 buffer.add('$N$n'); | 1357 buffer.write('$N$n'); |
| 1358 } | 1358 } |
| 1359 | 1359 |
| 1360 bool get getterAndSetterCanBeImplementedByFieldSpec => true; | 1360 bool get getterAndSetterCanBeImplementedByFieldSpec => true; |
| 1361 | 1361 |
| 1362 int _selectorRank(Selector selector) { | 1362 int _selectorRank(Selector selector) { |
| 1363 int arity = selector.argumentCount * 3; | 1363 int arity = selector.argumentCount * 3; |
| 1364 if (selector.isGetter()) return arity + 2; | 1364 if (selector.isGetter()) return arity + 2; |
| 1365 if (selector.isSetter()) return arity + 1; | 1365 if (selector.isSetter()) return arity + 1; |
| 1366 return arity; | 1366 return arity; |
| 1367 } | 1367 } |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1551 // The closure class could have become necessary because of the generation | 1551 // The closure class could have become necessary because of the generation |
| 1552 // of stubs. | 1552 // of stubs. |
| 1553 ClassElement closureClass = compiler.closureClass; | 1553 ClassElement closureClass = compiler.closureClass; |
| 1554 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { | 1554 if (needsClosureClass && !instantiatedClasses.contains(closureClass)) { |
| 1555 generateClass(closureClass, bufferForElement(closureClass, buffer)); | 1555 generateClass(closureClass, bufferForElement(closureClass, buffer)); |
| 1556 } | 1556 } |
| 1557 } | 1557 } |
| 1558 | 1558 |
| 1559 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { | 1559 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
| 1560 if (needsDefineClass) { | 1560 if (needsDefineClass) { |
| 1561 buffer.add('$finishClassesName($classesCollector,' | 1561 buffer.write('$finishClassesName($classesCollector,' |
| 1562 '$_$isolateProperties,' | 1562 '$_$isolateProperties,' |
| 1563 '${_}null)$N'); | 1563 '${_}null)$N'); |
| 1564 | 1564 |
| 1565 // Reset the map. | 1565 // Reset the map. |
| 1566 buffer.add("$classesCollector$_=${_}null$N$n"); | 1566 buffer.write("$classesCollector$_=${_}null$N$n"); |
| 1567 } | 1567 } |
| 1568 } | 1568 } |
| 1569 | 1569 |
| 1570 void emitStaticFunction(CodeBuffer buffer, | 1570 void emitStaticFunction(CodeBuffer buffer, |
| 1571 String name, | 1571 String name, |
| 1572 jsAst.Expression functionExpression) { | 1572 jsAst.Expression functionExpression) { |
| 1573 jsAst.Expression assignment = | 1573 jsAst.Expression assignment = |
| 1574 js[isolateProperties][name].assign(functionExpression); | 1574 js[isolateProperties][name].assign(functionExpression); |
| 1575 buffer.add(jsAst.prettyPrint(assignment, compiler)); | 1575 buffer.write(jsAst.prettyPrint(assignment, compiler)); |
| 1576 buffer.add('$N$n'); | 1576 buffer.write('$N$n'); |
| 1577 } | 1577 } |
| 1578 | 1578 |
| 1579 void emitStaticFunctions(CodeBuffer eagerBuffer) { | 1579 void emitStaticFunctions(CodeBuffer eagerBuffer) { |
| 1580 bool isStaticFunction(Element element) => | 1580 bool isStaticFunction(Element element) => |
| 1581 !element.isInstanceMember() && !element.isField(); | 1581 !element.isInstanceMember() && !element.isField(); |
| 1582 | 1582 |
| 1583 Iterable<Element> elements = | 1583 Iterable<Element> elements = |
| 1584 backend.generatedCode.keys.where(isStaticFunction); | 1584 backend.generatedCode.keys.where(isStaticFunction); |
| 1585 Set<Element> pendingElementsWithBailouts = | 1585 Set<Element> pendingElementsWithBailouts = |
| 1586 backend.generatedBailoutCode.keys | 1586 backend.generatedBailoutCode.keys |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1617 // The static function does not have the correct name. Since | 1617 // The static function does not have the correct name. Since |
| 1618 // [addParameterStubs] use the name to create its stubs we simply | 1618 // [addParameterStubs] use the name to create its stubs we simply |
| 1619 // create a fake element with the correct name. | 1619 // create a fake element with the correct name. |
| 1620 // Note: the callElement will not have any enclosingElement. | 1620 // Note: the callElement will not have any enclosingElement. |
| 1621 FunctionElement callElement = | 1621 FunctionElement callElement = |
| 1622 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1622 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
| 1623 element); | 1623 element); |
| 1624 String staticName = namer.getName(element); | 1624 String staticName = namer.getName(element); |
| 1625 String invocationName = namer.instanceMethodName(callElement); | 1625 String invocationName = namer.instanceMethodName(callElement); |
| 1626 String fieldAccess = '$isolateProperties.$staticName'; | 1626 String fieldAccess = '$isolateProperties.$staticName'; |
| 1627 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); | 1627 buffer.write("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); |
| 1628 | 1628 |
| 1629 addParameterStubs(callElement, (String name, jsAst.Expression value) { | 1629 addParameterStubs(callElement, (String name, jsAst.Expression value) { |
| 1630 jsAst.Expression assignment = | 1630 jsAst.Expression assignment = |
| 1631 js[isolateProperties][staticName][name].assign(value); | 1631 js[isolateProperties][staticName][name].assign(value); |
| 1632 buffer.add( | 1632 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); |
| 1633 jsAst.prettyPrint(assignment.toStatement(), compiler)); | 1633 buffer.write('$N'); |
| 1634 buffer.add('$N'); | |
| 1635 }); | 1634 }); |
| 1636 | 1635 |
| 1637 // If a static function is used as a closure we need to add its name | 1636 // If a static function is used as a closure we need to add its name |
| 1638 // in case it is used in spawnFunction. | 1637 // in case it is used in spawnFunction. |
| 1639 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1638 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| 1640 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); | 1639 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); |
| 1641 getTypedefChecksOn(element.computeType(compiler)).forEach( | 1640 getTypedefChecksOn(element.computeType(compiler)).forEach( |
| 1642 (Element typedef) { | 1641 (Element typedef) { |
| 1643 String operator = namer.operatorIs(typedef); | 1642 String operator = namer.operatorIs(typedef); |
| 1644 buffer.add('$fieldAccess.$operator$_=${_}true$N'); | 1643 buffer.write('$fieldAccess.$operator$_=${_}true$N'); |
| 1645 } | 1644 } |
| 1646 ); | 1645 ); |
| 1647 } | 1646 } |
| 1648 } | 1647 } |
| 1649 | 1648 |
| 1650 void emitBoundClosureClassHeader(String mangledName, | 1649 void emitBoundClosureClassHeader(String mangledName, |
| 1651 String superName, | 1650 String superName, |
| 1652 List<String> fieldNames, | 1651 List<String> fieldNames, |
| 1653 ClassBuilder builder) { | 1652 ClassBuilder builder) { |
| 1654 builder.addProperty('', | 1653 builder.addProperty('', |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1874 Iterable<VariableElement> staticNonFinalFields = | 1873 Iterable<VariableElement> staticNonFinalFields = |
| 1875 handler.getStaticNonFinalFieldsForEmission(); | 1874 handler.getStaticNonFinalFieldsForEmission(); |
| 1876 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { | 1875 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { |
| 1877 // [:interceptedNames:] is handled in [emitInterceptedNames]. | 1876 // [:interceptedNames:] is handled in [emitInterceptedNames]. |
| 1878 if (element == backend.interceptedNames) continue; | 1877 if (element == backend.interceptedNames) continue; |
| 1879 compiler.withCurrentElement(element, () { | 1878 compiler.withCurrentElement(element, () { |
| 1880 Constant initialValue = handler.getInitialValueFor(element); | 1879 Constant initialValue = handler.getInitialValueFor(element); |
| 1881 jsAst.Expression init = | 1880 jsAst.Expression init = |
| 1882 js[isolateProperties][namer.getName(element)].assign( | 1881 js[isolateProperties][namer.getName(element)].assign( |
| 1883 constantEmitter.referenceInInitializationContext(initialValue)); | 1882 constantEmitter.referenceInInitializationContext(initialValue)); |
| 1884 buffer.add(jsAst.prettyPrint(init, compiler)); | 1883 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 1885 buffer.add('$N'); | 1884 buffer.write('$N'); |
| 1886 }); | 1885 }); |
| 1887 } | 1886 } |
| 1888 } | 1887 } |
| 1889 | 1888 |
| 1890 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { | 1889 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { |
| 1891 ConstantHandler handler = compiler.constantHandler; | 1890 ConstantHandler handler = compiler.constantHandler; |
| 1892 List<VariableElement> lazyFields = | 1891 List<VariableElement> lazyFields = |
| 1893 handler.getLazilyInitializedFieldsForEmission(); | 1892 handler.getLazilyInitializedFieldsForEmission(); |
| 1894 if (!lazyFields.isEmpty) { | 1893 if (!lazyFields.isEmpty) { |
| 1895 needsLazyInitializer = true; | 1894 needsLazyInitializer = true; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1906 arguments.add(js[isolateProperties]); | 1905 arguments.add(js[isolateProperties]); |
| 1907 arguments.add(js.string(element.name.slowToString())); | 1906 arguments.add(js.string(element.name.slowToString())); |
| 1908 arguments.add(js.string(namer.getName(element))); | 1907 arguments.add(js.string(namer.getName(element))); |
| 1909 arguments.add(js.string(namer.getLazyInitializerName(element))); | 1908 arguments.add(js.string(namer.getLazyInitializerName(element))); |
| 1910 arguments.add(code); | 1909 arguments.add(code); |
| 1911 jsAst.Expression getter = buildLazyInitializedGetter(element); | 1910 jsAst.Expression getter = buildLazyInitializedGetter(element); |
| 1912 if (getter != null) { | 1911 if (getter != null) { |
| 1913 arguments.add(getter); | 1912 arguments.add(getter); |
| 1914 } | 1913 } |
| 1915 jsAst.Expression init = js[lazyInitializerName](arguments); | 1914 jsAst.Expression init = js[lazyInitializerName](arguments); |
| 1916 buffer.add(jsAst.prettyPrint(init, compiler)); | 1915 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 1917 buffer.add("$N"); | 1916 buffer.write("$N"); |
| 1918 } | 1917 } |
| 1919 } | 1918 } |
| 1920 } | 1919 } |
| 1921 | 1920 |
| 1922 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { | 1921 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { |
| 1923 // Nothing to do, the 'lazy' function will create the getter. | 1922 // Nothing to do, the 'lazy' function will create the getter. |
| 1924 return null; | 1923 return null; |
| 1925 } | 1924 } |
| 1926 | 1925 |
| 1927 void emitCompileTimeConstants(CodeBuffer eagerBuffer) { | 1926 void emitCompileTimeConstants(CodeBuffer eagerBuffer) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1940 // share the ones that take up too much space (like some strings). | 1939 // share the ones that take up too much space (like some strings). |
| 1941 if (name == null) continue; | 1940 if (name == null) continue; |
| 1942 if (!addedMakeConstantList && constant.isList()) { | 1941 if (!addedMakeConstantList && constant.isList()) { |
| 1943 addedMakeConstantList = true; | 1942 addedMakeConstantList = true; |
| 1944 emitMakeConstantList(eagerBuffer); | 1943 emitMakeConstantList(eagerBuffer); |
| 1945 } | 1944 } |
| 1946 CodeBuffer buffer = | 1945 CodeBuffer buffer = |
| 1947 bufferForElement(constant.computeType(compiler).element, eagerBuffer); | 1946 bufferForElement(constant.computeType(compiler).element, eagerBuffer); |
| 1948 jsAst.Expression init = js[isolateProperties][name].assign( | 1947 jsAst.Expression init = js[isolateProperties][name].assign( |
| 1949 constantInitializerExpression(constant)); | 1948 constantInitializerExpression(constant)); |
| 1950 buffer.add(jsAst.prettyPrint(init, compiler)); | 1949 buffer.write(jsAst.prettyPrint(init, compiler)); |
| 1951 buffer.add('$N'); | 1950 buffer.write('$N'); |
| 1952 } | 1951 } |
| 1953 } | 1952 } |
| 1954 | 1953 |
| 1955 void emitMakeConstantList(CodeBuffer buffer) { | 1954 void emitMakeConstantList(CodeBuffer buffer) { |
| 1956 buffer.add(namer.isolateName); | 1955 buffer.write(namer.isolateName); |
| 1957 buffer.add(r'''.makeConstantList = function(list) { | 1956 buffer.write(r'''.makeConstantList = function(list) { |
| 1958 list.immutable$list = true; | 1957 list.immutable$list = true; |
| 1959 list.fixed$length = true; | 1958 list.fixed$length = true; |
| 1960 return list; | 1959 return list; |
| 1961 }; | 1960 }; |
| 1962 '''); | 1961 '''); |
| 1963 } | 1962 } |
| 1964 | 1963 |
| 1965 /** | 1964 /** |
| 1966 * Documentation wanted -- johnniwinther | 1965 * Documentation wanted -- johnniwinther |
| 1967 * | 1966 * |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2122 String buildIsolateSetup(CodeBuffer buffer, | 2121 String buildIsolateSetup(CodeBuffer buffer, |
| 2123 Element appMain, | 2122 Element appMain, |
| 2124 Element isolateMain) { | 2123 Element isolateMain) { |
| 2125 String mainAccess = "${namer.isolateAccess(appMain)}"; | 2124 String mainAccess = "${namer.isolateAccess(appMain)}"; |
| 2126 String currentIsolate = "${namer.CURRENT_ISOLATE}"; | 2125 String currentIsolate = "${namer.CURRENT_ISOLATE}"; |
| 2127 // Since we pass the closurized version of the main method to | 2126 // Since we pass the closurized version of the main method to |
| 2128 // the isolate method, we must make sure that it exists. | 2127 // the isolate method, we must make sure that it exists. |
| 2129 if (!compiler.codegenWorld.staticFunctionsNeedingGetter.contains(appMain)) { | 2128 if (!compiler.codegenWorld.staticFunctionsNeedingGetter.contains(appMain)) { |
| 2130 Selector selector = new Selector.callClosure(0); | 2129 Selector selector = new Selector.callClosure(0); |
| 2131 String invocationName = namer.invocationName(selector); | 2130 String invocationName = namer.invocationName(selector); |
| 2132 buffer.add("$mainAccess.$invocationName = $mainAccess$N"); | 2131 buffer.write("$mainAccess.$invocationName = $mainAccess$N"); |
| 2133 } | 2132 } |
| 2134 return "${namer.isolateAccess(isolateMain)}($mainAccess)"; | 2133 return "${namer.isolateAccess(isolateMain)}($mainAccess)"; |
| 2135 } | 2134 } |
| 2136 | 2135 |
| 2137 emitMain(CodeBuffer buffer) { | 2136 emitMain(CodeBuffer buffer) { |
| 2138 if (compiler.isMockCompilation) return; | 2137 if (compiler.isMockCompilation) return; |
| 2139 Element main = compiler.mainApp.find(Compiler.MAIN); | 2138 Element main = compiler.mainApp.find(Compiler.MAIN); |
| 2140 String mainCall = null; | 2139 String mainCall = null; |
| 2141 if (compiler.hasIsolateSupport()) { | 2140 if (compiler.hasIsolateSupport()) { |
| 2142 Element isolateMain = | 2141 Element isolateMain = |
| 2143 compiler.isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE); | 2142 compiler.isolateHelperLibrary.find(Compiler.START_ROOT_ISOLATE); |
| 2144 mainCall = buildIsolateSetup(buffer, main, isolateMain); | 2143 mainCall = buildIsolateSetup(buffer, main, isolateMain); |
| 2145 } else { | 2144 } else { |
| 2146 mainCall = '${namer.isolateAccess(main)}()'; | 2145 mainCall = '${namer.isolateAccess(main)}()'; |
| 2147 } | 2146 } |
| 2148 addComment('BEGIN invoke [main].', buffer); | 2147 addComment('BEGIN invoke [main].', buffer); |
| 2149 buffer.add(""" | 2148 buffer.write(""" |
| 2150 if (typeof document !== "undefined" && document.readyState !== "complete") { | 2149 if (typeof document !== "undefined" && document.readyState !== "complete") { |
| 2151 document.addEventListener("readystatechange", function () { | 2150 document.addEventListener("readystatechange", function () { |
| 2152 if (document.readyState == "complete") { | 2151 if (document.readyState == "complete") { |
| 2153 if (typeof dartMainRunner === "function") { | 2152 if (typeof dartMainRunner === "function") { |
| 2154 dartMainRunner(function() { ${mainCall}; }); | 2153 dartMainRunner(function() { ${mainCall}; }); |
| 2155 } else { | 2154 } else { |
| 2156 ${mainCall}; | 2155 ${mainCall}; |
| 2157 } | 2156 } |
| 2158 } | 2157 } |
| 2159 }, false); | 2158 }, false); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2272 if (hasBool) { | 2271 if (hasBool) { |
| 2273 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); | 2272 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); |
| 2274 } | 2273 } |
| 2275 // TODO(ahe): It might be faster to check for Array before | 2274 // TODO(ahe): It might be faster to check for Array before |
| 2276 // function and bool. | 2275 // function and bool. |
| 2277 if (hasArray) { | 2276 if (hasArray) { |
| 2278 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); | 2277 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); |
| 2279 } | 2278 } |
| 2280 block.statements.add(js.return_(receiver)); | 2279 block.statements.add(js.return_(receiver)); |
| 2281 | 2280 |
| 2282 buffer.add(jsAst.prettyPrint( | 2281 buffer.write(jsAst.prettyPrint( |
| 2283 js[isolateProperties][key].assign(js.fun(['receiver'], block)), | 2282 js[isolateProperties][key].assign(js.fun(['receiver'], block)), |
| 2284 compiler)); | 2283 compiler)); |
| 2285 buffer.add(N); | 2284 buffer.write(N); |
| 2286 } | 2285 } |
| 2287 | 2286 |
| 2288 /** | 2287 /** |
| 2289 * Emit all versions of the [:getInterceptor:] method. | 2288 * Emit all versions of the [:getInterceptor:] method. |
| 2290 */ | 2289 */ |
| 2291 void emitGetInterceptorMethods(CodeBuffer buffer) { | 2290 void emitGetInterceptorMethods(CodeBuffer buffer) { |
| 2292 var specializedGetInterceptors = backend.specializedGetInterceptors; | 2291 var specializedGetInterceptors = backend.specializedGetInterceptors; |
| 2293 for (String name in specializedGetInterceptors.keys.toList()..sort()) { | 2292 for (String name in specializedGetInterceptors.keys.toList()..sort()) { |
| 2294 Collection<ClassElement> classes = specializedGetInterceptors[name]; | 2293 Collection<ClassElement> classes = specializedGetInterceptors[name]; |
| 2295 emitGetInterceptorMethod(buffer, name, classes); | 2294 emitGetInterceptorMethod(buffer, name, classes); |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2548 String invocationName = backend.namer.invocationName(selector); | 2547 String invocationName = backend.namer.invocationName(selector); |
| 2549 body.add(js.return_( | 2548 body.add(js.return_( |
| 2550 js[isolateProperties][getInterceptorName]('receiver')[invocationName]( | 2549 js[isolateProperties][getInterceptorName]('receiver')[invocationName]( |
| 2551 arguments))); | 2550 arguments))); |
| 2552 | 2551 |
| 2553 jsAst.Fun function = js.fun(parameters, body); | 2552 jsAst.Fun function = js.fun(parameters, body); |
| 2554 | 2553 |
| 2555 jsAst.PropertyAccess property = | 2554 jsAst.PropertyAccess property = |
| 2556 js[isolateProperties][name]; | 2555 js[isolateProperties][name]; |
| 2557 | 2556 |
| 2558 buffer.add(jsAst.prettyPrint(property.assign(function), compiler)); | 2557 buffer.write(jsAst.prettyPrint(property.assign(function), compiler)); |
| 2559 buffer.add(N); | 2558 buffer.write(N); |
| 2560 } | 2559 } |
| 2561 } | 2560 } |
| 2562 | 2561 |
| 2563 /** | 2562 /** |
| 2564 * If [:invokeOn:] has been compiled, emit all the possible selector names | 2563 * If [:invokeOn:] has been compiled, emit all the possible selector names |
| 2565 * that are intercepted into the [:interceptedNames:] top-level | 2564 * that are intercepted into the [:interceptedNames:] top-level |
| 2566 * variable. The implementation of [:invokeOn:] will use it to | 2565 * variable. The implementation of [:invokeOn:] will use it to |
| 2567 * determine whether it should call the method with an extra | 2566 * determine whether it should call the method with an extra |
| 2568 * parameter. | 2567 * parameter. |
| 2569 */ | 2568 */ |
| 2570 void emitInterceptedNames(CodeBuffer buffer) { | 2569 void emitInterceptedNames(CodeBuffer buffer) { |
| 2571 if (!compiler.enabledInvokeOn) return; | 2570 if (!compiler.enabledInvokeOn) return; |
| 2572 String name = backend.namer.getName(backend.interceptedNames); | 2571 String name = backend.namer.getName(backend.interceptedNames); |
| 2573 jsAst.PropertyAccess property = js[isolateProperties][name]; | 2572 jsAst.PropertyAccess property = js[isolateProperties][name]; |
| 2574 | 2573 |
| 2575 int index = 0; | 2574 int index = 0; |
| 2576 List<jsAst.ArrayElement> elements = backend.usedInterceptors.map( | 2575 List<jsAst.ArrayElement> elements = backend.usedInterceptors.map( |
| 2577 (Selector selector) { | 2576 (Selector selector) { |
| 2578 jsAst.Literal str = js.string(namer.invocationName(selector)); | 2577 jsAst.Literal str = js.string(namer.invocationName(selector)); |
| 2579 return new jsAst.ArrayElement(index++, str); | 2578 return new jsAst.ArrayElement(index++, str); |
| 2580 }).toList(); | 2579 }).toList(); |
| 2581 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer( | 2580 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer( |
| 2582 backend.usedInterceptors.length, | 2581 backend.usedInterceptors.length, |
| 2583 elements); | 2582 elements); |
| 2584 | 2583 |
| 2585 buffer.add(jsAst.prettyPrint(property.assign(array), compiler)); | 2584 buffer.write(jsAst.prettyPrint(property.assign(array), compiler)); |
| 2586 buffer.add(N); | 2585 buffer.write(N); |
| 2587 } | 2586 } |
| 2588 | 2587 |
| 2589 void emitInitFunction(CodeBuffer buffer) { | 2588 void emitInitFunction(CodeBuffer buffer) { |
| 2590 jsAst.Fun fun = js.fun([], [ | 2589 jsAst.Fun fun = js.fun([], [ |
| 2591 js['$isolateProperties = {}'], | 2590 js['$isolateProperties = {}'], |
| 2592 ] | 2591 ] |
| 2593 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) | 2592 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) |
| 2594 ..addAll(buildLazyInitializerFunctionIfNecessary()) | 2593 ..addAll(buildLazyInitializerFunctionIfNecessary()) |
| 2595 ..addAll(buildFinishIsolateConstructor()) | 2594 ..addAll(buildFinishIsolateConstructor()) |
| 2596 ); | 2595 ); |
| 2597 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( | 2596 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( |
| 2598 new jsAst.VariableDeclaration('init'), fun); | 2597 new jsAst.VariableDeclaration('init'), fun); |
| 2599 buffer.add(jsAst.prettyPrint(decl, compiler).getText()); | 2598 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); |
| 2600 } | 2599 } |
| 2601 | 2600 |
| 2602 String assembleProgram() { | 2601 String assembleProgram() { |
| 2603 measure(() { | 2602 measure(() { |
| 2604 computeNeededClasses(); | 2603 computeNeededClasses(); |
| 2605 | 2604 |
| 2606 // Compute the required type checks to know which classes need a | 2605 // Compute the required type checks to know which classes need a |
| 2607 // 'is$' method. | 2606 // 'is$' method. |
| 2608 computeRequiredTypeChecks(); | 2607 computeRequiredTypeChecks(); |
| 2609 | 2608 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2715 | 2714 |
| 2716 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { | 2715 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { |
| 2717 if (!isDeferred(element)) return eagerBuffer; | 2716 if (!isDeferred(element)) return eagerBuffer; |
| 2718 emitDeferredPreambleWhenEmpty(deferredBuffer); | 2717 emitDeferredPreambleWhenEmpty(deferredBuffer); |
| 2719 return deferredBuffer; | 2718 return deferredBuffer; |
| 2720 } | 2719 } |
| 2721 | 2720 |
| 2722 void emitDeferredCode(CodeBuffer buffer) { | 2721 void emitDeferredCode(CodeBuffer buffer) { |
| 2723 if (buffer.isEmpty) return; | 2722 if (buffer.isEmpty) return; |
| 2724 | 2723 |
| 2725 buffer.add(n); | 2724 buffer.write(n); |
| 2726 | 2725 |
| 2727 buffer.add('${namer.CURRENT_ISOLATE}$_=${_}old${namer.CURRENT_ISOLATE}$N'); | 2726 buffer.write( |
| 2727 '${namer.CURRENT_ISOLATE}$_=${_}old${namer.CURRENT_ISOLATE}$N'); |
| 2728 | 2728 |
| 2729 String code = buffer.getText(); | 2729 String code = buffer.getText(); |
| 2730 compiler.outputProvider('part', 'js') | 2730 compiler.outputProvider('part', 'js') |
| 2731 ..add(code) | 2731 ..add(code) |
| 2732 ..close(); | 2732 ..close(); |
| 2733 outputSourceMap(buffer, compiler.assembledCode, 'part'); | 2733 outputSourceMap(buffer, compiler.assembledCode, 'part'); |
| 2734 } | 2734 } |
| 2735 | 2735 |
| 2736 void emitDeferredPreambleWhenEmpty(CodeBuffer buffer) { | 2736 void emitDeferredPreambleWhenEmpty(CodeBuffer buffer) { |
| 2737 if (!buffer.isEmpty) return; | 2737 if (!buffer.isEmpty) return; |
| 2738 | 2738 |
| 2739 buffer.add(GENERATED_BY); | 2739 buffer.write(GENERATED_BY); |
| 2740 | 2740 |
| 2741 buffer.add('var old${namer.CURRENT_ISOLATE}$_=' | 2741 buffer.write('var old${namer.CURRENT_ISOLATE}$_=' |
| 2742 '$_${namer.CURRENT_ISOLATE}$N'); | 2742 '$_${namer.CURRENT_ISOLATE}$N'); |
| 2743 | 2743 |
| 2744 // TODO(ahe): This defines a lot of properties on the | 2744 // TODO(ahe): This defines a lot of properties on the |
| 2745 // Isolate.prototype object. We know this will turn it into a | 2745 // Isolate.prototype object. We know this will turn it into a |
| 2746 // slow object in V8, so instead we should do something similar to | 2746 // slow object in V8, so instead we should do something similar to |
| 2747 // Isolate.$finishIsolateConstructor. | 2747 // Isolate.$finishIsolateConstructor. |
| 2748 buffer.add('${namer.CURRENT_ISOLATE}$_=' | 2748 buffer.write('${namer.CURRENT_ISOLATE}$_=' |
| 2749 '$_${namer.isolateName}.prototype$N$n'); | 2749 '$_${namer.isolateName}.prototype$N$n'); |
| 2750 } | 2750 } |
| 2751 | 2751 |
| 2752 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { | 2752 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { |
| 2753 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); | 2753 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); |
| 2754 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); | 2754 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); |
| 2755 return sourceMapBuilder.build(compiledFile); | 2755 return sourceMapBuilder.build(compiledFile); |
| 2756 } | 2756 } |
| 2757 | 2757 |
| 2758 void outputSourceMap(CodeBuffer buffer, String code, String name) { | 2758 void outputSourceMap(CodeBuffer buffer, String code, String name) { |
| 2759 if (!generateSourceMap) return; | 2759 if (!generateSourceMap) return; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2781 """; | 2781 """; |
| 2782 const String HOOKS_API_USAGE = """ | 2782 const String HOOKS_API_USAGE = """ |
| 2783 // The code supports the following hooks: | 2783 // The code supports the following hooks: |
| 2784 // dartPrint(message) - if this function is defined it is called | 2784 // dartPrint(message) - if this function is defined it is called |
| 2785 // instead of the Dart [print] method. | 2785 // instead of the Dart [print] method. |
| 2786 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2786 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2787 // method will not be invoked directly. | 2787 // method will not be invoked directly. |
| 2788 // Instead, a closure that will invoke [main] is | 2788 // Instead, a closure that will invoke [main] is |
| 2789 // passed to [dartMainRunner]. | 2789 // passed to [dartMainRunner]. |
| 2790 """; | 2790 """; |
| OLD | NEW |