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 |