| 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 CodeBuffer boundClosureBuffer; | 62 CodeBuffer boundClosureBuffer; |
| 63 CodeBuffer mainBuffer; | 63 CodeBuffer mainBuffer; |
| 64 /** Shorter access to [isolatePropertiesName]. Both here in the code, as | 64 /** Shorter access to [isolatePropertiesName]. Both here in the code, as |
| 65 well as in the generated code. */ | 65 well as in the generated code. */ |
| 66 String isolateProperties; | 66 String isolateProperties; |
| 67 String classesCollector; | 67 String classesCollector; |
| 68 Set<ClassElement> neededClasses; | 68 Set<ClassElement> neededClasses; |
| 69 // TODO(ngeoffray): remove this field. | 69 // TODO(ngeoffray): remove this field. |
| 70 Set<ClassElement> instantiatedClasses; | 70 Set<ClassElement> instantiatedClasses; |
| 71 | 71 |
| 72 JavaScriptBackend get backend => compiler.backend; |
| 73 |
| 72 String get _ => compiler.enableMinification ? "" : " "; | 74 String get _ => compiler.enableMinification ? "" : " "; |
| 73 String get n => compiler.enableMinification ? "" : "\n"; | 75 String get n => compiler.enableMinification ? "" : "\n"; |
| 74 String get N => compiler.enableMinification ? "\n" : ";\n"; | 76 String get N => compiler.enableMinification ? "\n" : ";\n"; |
| 75 | 77 |
| 76 /** | 78 /** |
| 77 * A cache of closures that are used to closurize instance methods. | 79 * A cache of closures that are used to closurize instance methods. |
| 78 * A closure is dynamically bound to the instance used when | 80 * A closure is dynamically bound to the instance used when |
| 79 * closurized. | 81 * closurized. |
| 80 */ | 82 */ |
| 81 final Map<int, String> boundClosureCache; | 83 final Map<int, String> boundClosureCache; |
| (...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 return js.fun(parameters, [ | 635 return js.fun(parameters, [ |
| 634 // var getter = new Function("{ return $isolate." + fieldName + ";}"); | 636 // var getter = new Function("{ return $isolate." + fieldName + ";}"); |
| 635 js['getter'].def(js['Function'].newWith([ | 637 js['getter'].def(js['Function'].newWith([ |
| 636 js.string("{ return $isolate.") + 'fieldName' + js.string('}')])) | 638 js.string("{ return $isolate.") + 'fieldName' + js.string('}')])) |
| 637 ]..addAll(addLazyInitializerLogic()) | 639 ]..addAll(addLazyInitializerLogic()) |
| 638 ); | 640 ); |
| 639 } | 641 } |
| 640 | 642 |
| 641 List addLazyInitializerLogic() { | 643 List addLazyInitializerLogic() { |
| 642 String isolate = namer.CURRENT_ISOLATE; | 644 String isolate = namer.CURRENT_ISOLATE; |
| 643 JavaScriptBackend backend = compiler.backend; | 645 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); |
| 644 String cyclicThrow = namer.isolateAccess(backend.cyclicThrowHelper); | |
| 645 | 646 |
| 646 return [ | 647 return [ |
| 647 // var sentinelUndefined = {}; | 648 // var sentinelUndefined = {}; |
| 648 js['sentinelUndefined'].def({}), | 649 js['sentinelUndefined'].def({}), |
| 649 | 650 |
| 650 // var sentinelInProgress = {}; | 651 // var sentinelInProgress = {}; |
| 651 js['sentinelInProgress'].def({}), | 652 js['sentinelInProgress'].def({}), |
| 652 | 653 |
| 653 // prototype[fieldName] = sentinelUndefined; | 654 // prototype[fieldName] = sentinelUndefined; |
| 654 js['prototype'][js['fieldName']].assign('sentinelUndefined'), | 655 js['prototype'][js['fieldName']].assign('sentinelUndefined'), |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 // hit the method directly. | 771 // hit the method directly. |
| 771 return; | 772 return; |
| 772 } | 773 } |
| 773 ConstantHandler handler = compiler.constantHandler; | 774 ConstantHandler handler = compiler.constantHandler; |
| 774 List<SourceString> names = selector.getOrderedNamedArguments(); | 775 List<SourceString> names = selector.getOrderedNamedArguments(); |
| 775 | 776 |
| 776 String invocationName = namer.invocationName(selector); | 777 String invocationName = namer.invocationName(selector); |
| 777 if (alreadyGenerated.contains(invocationName)) return; | 778 if (alreadyGenerated.contains(invocationName)) return; |
| 778 alreadyGenerated.add(invocationName); | 779 alreadyGenerated.add(invocationName); |
| 779 | 780 |
| 780 JavaScriptBackend backend = compiler.backend; | |
| 781 bool isInterceptorClass = | 781 bool isInterceptorClass = |
| 782 backend.isInterceptorClass(member.getEnclosingClass()); | 782 backend.isInterceptorClass(member.getEnclosingClass()); |
| 783 | 783 |
| 784 // If the method is in an interceptor class, we need to also pass | 784 // If the method is in an interceptor class, we need to also pass |
| 785 // the actual receiver. | 785 // the actual receiver. |
| 786 int extraArgumentCount = isInterceptorClass ? 1 : 0; | 786 int extraArgumentCount = isInterceptorClass ? 1 : 0; |
| 787 // Use '$receiver' to avoid clashes with other parameter names. Using | 787 // Use '$receiver' to avoid clashes with other parameter names. Using |
| 788 // '$receiver' works because [:namer.safeName:] used for getting parameter | 788 // '$receiver' works because [:namer.safeName:] used for getting parameter |
| 789 // names never returns a name beginning with a single '$'. | 789 // names never returns a name beginning with a single '$'. |
| 790 String receiverArgumentName = r'$receiver'; | 790 String receiverArgumentName = r'$receiver'; |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1005 */ | 1005 */ |
| 1006 void addInstanceMember(Element member, ClassBuilder builder) { | 1006 void addInstanceMember(Element member, ClassBuilder builder) { |
| 1007 assert(invariant(member, member.isDeclaration)); | 1007 assert(invariant(member, member.isDeclaration)); |
| 1008 // TODO(floitsch): we don't need to deal with members of | 1008 // TODO(floitsch): we don't need to deal with members of |
| 1009 // uninstantiated classes, that have been overwritten by subclasses. | 1009 // uninstantiated classes, that have been overwritten by subclasses. |
| 1010 | 1010 |
| 1011 if (member.isFunction() | 1011 if (member.isFunction() |
| 1012 || member.isGenerativeConstructorBody() | 1012 || member.isGenerativeConstructorBody() |
| 1013 || member.isAccessor()) { | 1013 || member.isAccessor()) { |
| 1014 if (member.isAbstract(compiler)) return; | 1014 if (member.isAbstract(compiler)) return; |
| 1015 JavaScriptBackend backend = compiler.backend; | |
| 1016 jsAst.Expression code = backend.generatedCode[member]; | 1015 jsAst.Expression code = backend.generatedCode[member]; |
| 1017 if (code == null) return; | 1016 if (code == null) return; |
| 1018 builder.addProperty(namer.getName(member), code); | 1017 builder.addProperty(namer.getName(member), code); |
| 1019 code = backend.generatedBailoutCode[member]; | 1018 code = backend.generatedBailoutCode[member]; |
| 1020 if (code != null) { | 1019 if (code != null) { |
| 1021 builder.addProperty(namer.getBailoutName(member), code); | 1020 builder.addProperty(namer.getBailoutName(member), code); |
| 1022 } | 1021 } |
| 1023 FunctionElement function = member; | 1022 FunctionElement function = member; |
| 1024 FunctionSignature parameters = function.computeSignature(compiler); | 1023 FunctionSignature parameters = function.computeSignature(compiler); |
| 1025 if (!parameters.optionalParameters.isEmpty) { | 1024 if (!parameters.optionalParameters.isEmpty) { |
| 1026 addParameterStubs(member, builder.addProperty); | 1025 addParameterStubs(member, builder.addProperty); |
| 1027 } | 1026 } |
| 1028 } else if (!member.isField()) { | 1027 } else if (!member.isField()) { |
| 1029 compiler.internalError('unexpected kind: "${member.kind}"', | 1028 compiler.internalError('unexpected kind: "${member.kind}"', |
| 1030 element: member); | 1029 element: member); |
| 1031 } | 1030 } |
| 1032 emitExtraAccessors(member, builder); | 1031 emitExtraAccessors(member, builder); |
| 1033 } | 1032 } |
| 1034 | 1033 |
| 1035 /** | 1034 /** |
| 1036 * Documentation wanted -- johnniwinther | 1035 * Documentation wanted -- johnniwinther |
| 1037 * | 1036 * |
| 1038 * Invariant: [classElement] must be a declaration element. | 1037 * Invariant: [classElement] must be a declaration element. |
| 1039 */ | 1038 */ |
| 1040 void emitInstanceMembers(ClassElement classElement, | 1039 void emitInstanceMembers(ClassElement classElement, |
| 1041 ClassBuilder builder) { | 1040 ClassBuilder builder) { |
| 1042 assert(invariant(classElement, classElement.isDeclaration)); | 1041 assert(invariant(classElement, classElement.isDeclaration)); |
| 1043 JavaScriptBackend backend = compiler.backend; | |
| 1044 if (classElement == backend.objectInterceptorClass) { | 1042 if (classElement == backend.objectInterceptorClass) { |
| 1045 emitInterceptorMethods(builder); | 1043 emitInterceptorMethods(builder); |
| 1046 // The ObjectInterceptor does not have any instance methods. | 1044 // The ObjectInterceptor does not have any instance methods. |
| 1047 return; | 1045 return; |
| 1048 } | 1046 } |
| 1049 | 1047 |
| 1050 void visitMember(ClassElement enclosing, Element member) { | 1048 void visitMember(ClassElement enclosing, Element member) { |
| 1051 assert(invariant(classElement, member.isDeclaration)); | 1049 assert(invariant(classElement, member.isDeclaration)); |
| 1052 if (member.isInstanceMember()) { | 1050 if (member.isInstanceMember()) { |
| 1053 addInstanceMember(member, builder); | 1051 addInstanceMember(member, builder); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 const SourceString('=='), 1); | 1129 const SourceString('=='), 1); |
| 1132 Function kind = (classElement == backend.jsNullClass) | 1130 Function kind = (classElement == backend.jsNullClass) |
| 1133 ? js.equals | 1131 ? js.equals |
| 1134 : js.strictEquals; | 1132 : js.strictEquals; |
| 1135 builder.addProperty(name, js.fun(['receiver', 'a'], | 1133 builder.addProperty(name, js.fun(['receiver', 'a'], |
| 1136 js.block(js.return_(kind(js['receiver'], js['a']))))); | 1134 js.block(js.return_(kind(js['receiver'], js['a']))))); |
| 1137 } | 1135 } |
| 1138 } | 1136 } |
| 1139 | 1137 |
| 1140 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 1138 void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
| 1141 JavaScriptBackend backend = compiler.backend; | |
| 1142 RuntimeTypeInformation rti = backend.rti; | 1139 RuntimeTypeInformation rti = backend.rti; |
| 1143 TypeChecks typeChecks = rti.getRequiredChecks(); | 1140 TypeChecks typeChecks = rti.getRequiredChecks(); |
| 1144 | 1141 |
| 1145 bool needsHolder(ClassElement cls) { | 1142 bool needsHolder(ClassElement cls) { |
| 1146 return !neededClasses.contains(cls) || cls.isNative() || | 1143 return !neededClasses.contains(cls) || cls.isNative() || |
| 1147 rti.isJsNative(cls); | 1144 rti.isJsNative(cls); |
| 1148 } | 1145 } |
| 1149 | 1146 |
| 1150 /** | 1147 /** |
| 1151 * Generates a holder object if it is needed. A holder is a JavaScript | 1148 * Generates a holder object if it is needed. A holder is a JavaScript |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 } | 1314 } |
| 1318 | 1315 |
| 1319 void generateCheckedSetter(Element member, | 1316 void generateCheckedSetter(Element member, |
| 1320 String fieldName, | 1317 String fieldName, |
| 1321 String accessorName, | 1318 String accessorName, |
| 1322 ClassBuilder builder) { | 1319 ClassBuilder builder) { |
| 1323 assert(canGenerateCheckedSetter(member)); | 1320 assert(canGenerateCheckedSetter(member)); |
| 1324 DartType type = member.computeType(compiler); | 1321 DartType type = member.computeType(compiler); |
| 1325 // TODO(ahe): Generate a dynamic type error here. | 1322 // TODO(ahe): Generate a dynamic type error here. |
| 1326 if (type.element.isErroneous()) return; | 1323 if (type.element.isErroneous()) return; |
| 1327 SourceString helper = compiler.backend.getCheckedModeHelper(type); | 1324 SourceString helper = backend.getCheckedModeHelper(type); |
| 1328 FunctionElement helperElement = compiler.findHelper(helper); | 1325 FunctionElement helperElement = compiler.findHelper(helper); |
| 1329 String helperName = namer.isolateAccess(helperElement); | 1326 String helperName = namer.isolateAccess(helperElement); |
| 1330 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; | 1327 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; |
| 1331 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 1328 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
| 1332 arguments.add(js.string(namer.operatorIs(type.element))); | 1329 arguments.add(js.string(namer.operatorIs(type.element))); |
| 1333 } | 1330 } |
| 1334 | 1331 |
| 1335 String setterName = namer.setterNameFromAccessorName(accessorName); | 1332 String setterName = namer.setterNameFromAccessorName(accessorName); |
| 1336 builder.addProperty(setterName, | 1333 builder.addProperty(setterName, |
| 1337 js.fun(['v'], js['this'][fieldName].assign(js[helperName](arguments)))); | 1334 js.fun(['v'], js['this'][fieldName].assign(js[helperName](arguments)))); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1482 } | 1479 } |
| 1483 | 1480 |
| 1484 int _compareSelectorNames(Selector selector1, Selector selector2) { | 1481 int _compareSelectorNames(Selector selector1, Selector selector2) { |
| 1485 String name1 = selector1.name.toString(); | 1482 String name1 = selector1.name.toString(); |
| 1486 String name2 = selector2.name.toString(); | 1483 String name2 = selector2.name.toString(); |
| 1487 if (name1 != name2) return Comparable.compare(name1, name2); | 1484 if (name1 != name2) return Comparable.compare(name1, name2); |
| 1488 return _selectorRank(selector1) - _selectorRank(selector2); | 1485 return _selectorRank(selector1) - _selectorRank(selector2); |
| 1489 } | 1486 } |
| 1490 | 1487 |
| 1491 void emitInterceptorMethods(ClassBuilder builder) { | 1488 void emitInterceptorMethods(ClassBuilder builder) { |
| 1492 JavaScriptBackend backend = compiler.backend; | |
| 1493 // Emit forwarders for the ObjectInterceptor class. We need to | 1489 // Emit forwarders for the ObjectInterceptor class. We need to |
| 1494 // emit all possible sends on intercepted methods. | 1490 // emit all possible sends on intercepted methods. |
| 1495 for (Selector selector in | 1491 for (Selector selector in |
| 1496 backend.usedInterceptors.toList()..sort(_compareSelectorNames)) { | 1492 backend.usedInterceptors.toList()..sort(_compareSelectorNames)) { |
| 1497 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; | 1493 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; |
| 1498 List<jsAst.Expression> arguments = <jsAst.Expression>[]; | 1494 List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
| 1499 parameters.add(new jsAst.Parameter('receiver')); | 1495 parameters.add(new jsAst.Parameter('receiver')); |
| 1500 | 1496 |
| 1501 String name = backend.namer.invocationName(selector); | 1497 String name = backend.namer.invocationName(selector); |
| 1502 if (selector.isSetter()) { | 1498 if (selector.isSetter()) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1533 * substitutions, because they may have changed. | 1529 * substitutions, because they may have changed. |
| 1534 */ | 1530 */ |
| 1535 void generateIsTestsOn(ClassElement cls, | 1531 void generateIsTestsOn(ClassElement cls, |
| 1536 void emitIsTest(Element element), | 1532 void emitIsTest(Element element), |
| 1537 void emitSubstitution(Element element, {emitNull})) { | 1533 void emitSubstitution(Element element, {emitNull})) { |
| 1538 if (checkedClasses.contains(cls)) { | 1534 if (checkedClasses.contains(cls)) { |
| 1539 emitIsTest(cls); | 1535 emitIsTest(cls); |
| 1540 emitSubstitution(cls); | 1536 emitSubstitution(cls); |
| 1541 } | 1537 } |
| 1542 | 1538 |
| 1543 JavaScriptBackend jsBackend = compiler.backend; | 1539 RuntimeTypeInformation rti = backend.rti; |
| 1544 RuntimeTypeInformation rti = jsBackend.rti; | |
| 1545 ClassElement superclass = cls.superclass; | 1540 ClassElement superclass = cls.superclass; |
| 1546 | 1541 |
| 1547 bool haveSameTypeVariables(ClassElement a, ClassElement b) { | 1542 bool haveSameTypeVariables(ClassElement a, ClassElement b) { |
| 1548 if (a.isClosure()) return true; | 1543 if (a.isClosure()) return true; |
| 1549 return a.typeVariables == b.typeVariables; | 1544 return a.typeVariables == b.typeVariables; |
| 1550 } | 1545 } |
| 1551 | 1546 |
| 1552 if (superclass != null && superclass != compiler.objectClass && | 1547 if (superclass != null && superclass != compiler.objectClass && |
| 1553 !haveSameTypeVariables(cls, superclass)) { | 1548 !haveSameTypeVariables(cls, superclass)) { |
| 1554 // We cannot inherit the generated substitutions, because the type | 1549 // We cannot inherit the generated substitutions, because the type |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1649 /** | 1644 /** |
| 1650 * Return a function that returns true if its argument is a class | 1645 * Return a function that returns true if its argument is a class |
| 1651 * that needs to be emitted. | 1646 * that needs to be emitted. |
| 1652 */ | 1647 */ |
| 1653 Function computeClassFilter() { | 1648 Function computeClassFilter() { |
| 1654 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 1649 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
| 1655 // The [Bool] class is not marked as abstract, but has a factory | 1650 // The [Bool] class is not marked as abstract, but has a factory |
| 1656 // constructor that always throws. We never need to emit it. | 1651 // constructor that always throws. We never need to emit it. |
| 1657 unneededClasses.add(compiler.boolClass); | 1652 unneededClasses.add(compiler.boolClass); |
| 1658 | 1653 |
| 1659 JavaScriptBackend backend = compiler.backend; | |
| 1660 | |
| 1661 // Go over specialized interceptors and then constants to know which | 1654 // Go over specialized interceptors and then constants to know which |
| 1662 // interceptors are needed. | 1655 // interceptors are needed. |
| 1663 Set<ClassElement> needed = new Set<ClassElement>(); | 1656 Set<ClassElement> needed = new Set<ClassElement>(); |
| 1664 backend.specializedGetInterceptors.forEach( | 1657 backend.specializedGetInterceptors.forEach( |
| 1665 (_, Collection<ClassElement> elements) { | 1658 (_, Collection<ClassElement> elements) { |
| 1666 needed.addAll(elements); | 1659 needed.addAll(elements); |
| 1667 } | 1660 } |
| 1668 ); | 1661 ); |
| 1669 | 1662 |
| 1670 ConstantHandler handler = compiler.constantHandler; | 1663 ConstantHandler handler = compiler.constantHandler; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1741 void emitStaticFunction(CodeBuffer buffer, | 1734 void emitStaticFunction(CodeBuffer buffer, |
| 1742 String name, | 1735 String name, |
| 1743 jsAst.Expression functionExpression) { | 1736 jsAst.Expression functionExpression) { |
| 1744 jsAst.Expression assignment = | 1737 jsAst.Expression assignment = |
| 1745 js[isolateProperties][name].assign(functionExpression); | 1738 js[isolateProperties][name].assign(functionExpression); |
| 1746 buffer.add(jsAst.prettyPrint(assignment, compiler)); | 1739 buffer.add(jsAst.prettyPrint(assignment, compiler)); |
| 1747 buffer.add('$N$n'); | 1740 buffer.add('$N$n'); |
| 1748 } | 1741 } |
| 1749 | 1742 |
| 1750 void emitStaticFunctions(CodeBuffer buffer) { | 1743 void emitStaticFunctions(CodeBuffer buffer) { |
| 1751 JavaScriptBackend backend = compiler.backend; | |
| 1752 bool isStaticFunction(Element element) => | 1744 bool isStaticFunction(Element element) => |
| 1753 !element.isInstanceMember() && !element.isField(); | 1745 !element.isInstanceMember() && !element.isField(); |
| 1754 | 1746 |
| 1755 Iterable<Element> elements = | 1747 Iterable<Element> elements = |
| 1756 backend.generatedCode.keys.where(isStaticFunction); | 1748 backend.generatedCode.keys.where(isStaticFunction); |
| 1757 Set<Element> pendingElementsWithBailouts = | 1749 Set<Element> pendingElementsWithBailouts = |
| 1758 backend.generatedBailoutCode.keys | 1750 backend.generatedBailoutCode.keys |
| 1759 .where(isStaticFunction) | 1751 .where(isStaticFunction) |
| 1760 .toSet(); | 1752 .toSet(); |
| 1761 | 1753 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1852 // are more difficult to canonicalize because they would need to have the | 1844 // are more difficult to canonicalize because they would need to have the |
| 1853 // same default values. | 1845 // same default values. |
| 1854 | 1846 |
| 1855 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; | 1847 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; |
| 1856 int parameterCount = member.parameterCount(compiler); | 1848 int parameterCount = member.parameterCount(compiler); |
| 1857 | 1849 |
| 1858 Map<int, String> cache; | 1850 Map<int, String> cache; |
| 1859 String extraArg = null; | 1851 String extraArg = null; |
| 1860 // Methods on interceptor classes take an extra parameter, which is the | 1852 // Methods on interceptor classes take an extra parameter, which is the |
| 1861 // actual receiver of the call. | 1853 // actual receiver of the call. |
| 1862 JavaScriptBackend backend = compiler.backend; | |
| 1863 bool inInterceptor = backend.isInterceptorClass(member.getEnclosingClass()); | 1854 bool inInterceptor = backend.isInterceptorClass(member.getEnclosingClass()); |
| 1864 if (inInterceptor) { | 1855 if (inInterceptor) { |
| 1865 cache = interceptorClosureCache; | 1856 cache = interceptorClosureCache; |
| 1866 extraArg = 'receiver'; | 1857 extraArg = 'receiver'; |
| 1867 } else { | 1858 } else { |
| 1868 cache = boundClosureCache; | 1859 cache = boundClosureCache; |
| 1869 } | 1860 } |
| 1870 List<String> fieldNames = compiler.enableMinification | 1861 List<String> fieldNames = compiler.enableMinification |
| 1871 ? inInterceptor ? const ['a', 'b', 'c'] | 1862 ? inInterceptor ? const ['a', 'b', 'c'] |
| 1872 : const ['a', 'b'] | 1863 : const ['a', 'b'] |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1976 /** | 1967 /** |
| 1977 * Documentation wanted -- johnniwinther | 1968 * Documentation wanted -- johnniwinther |
| 1978 * | 1969 * |
| 1979 * Invariant: [member] must be a declaration element. | 1970 * Invariant: [member] must be a declaration element. |
| 1980 */ | 1971 */ |
| 1981 void emitCallStubForGetter(Element member, | 1972 void emitCallStubForGetter(Element member, |
| 1982 Set<Selector> selectors, | 1973 Set<Selector> selectors, |
| 1983 DefineStubFunction defineStub) { | 1974 DefineStubFunction defineStub) { |
| 1984 assert(invariant(member, member.isDeclaration)); | 1975 assert(invariant(member, member.isDeclaration)); |
| 1985 LibraryElement memberLibrary = member.getLibrary(); | 1976 LibraryElement memberLibrary = member.getLibrary(); |
| 1986 JavaScriptBackend backend = compiler.backend; | |
| 1987 // If the class is an interceptor class, the stub gets the | 1977 // If the class is an interceptor class, the stub gets the |
| 1988 // receiver explicitely and we need to pass it to the getter call. | 1978 // receiver explicitely and we need to pass it to the getter call. |
| 1989 bool isInterceptorClass = | 1979 bool isInterceptorClass = |
| 1990 backend.isInterceptorClass(member.getEnclosingClass()); | 1980 backend.isInterceptorClass(member.getEnclosingClass()); |
| 1991 | 1981 |
| 1992 const String receiverArgumentName = r'$receiver'; | 1982 const String receiverArgumentName = r'$receiver'; |
| 1993 | 1983 |
| 1994 jsAst.Expression buildGetter() { | 1984 jsAst.Expression buildGetter() { |
| 1995 if (member.isGetter()) { | 1985 if (member.isGetter()) { |
| 1996 String getterName = namer.getterName(member); | 1986 String getterName = namer.getterName(member); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2055 buffer.add(jsAst.prettyPrint(init, compiler)); | 2045 buffer.add(jsAst.prettyPrint(init, compiler)); |
| 2056 buffer.add('$N'); | 2046 buffer.add('$N'); |
| 2057 }); | 2047 }); |
| 2058 } | 2048 } |
| 2059 } | 2049 } |
| 2060 | 2050 |
| 2061 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { | 2051 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { |
| 2062 ConstantHandler handler = compiler.constantHandler; | 2052 ConstantHandler handler = compiler.constantHandler; |
| 2063 List<VariableElement> lazyFields = | 2053 List<VariableElement> lazyFields = |
| 2064 handler.getLazilyInitializedFieldsForEmission(); | 2054 handler.getLazilyInitializedFieldsForEmission(); |
| 2065 JavaScriptBackend backend = compiler.backend; | |
| 2066 if (!lazyFields.isEmpty) { | 2055 if (!lazyFields.isEmpty) { |
| 2067 needsLazyInitializer = true; | 2056 needsLazyInitializer = true; |
| 2068 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { | 2057 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { |
| 2069 assert(backend.generatedBailoutCode[element] == null); | 2058 assert(backend.generatedBailoutCode[element] == null); |
| 2070 jsAst.Expression code = backend.generatedCode[element]; | 2059 jsAst.Expression code = backend.generatedCode[element]; |
| 2071 assert(code != null); | 2060 assert(code != null); |
| 2072 // The code only computes the initial value. We build the lazy-check | 2061 // The code only computes the initial value. We build the lazy-check |
| 2073 // here: | 2062 // here: |
| 2074 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); | 2063 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); |
| 2075 // The name is used for error reporting. The 'initial' must be a | 2064 // The name is used for error reporting. The 'initial' must be a |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2381 | 2370 |
| 2382 void emitGetInterceptorMethod(CodeBuffer buffer, | 2371 void emitGetInterceptorMethod(CodeBuffer buffer, |
| 2383 String objectName, | 2372 String objectName, |
| 2384 String key, | 2373 String key, |
| 2385 Collection<ClassElement> classes) { | 2374 Collection<ClassElement> classes) { |
| 2386 jsAst.Statement buildReturnInterceptor(ClassElement cls) { | 2375 jsAst.Statement buildReturnInterceptor(ClassElement cls) { |
| 2387 return js.return_(js[namer.isolateAccess(cls)]['prototype']); | 2376 return js.return_(js[namer.isolateAccess(cls)]['prototype']); |
| 2388 } | 2377 } |
| 2389 | 2378 |
| 2390 jsAst.VariableUse receiver = js['receiver']; | 2379 jsAst.VariableUse receiver = js['receiver']; |
| 2391 JavaScriptBackend backend = compiler.backend; | |
| 2392 | |
| 2393 /** | 2380 /** |
| 2394 * Build a JavaScrit AST node for doing a type check on | 2381 * Build a JavaScrit AST node for doing a type check on |
| 2395 * [cls]. [cls] must be an interceptor class. | 2382 * [cls]. [cls] must be an interceptor class. |
| 2396 */ | 2383 */ |
| 2397 jsAst.Statement buildInterceptorCheck(ClassElement cls) { | 2384 jsAst.Statement buildInterceptorCheck(ClassElement cls) { |
| 2398 jsAst.Expression condition; | 2385 jsAst.Expression condition; |
| 2399 assert(backend.isInterceptorClass(cls)); | 2386 assert(backend.isInterceptorClass(cls)); |
| 2400 if (cls == backend.jsBoolClass) { | 2387 if (cls == backend.jsBoolClass) { |
| 2401 condition = receiver.typeof.equals(js.string('boolean')); | 2388 condition = receiver.typeof.equals(js.string('boolean')); |
| 2402 } else if (cls == backend.jsIntClass || | 2389 } else if (cls == backend.jsIntClass || |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2495 buffer.add(jsAst.prettyPrint( | 2482 buffer.add(jsAst.prettyPrint( |
| 2496 js[isolateProperties][key].assign(js.fun(['receiver'], block)), | 2483 js[isolateProperties][key].assign(js.fun(['receiver'], block)), |
| 2497 compiler)); | 2484 compiler)); |
| 2498 buffer.add(N); | 2485 buffer.add(N); |
| 2499 } | 2486 } |
| 2500 | 2487 |
| 2501 /** | 2488 /** |
| 2502 * Emit all versions of the [:getInterceptor:] method. | 2489 * Emit all versions of the [:getInterceptor:] method. |
| 2503 */ | 2490 */ |
| 2504 void emitGetInterceptorMethods(CodeBuffer buffer) { | 2491 void emitGetInterceptorMethods(CodeBuffer buffer) { |
| 2505 JavaScriptBackend backend = compiler.backend; | |
| 2506 // If no class needs to be intercepted, just return. | 2492 // If no class needs to be intercepted, just return. |
| 2507 if (backend.objectInterceptorClass == null) return; | 2493 if (backend.objectInterceptorClass == null) return; |
| 2508 String objectName = namer.isolateAccess(backend.objectInterceptorClass); | 2494 String objectName = namer.isolateAccess(backend.objectInterceptorClass); |
| 2509 var specializedGetInterceptors = backend.specializedGetInterceptors; | 2495 var specializedGetInterceptors = backend.specializedGetInterceptors; |
| 2510 for (String name in specializedGetInterceptors.keys.toList()..sort()) { | 2496 for (String name in specializedGetInterceptors.keys.toList()..sort()) { |
| 2511 Collection<ClassElement> classes = specializedGetInterceptors[name]; | 2497 Collection<ClassElement> classes = specializedGetInterceptors[name]; |
| 2512 emitGetInterceptorMethod(buffer, objectName, name, classes); | 2498 emitGetInterceptorMethod(buffer, objectName, name, classes); |
| 2513 } | 2499 } |
| 2514 } | 2500 } |
| 2515 | 2501 |
| 2516 void computeNeededClasses() { | 2502 void computeNeededClasses() { |
| 2517 instantiatedClasses = | 2503 instantiatedClasses = |
| 2518 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) | 2504 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) |
| 2519 .toSet(); | 2505 .toSet(); |
| 2520 neededClasses = new Set<ClassElement>.from(instantiatedClasses); | 2506 neededClasses = new Set<ClassElement>.from(instantiatedClasses); |
| 2521 for (ClassElement element in instantiatedClasses) { | 2507 for (ClassElement element in instantiatedClasses) { |
| 2522 for (ClassElement superclass = element.superclass; | 2508 for (ClassElement superclass = element.superclass; |
| 2523 superclass != null; | 2509 superclass != null; |
| 2524 superclass = superclass.superclass) { | 2510 superclass = superclass.superclass) { |
| 2525 if (neededClasses.contains(superclass)) break; | 2511 if (neededClasses.contains(superclass)) break; |
| 2526 neededClasses.add(superclass); | 2512 neededClasses.add(superclass); |
| 2527 } | 2513 } |
| 2528 } | 2514 } |
| 2529 } | 2515 } |
| 2530 | 2516 |
| 2531 int _compareSelectors(Selector selector1, Selector selector2) { | 2517 int _compareSelectors(Selector selector1, Selector selector2) { |
| 2532 int comparison = _compareSelectorNames(selector1, selector2); | 2518 int comparison = _compareSelectorNames(selector1, selector2); |
| 2533 if (comparison != 0) return comparison; | 2519 if (comparison != 0) return comparison; |
| 2534 | 2520 |
| 2535 JavaScriptBackend backend = compiler.backend; | |
| 2536 Set<ClassElement> classes1 = backend.getInterceptedClassesOn(selector1); | 2521 Set<ClassElement> classes1 = backend.getInterceptedClassesOn(selector1); |
| 2537 Set<ClassElement> classes2 = backend.getInterceptedClassesOn(selector2); | 2522 Set<ClassElement> classes2 = backend.getInterceptedClassesOn(selector2); |
| 2538 if (classes1.length != classes2.length) { | 2523 if (classes1.length != classes2.length) { |
| 2539 return classes1.length - classes2.length; | 2524 return classes1.length - classes2.length; |
| 2540 } | 2525 } |
| 2541 String getInterceptor1 = | 2526 String getInterceptor1 = |
| 2542 namer.getInterceptorName(backend.getInterceptorMethod, classes1); | 2527 namer.getInterceptorName(backend.getInterceptorMethod, classes1); |
| 2543 String getInterceptor2 = | 2528 String getInterceptor2 = |
| 2544 namer.getInterceptorName(backend.getInterceptorMethod, classes2); | 2529 namer.getInterceptorName(backend.getInterceptorMethod, classes2); |
| 2545 return Comparable.compare(getInterceptor1, getInterceptor2); | 2530 return Comparable.compare(getInterceptor1, getInterceptor2); |
| 2546 } | 2531 } |
| 2547 | 2532 |
| 2548 void emitOneShotInterceptors(CodeBuffer buffer) { | 2533 void emitOneShotInterceptors(CodeBuffer buffer) { |
| 2549 JavaScriptBackend backend = compiler.backend; | |
| 2550 for (Selector selector in | 2534 for (Selector selector in |
| 2551 backend.oneShotInterceptors.toList()..sort(_compareSelectors)) { | 2535 backend.oneShotInterceptors.toList()..sort(_compareSelectors)) { |
| 2552 Set<ClassElement> classes = backend.getInterceptedClassesOn(selector); | 2536 Set<ClassElement> classes = backend.getInterceptedClassesOn(selector); |
| 2553 String oneShotInterceptorName = namer.oneShotInterceptorName(selector); | 2537 String oneShotInterceptorName = namer.oneShotInterceptorName(selector); |
| 2554 String getInterceptorName = | 2538 String getInterceptorName = |
| 2555 namer.getInterceptorName(backend.getInterceptorMethod, classes); | 2539 namer.getInterceptorName(backend.getInterceptorMethod, classes); |
| 2556 | 2540 |
| 2557 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; | 2541 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; |
| 2558 List<jsAst.Expression> arguments = <jsAst.Expression>[]; | 2542 List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
| 2559 parameters.add(new jsAst.Parameter('receiver')); | 2543 parameters.add(new jsAst.Parameter('receiver')); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2672 """; | 2656 """; |
| 2673 const String HOOKS_API_USAGE = """ | 2657 const String HOOKS_API_USAGE = """ |
| 2674 // The code supports the following hooks: | 2658 // The code supports the following hooks: |
| 2675 // dartPrint(message) - if this function is defined it is called | 2659 // dartPrint(message) - if this function is defined it is called |
| 2676 // instead of the Dart [print] method. | 2660 // instead of the Dart [print] method. |
| 2677 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2661 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2678 // method will not be invoked directly. | 2662 // method will not be invoked directly. |
| 2679 // Instead, a closure that will invoke [main] is | 2663 // Instead, a closure that will invoke [main] is |
| 2680 // passed to [dartMainRunner]. | 2664 // passed to [dartMainRunner]. |
| 2681 """; | 2665 """; |
| OLD | NEW |