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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 * `x is Set<String>` then the ClassElement `Set` will occur once in | 101 * `x is Set<String>` then the ClassElement `Set` will occur once in |
102 * [checkedClasses]. | 102 * [checkedClasses]. |
103 */ | 103 */ |
104 Set<ClassElement> checkedClasses; | 104 Set<ClassElement> checkedClasses; |
105 | 105 |
106 /** | 106 /** |
107 * Raw Typedef symbols occuring in is-checks and type assertions. If the | 107 * Raw Typedef symbols occuring in is-checks and type assertions. If the |
108 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement | 108 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement |
109 * `F` will occur once in [checkedTypedefs]. | 109 * `F` will occur once in [checkedTypedefs]. |
110 */ | 110 */ |
111 Set<TypedefElement> checkedTypedefs; | 111 Set<FunctionType> checkedFunctionTypes; |
| 112 |
| 113 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes |
| 114 = new Map<ClassElement, Set<FunctionType>>(); |
| 115 |
| 116 Set<FunctionType> checkedNonGenericFunctionTypes |
| 117 = new Set<FunctionType>(); |
| 118 |
| 119 void registerDynamicFunctionTypeCheck(FunctionType functionType) { |
| 120 ClassElement classElement = Types.getClassContext(functionType); |
| 121 if (classElement != null) { |
| 122 checkedGenericFunctionTypes.putIfAbsent(classElement, |
| 123 () => new Set<FunctionType>()).add(functionType); |
| 124 } else { |
| 125 checkedNonGenericFunctionTypes.add(functionType); |
| 126 } |
| 127 } |
112 | 128 |
113 final bool generateSourceMap; | 129 final bool generateSourceMap; |
114 | 130 |
115 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; | 131 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; |
116 | 132 |
117 Iterable<ClassElement> get classesUsingTypeVariableTests { | 133 Iterable<ClassElement> get classesUsingTypeVariableTests { |
118 if (cachedClassesUsingTypeVariableTests == null) { | 134 if (cachedClassesUsingTypeVariableTests == null) { |
119 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks | 135 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks |
120 .where((DartType t) => t is TypeVariableType) | 136 .where((DartType t) => t is TypeVariableType) |
121 .map((TypeVariableType v) => v.element.getEnclosingClass()) | 137 .map((TypeVariableType v) => v.element.getEnclosingClass()) |
(...skipping 10 matching lines...) Expand all Loading... |
132 constantEmitter = new ConstantEmitter(compiler, namer), | 148 constantEmitter = new ConstantEmitter(compiler, namer), |
133 super(compiler) { | 149 super(compiler) { |
134 nativeEmitter = new NativeEmitter(this); | 150 nativeEmitter = new NativeEmitter(this); |
135 } | 151 } |
136 | 152 |
137 void addComment(String comment, CodeBuffer buffer) { | 153 void addComment(String comment, CodeBuffer buffer) { |
138 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); | 154 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); |
139 } | 155 } |
140 | 156 |
141 void computeRequiredTypeChecks() { | 157 void computeRequiredTypeChecks() { |
142 assert(checkedClasses == null && checkedTypedefs == null); | 158 assert(checkedClasses == null && checkedFunctionTypes == null); |
143 | 159 |
144 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); | 160 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); |
145 | 161 |
146 checkedClasses = new Set<ClassElement>(); | 162 checkedClasses = new Set<ClassElement>(); |
147 checkedTypedefs = new Set<TypedefElement>(); | 163 checkedFunctionTypes = new Set<FunctionType>(); |
148 compiler.codegenWorld.isChecks.forEach((DartType t) { | 164 compiler.codegenWorld.isChecks.forEach((DartType t) { |
149 if (t is InterfaceType) { | 165 if (t is InterfaceType) { |
150 checkedClasses.add(t.element); | 166 checkedClasses.add(t.element); |
151 } else if (t is TypedefType) { | 167 } else if (t is FunctionType) { |
152 checkedTypedefs.add(t.element); | 168 checkedFunctionTypes.add(t); |
153 } | 169 } |
154 }); | 170 }); |
155 } | 171 } |
156 | 172 |
157 jsAst.Expression constantReference(Constant value) { | 173 jsAst.Expression constantReference(Constant value) { |
158 return constantEmitter.reference(value); | 174 return constantEmitter.reference(value); |
159 } | 175 } |
160 | 176 |
161 jsAst.Expression constantInitializerExpression(Constant value) { | 177 jsAst.Expression constantInitializerExpression(Constant value) { |
162 return constantEmitter.initializationExpression(value); | 178 return constantEmitter.initializationExpression(value); |
(...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 return; | 983 return; |
968 } | 984 } |
969 if (nativeEmitter.requiresNativeIsCheck(other)) { | 985 if (nativeEmitter.requiresNativeIsCheck(other)) { |
970 code = js.fun([], [js.return_(true)]); | 986 code = js.fun([], [js.return_(true)]); |
971 } else { | 987 } else { |
972 code = new jsAst.LiteralBool(true); | 988 code = new jsAst.LiteralBool(true); |
973 } | 989 } |
974 builder.addProperty(namer.operatorIs(other), code); | 990 builder.addProperty(namer.operatorIs(other), code); |
975 } | 991 } |
976 | 992 |
| 993 void generateIsFunctionTypeTest(FunctionType type) { |
| 994 builder.addProperty(namer.operatorIsFunctionType(type), |
| 995 new jsAst.LiteralBool(true)); |
| 996 } |
| 997 |
| 998 void generateFunctionTypeSignature(FunctionType type) { |
| 999 RuntimeTypeInformation rti = backend.rti; |
| 1000 String encoding = rti.getTypeEncoding(type, alwaysGenerateFunction: true); |
| 1001 String operatorSignature = namer.operatorSignature(); |
| 1002 builder.addProperty(operatorSignature, |
| 1003 new jsAst.LiteralExpression(encoding)); |
| 1004 } |
| 1005 |
977 void generateSubstitution(Element other, {bool emitNull: false}) { | 1006 void generateSubstitution(Element other, {bool emitNull: false}) { |
978 RuntimeTypeInformation rti = backend.rti; | 1007 RuntimeTypeInformation rti = backend.rti; |
979 // TODO(karlklose): support typedefs with variables. | 1008 // TODO(karlklose): support typedefs with variables. |
980 jsAst.Expression expression; | 1009 jsAst.Expression expression; |
981 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); | 1010 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); |
982 if (other.kind == ElementKind.CLASS) { | 1011 if (other.kind == ElementKind.CLASS) { |
983 String substitution = rti.getSupertypeSubstitution(classElement, other, | 1012 String substitution = rti.getSupertypeSubstitution(classElement, other, |
984 alwaysGenerateFunction: true); | 1013 alwaysGenerateFunction: true); |
985 if (substitution != null) { | 1014 if (substitution != null) { |
986 expression = new jsAst.LiteralExpression(substitution); | 1015 expression = new jsAst.LiteralExpression(substitution); |
987 } else if (emitNull || needsNativeCheck) { | 1016 } else if (emitNull || needsNativeCheck) { |
988 expression = new jsAst.LiteralNull(); | 1017 expression = new jsAst.LiteralNull(); |
989 } | 1018 } |
990 } | 1019 } |
991 if (expression != null) { | 1020 if (expression != null) { |
992 if (needsNativeCheck) { | 1021 if (needsNativeCheck) { |
993 expression = js.fun([], js.return_(expression)); | 1022 expression = js.fun([], js.return_(expression)); |
994 } | 1023 } |
995 builder.addProperty(namer.substitutionName(other), expression); | 1024 builder.addProperty(namer.substitutionName(other), expression); |
996 } | 1025 } |
997 } | 1026 } |
998 | 1027 |
999 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); | 1028 generateIsTestsOn(classElement, generateIsTest, |
| 1029 generateIsFunctionTypeTest, generateFunctionTypeSignature, |
| 1030 generateSubstitution); |
1000 | 1031 |
1001 if (identical(classElement, compiler.objectClass) | 1032 if (identical(classElement, compiler.objectClass) |
1002 && compiler.enabledNoSuchMethod) { | 1033 && compiler.enabledNoSuchMethod) { |
1003 // Emit the noSuchMethod handlers on the Object prototype now, | 1034 // Emit the noSuchMethod handlers on the Object prototype now, |
1004 // so that the code in the dynamicFunction helper can find | 1035 // so that the code in the dynamicFunction helper can find |
1005 // them. Note that this helper is invoked before analyzing the | 1036 // them. Note that this helper is invoked before analyzing the |
1006 // full JS script. | 1037 // full JS script. |
1007 if (!nativeEmitter.handleNoSuchMethod) { | 1038 if (!nativeEmitter.handleNoSuchMethod) { |
1008 emitNoSuchMethodHandlers(builder.addProperty); | 1039 emitNoSuchMethodHandlers(builder.addProperty); |
1009 } | 1040 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1047 for (ClassElement cls in typeChecks) { | 1078 for (ClassElement cls in typeChecks) { |
1048 String holder = namer.isolateAccess(cls); | 1079 String holder = namer.isolateAccess(cls); |
1049 for (ClassElement check in typeChecks[cls]) { | 1080 for (ClassElement check in typeChecks[cls]) { |
1050 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 1081 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
1051 String body = rti.getSupertypeSubstitution(cls, check); | 1082 String body = rti.getSupertypeSubstitution(cls, check); |
1052 if (body != null) { | 1083 if (body != null) { |
1053 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N')
; | 1084 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N')
; |
1054 } | 1085 } |
1055 }; | 1086 }; |
1056 } | 1087 } |
| 1088 |
| 1089 checkedNonGenericFunctionTypes.forEach((FunctionType type) { |
| 1090 String encoding = rti.getTypeEncoding(type); |
| 1091 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N'); |
| 1092 }); |
| 1093 |
| 1094 checkedGenericFunctionTypes.forEach( |
| 1095 (ClassElement cls, Set<FunctionType> functionTypes) { |
| 1096 for (FunctionType type in functionTypes) { |
| 1097 String encoding = rti.getTypeEncoding(type); |
| 1098 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N'); |
| 1099 } |
| 1100 }); |
1057 } | 1101 } |
1058 | 1102 |
1059 void visitNativeMixins(ClassElement classElement, | 1103 void visitNativeMixins(ClassElement classElement, |
1060 void visit(MixinApplicationElement mixinApplication)) { | 1104 void visit(MixinApplicationElement mixinApplication)) { |
1061 if (!classElement.isNative()) return; | 1105 if (!classElement.isNative()) return; |
1062 // Use recursion to make sure to visit the superclasses before the | 1106 // Use recursion to make sure to visit the superclasses before the |
1063 // subclasses. Once we start keeping track of the emitted fields | 1107 // subclasses. Once we start keeping track of the emitted fields |
1064 // and members, we're going to want to visit these in the other | 1108 // and members, we're going to want to visit these in the other |
1065 // order so we get the most specialized definition first. | 1109 // order so we get the most specialized definition first. |
1066 void recurse(ClassElement cls) { | 1110 void recurse(ClassElement cls) { |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 return arity; | 1426 return arity; |
1383 } | 1427 } |
1384 | 1428 |
1385 int _compareSelectorNames(Selector selector1, Selector selector2) { | 1429 int _compareSelectorNames(Selector selector1, Selector selector2) { |
1386 String name1 = selector1.name.toString(); | 1430 String name1 = selector1.name.toString(); |
1387 String name2 = selector2.name.toString(); | 1431 String name2 = selector2.name.toString(); |
1388 if (name1 != name2) return Comparable.compare(name1, name2); | 1432 if (name1 != name2) return Comparable.compare(name1, name2); |
1389 return _selectorRank(selector1) - _selectorRank(selector2); | 1433 return _selectorRank(selector1) - _selectorRank(selector2); |
1390 } | 1434 } |
1391 | 1435 |
1392 Iterable<Element> getTypedefChecksOn(DartType type) { | 1436 /** |
1393 bool isSubtype(TypedefElement typedef) { | 1437 * Returns a mapping containing all checked function types for which [type] |
1394 FunctionType typedefType = | 1438 * can be a subtype. A function type is mapped to [:true:] if [type] is |
1395 typedef.computeType(compiler).unalias(compiler); | 1439 * statically known to be a subtype of it. |
1396 return compiler.types.isSubtype(type, typedefType); | 1440 */ |
| 1441 // TODO(johnniwinther): Change to return a mapping from function types to |
| 1442 // a set of variable points and use this to detect statically/dynamically |
| 1443 // known subtype relations. |
| 1444 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) { |
| 1445 Map<FunctionType, bool> functionTypeMap = |
| 1446 new LinkedHashMap<FunctionType, bool>(); |
| 1447 for (FunctionType functionType in checkedFunctionTypes) { |
| 1448 if (compiler.types.isSubtype(type, functionType)) { |
| 1449 functionTypeMap[functionType] = true; |
| 1450 } else if (compiler.types.isPotentialSubtype(type, functionType)) { |
| 1451 functionTypeMap[functionType] = false; |
| 1452 } |
1397 } | 1453 } |
1398 return checkedTypedefs.where(isSubtype).toList() | 1454 // TODO(johnniwinther): Ensure stable ordering of the keys. |
1399 ..sort(Elements.compareByPosition); | 1455 return functionTypeMap; |
1400 } | 1456 } |
1401 | 1457 |
1402 /** | 1458 /** |
1403 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1459 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
1404 * classes it implements and type argument substitution functions for these | 1460 * classes it implements and type argument substitution functions for these |
1405 * tests. We don't need to add the "is tests" of the super class because | 1461 * tests. We don't need to add the "is tests" of the super class because |
1406 * they will be inherited at runtime, but we may need to generate the | 1462 * they will be inherited at runtime, but we may need to generate the |
1407 * substitutions, because they may have changed. | 1463 * substitutions, because they may have changed. |
1408 */ | 1464 */ |
1409 void generateIsTestsOn(ClassElement cls, | 1465 void generateIsTestsOn(ClassElement cls, |
1410 void emitIsTest(Element element), | 1466 void emitIsTest(Element element), |
| 1467 void emitIsFunctionTypeTest(FunctionType type), |
| 1468 void emitFunctionTypeSignature(FunctionType type), |
1411 void emitSubstitution(Element element, {emitNull})) { | 1469 void emitSubstitution(Element element, {emitNull})) { |
1412 if (checkedClasses.contains(cls)) { | 1470 if (checkedClasses.contains(cls)) { |
1413 emitIsTest(cls); | 1471 emitIsTest(cls); |
1414 emitSubstitution(cls); | 1472 emitSubstitution(cls); |
1415 } | 1473 } |
1416 | 1474 |
1417 RuntimeTypeInformation rti = backend.rti; | 1475 RuntimeTypeInformation rti = backend.rti; |
1418 ClassElement superclass = cls.superclass; | 1476 ClassElement superclass = cls.superclass; |
1419 | 1477 |
1420 bool haveSameTypeVariables(ClassElement a, ClassElement b) { | 1478 bool haveSameTypeVariables(ClassElement a, ClassElement b) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1452 } | 1510 } |
1453 } | 1511 } |
1454 void emitNothing(_, {emitNull}) {}; | 1512 void emitNothing(_, {emitNull}) {}; |
1455 emitSubstitution = emitNothing; | 1513 emitSubstitution = emitNothing; |
1456 } | 1514 } |
1457 | 1515 |
1458 Set<Element> generated = new Set<Element>(); | 1516 Set<Element> generated = new Set<Element>(); |
1459 // A class that defines a [:call:] method implicitly implements | 1517 // A class that defines a [:call:] method implicitly implements |
1460 // [Function] and needs checks for all typedefs that are used in is-checks. | 1518 // [Function] and needs checks for all typedefs that are used in is-checks. |
1461 if (checkedClasses.contains(compiler.functionClass) || | 1519 if (checkedClasses.contains(compiler.functionClass) || |
1462 !checkedTypedefs.isEmpty) { | 1520 !checkedFunctionTypes.isEmpty) { |
1463 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1521 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
1464 if (call == null) { | 1522 if (call == null) { |
1465 // If [cls] is a closure, it has a synthetic call operator method. | 1523 // If [cls] is a closure, it has a synthetic call operator method. |
1466 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1524 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
1467 } | 1525 } |
1468 if (call != null) { | 1526 if (call != null) { |
1469 generateInterfacesIsTests(compiler.functionClass, | 1527 generateInterfacesIsTests(compiler.functionClass, |
1470 emitIsTest, | 1528 emitIsTest, |
1471 emitSubstitution, | 1529 emitSubstitution, |
1472 generated); | 1530 generated); |
1473 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1531 FunctionType callType = call.computeType(compiler); |
| 1532 Map<FunctionType,bool> functionTypeChecks = |
| 1533 getFunctionTypeChecksOn(callType); |
| 1534 bool hasDynamicFunctionTypeCheck = false; |
| 1535 functionTypeChecks.forEach((FunctionType functionType, |
| 1536 bool knownSubtype) { |
| 1537 emitIsFunctionTypeTest(functionType); |
| 1538 if (!knownSubtype) { |
| 1539 registerDynamicFunctionTypeCheck(functionType); |
| 1540 hasDynamicFunctionTypeCheck = true; |
| 1541 } |
| 1542 }); |
| 1543 if (hasDynamicFunctionTypeCheck) { |
| 1544 emitFunctionTypeSignature(callType); |
| 1545 } |
1474 } | 1546 } |
1475 } | 1547 } |
1476 | 1548 |
1477 for (DartType interfaceType in cls.interfaces) { | 1549 for (DartType interfaceType in cls.interfaces) { |
1478 generateInterfacesIsTests(interfaceType.element, emitIsTest, | 1550 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
1479 emitSubstitution, generated); | 1551 emitSubstitution, generated); |
1480 } | 1552 } |
1481 | 1553 |
1482 // For native classes, we also have to run through their mixin | 1554 // For native classes, we also have to run through their mixin |
1483 // applications and make sure we deal with 'is' tests correctly | 1555 // applications and make sure we deal with 'is' tests correctly |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1646 jsAst.Expression assignment = | 1718 jsAst.Expression assignment = |
1647 js[isolateProperties][staticName][name].assign(value); | 1719 js[isolateProperties][staticName][name].assign(value); |
1648 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); | 1720 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); |
1649 buffer.write('$N'); | 1721 buffer.write('$N'); |
1650 }); | 1722 }); |
1651 | 1723 |
1652 // If a static function is used as a closure we need to add its name | 1724 // If a static function is used as a closure we need to add its name |
1653 // in case it is used in spawnFunction. | 1725 // in case it is used in spawnFunction. |
1654 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1726 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
1655 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); | 1727 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); |
1656 getTypedefChecksOn(element.computeType(compiler)).forEach( | 1728 FunctionType elementType = element.computeType(compiler); |
1657 (Element typedef) { | 1729 Map<FunctionType,bool> functionTypeChecks = |
1658 String operator = namer.operatorIs(typedef); | 1730 getFunctionTypeChecksOn(elementType); |
1659 buffer.write('$fieldAccess.$operator$_=${_}true$N'); | 1731 bool hasDynamicFunctionTypeCheck = false; |
| 1732 functionTypeChecks.forEach((FunctionType functionType, |
| 1733 bool knownSubtype) { |
| 1734 String operator = namer.operatorIsFunctionType(functionType); |
| 1735 buffer.write('$fieldAccess.$operator$_=${_}true$N'); |
| 1736 if (!knownSubtype) { |
| 1737 TypeVariableType typeVariable = functionType.typeVariableOccurrence; |
| 1738 registerDynamicFunctionTypeCheck(functionType); |
| 1739 hasDynamicFunctionTypeCheck = true; |
1660 } | 1740 } |
1661 ); | 1741 }); |
| 1742 if (hasDynamicFunctionTypeCheck) { |
| 1743 RuntimeTypeInformation rti = backend.rti; |
| 1744 String encoding = rti.getTypeEncoding(elementType, |
| 1745 alwaysGenerateFunction: true); |
| 1746 String operatorSignature = namer.operatorSignature(); |
| 1747 buffer.add('$fieldAccess.$operatorSignature$_=${_}$encoding$N'); |
| 1748 } |
| 1749 |
1662 } | 1750 } |
1663 } | 1751 } |
1664 | 1752 |
1665 void emitBoundClosureClassHeader(String mangledName, | 1753 void emitBoundClosureClassHeader(String mangledName, |
1666 String superName, | 1754 String superName, |
1667 List<String> fieldNames, | 1755 List<String> fieldNames, |
1668 ClassBuilder builder) { | 1756 ClassBuilder builder) { |
1669 builder.addProperty('', | 1757 builder.addProperty('', |
1670 js.string("$superName;${fieldNames.join(',')}")); | 1758 js.string("$superName;${fieldNames.join(',')}")); |
1671 } | 1759 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1712 extraArg = 'receiver'; | 1800 extraArg = 'receiver'; |
1713 } else { | 1801 } else { |
1714 cache = boundClosureCache; | 1802 cache = boundClosureCache; |
1715 } | 1803 } |
1716 List<String> fieldNames = compiler.enableMinification | 1804 List<String> fieldNames = compiler.enableMinification |
1717 ? inInterceptor ? const ['a', 'b', 'c'] | 1805 ? inInterceptor ? const ['a', 'b', 'c'] |
1718 : const ['a', 'b'] | 1806 : const ['a', 'b'] |
1719 : inInterceptor ? const ['self', 'target', 'receiver'] | 1807 : inInterceptor ? const ['self', 'target', 'receiver'] |
1720 : const ['self', 'target']; | 1808 : const ['self', 'target']; |
1721 | 1809 |
1722 Iterable<Element> typedefChecks = | 1810 DartType memberType = member.computeType(compiler); |
1723 getTypedefChecksOn(member.computeType(compiler)); | 1811 Map<FunctionType, bool> functionTypeChecks = |
1724 bool hasTypedefChecks = !typedefChecks.isEmpty; | 1812 getFunctionTypeChecksOn(memberType); |
| 1813 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty; |
1725 | 1814 |
1726 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; | 1815 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks; |
1727 | 1816 |
| 1817 ClassElement classElement = member.getEnclosingClass(); |
1728 String closureClass = canBeShared ? cache[parameterCount] : null; | 1818 String closureClass = canBeShared ? cache[parameterCount] : null; |
1729 if (closureClass == null) { | 1819 if (closureClass == null) { |
1730 // Either the class was not cached yet, or there are optional parameters. | 1820 // Either the class was not cached yet, or there are optional parameters. |
1731 // Create a new closure class. | 1821 // Create a new closure class. |
1732 String name; | 1822 String name; |
1733 if (canBeShared) { | 1823 if (canBeShared) { |
1734 if (inInterceptor) { | 1824 if (inInterceptor) { |
1735 name = 'BoundClosure\$i${parameterCount}'; | 1825 name = 'BoundClosure\$i${parameterCount}'; |
1736 } else { | 1826 } else { |
1737 name = 'BoundClosure\$${parameterCount}'; | 1827 name = 'BoundClosure\$${parameterCount}'; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1774 arguments.add(js[name]); | 1864 arguments.add(js[name]); |
1775 } | 1865 } |
1776 | 1866 |
1777 jsAst.Expression fun = js.fun( | 1867 jsAst.Expression fun = js.fun( |
1778 parameters, | 1868 parameters, |
1779 js.return_( | 1869 js.return_( |
1780 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments))); | 1870 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments))); |
1781 boundClosureBuilder.addProperty(invocationName, fun); | 1871 boundClosureBuilder.addProperty(invocationName, fun); |
1782 | 1872 |
1783 addParameterStubs(callElement, boundClosureBuilder.addProperty); | 1873 addParameterStubs(callElement, boundClosureBuilder.addProperty); |
1784 typedefChecks.forEach((Element typedef) { | 1874 bool hasDynamicFunctionTypeCheck = false; |
1785 String operator = namer.operatorIs(typedef); | 1875 functionTypeChecks.forEach((FunctionType functionType, |
| 1876 bool knownSubtype) { |
| 1877 String operator = namer.operatorIsFunctionType(functionType); |
1786 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true)); | 1878 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true)); |
| 1879 if (!knownSubtype) { |
| 1880 registerDynamicFunctionTypeCheck(functionType); |
| 1881 hasDynamicFunctionTypeCheck = true; |
| 1882 } |
1787 }); | 1883 }); |
| 1884 if (hasDynamicFunctionTypeCheck) { |
| 1885 RuntimeTypeInformation rti = backend.rti; |
| 1886 String encoding = rti.getTypeEncoding(memberType, |
| 1887 alwaysGenerateFunction: true); |
| 1888 String operatorSignature = namer.operatorSignature(); |
| 1889 boundClosureBuilder.addProperty(operatorSignature, |
| 1890 new jsAst.LiteralExpression(encoding)); |
| 1891 } |
1788 | 1892 |
1789 boundClosures.add( | 1893 boundClosures.add( |
1790 js[classesCollector][mangledName].assign( | 1894 js[classesCollector][mangledName].assign( |
1791 boundClosureBuilder.toObjectInitializer())); | 1895 boundClosureBuilder.toObjectInitializer())); |
1792 | 1896 |
1793 closureClass = namer.isolateAccess(closureClassElement); | 1897 closureClass = namer.isolateAccess(closureClassElement); |
1794 | 1898 |
1795 // Cache it. | 1899 // Cache it. |
1796 if (canBeShared) { | 1900 if (canBeShared) { |
1797 cache[parameterCount] = closureClass; | 1901 cache[parameterCount] = closureClass; |
1798 } | 1902 } |
1799 } | 1903 } |
1800 | 1904 |
1801 // And finally the getter. | 1905 // And finally the getter. |
1802 String getterName = namer.getterName(member); | 1906 String getterName = namer.getterName(member); |
1803 String targetName = namer.instanceMethodName(member); | 1907 String targetName = namer.instanceMethodName(member); |
1804 | 1908 |
1805 List<String> parameters = <String>[]; | 1909 List<String> parameters = <String>[]; |
1806 List<jsAst.Expression> arguments = <jsAst.Expression>[]; | 1910 List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
1807 arguments.add(js['this']); | 1911 arguments.add(js['this']); |
1808 arguments.add(js.string(targetName)); | 1912 arguments.add(js.string(targetName)); |
1809 if (inInterceptor) { | 1913 if (inInterceptor) { |
1810 parameters.add(extraArg); | 1914 parameters.add(extraArg); |
1811 arguments.add(js[extraArg]); | 1915 arguments.add(js[extraArg]); |
1812 } | 1916 } |
1813 | 1917 |
| 1918 jsAst.Expression newClosure = js[closureClass].newWith(arguments); |
1814 jsAst.Expression getterFunction = js.fun( | 1919 jsAst.Expression getterFunction = js.fun( |
1815 parameters, | 1920 parameters, |
1816 js.return_(js[closureClass].newWith(arguments))); | 1921 forwardRuntimeTypeInfo(newClosure, memberType, classElement)); |
1817 | 1922 |
1818 defineStub(getterName, getterFunction); | 1923 defineStub(getterName, getterFunction); |
1819 } | 1924 } |
1820 | 1925 |
1821 /** | 1926 /** |
| 1927 * Wraps the [newExpression] of a closure with code for setting the runtime |
| 1928 * type information if needed. |
| 1929 */ |
| 1930 forwardRuntimeTypeInfo(jsAst.Expression newExpression, |
| 1931 DartType memberType, |
| 1932 ClassElement thisClass) { |
| 1933 if (compiler.world.needsRti(thisClass) && |
| 1934 memberType.containsTypeVariables) { |
| 1935 String forwardRuntimeTypeInfo = |
| 1936 namer.isolateAccess(backend.getForwardRuntimeTypeInfo()); |
| 1937 String substitution = namer.substitutionName(thisClass); |
| 1938 return js.return_(new jsAst.Call(js[forwardRuntimeTypeInfo], |
| 1939 [newExpression, js['this.$substitution'], js['this']])); |
| 1940 } else { |
| 1941 return js.return_(newExpression); |
| 1942 } |
| 1943 } |
| 1944 |
| 1945 /** |
1822 * Documentation wanted -- johnniwinther | 1946 * Documentation wanted -- johnniwinther |
1823 * | 1947 * |
1824 * Invariant: [member] must be a declaration element. | 1948 * Invariant: [member] must be a declaration element. |
1825 */ | 1949 */ |
1826 void emitCallStubForGetter(Element member, | 1950 void emitCallStubForGetter(Element member, |
1827 Set<Selector> selectors, | 1951 Set<Selector> selectors, |
1828 DefineStubFunction defineStub) { | 1952 DefineStubFunction defineStub) { |
1829 assert(invariant(member, member.isDeclaration)); | 1953 assert(invariant(member, member.isDeclaration)); |
1830 LibraryElement memberLibrary = member.getLibrary(); | 1954 LibraryElement memberLibrary = member.getLibrary(); |
1831 // If the method is intercepted, the stub gets the | 1955 // If the method is intercepted, the stub gets the |
(...skipping 14 matching lines...) Expand all Loading... |
1846 ? member.fixedBackendName() | 1970 ? member.fixedBackendName() |
1847 : namer.instanceFieldName(member); | 1971 : namer.instanceFieldName(member); |
1848 return js['this'][fieldName]; | 1972 return js['this'][fieldName]; |
1849 } | 1973 } |
1850 } | 1974 } |
1851 | 1975 |
1852 // Two selectors may match but differ only in type. To avoid generating | 1976 // Two selectors may match but differ only in type. To avoid generating |
1853 // identical stubs for each we track untyped selectors which already have | 1977 // identical stubs for each we track untyped selectors which already have |
1854 // stubs. | 1978 // stubs. |
1855 Set<Selector> generatedSelectors = new Set<Selector>(); | 1979 Set<Selector> generatedSelectors = new Set<Selector>(); |
1856 | 1980 DartType memberType = member.computeType(compiler); |
1857 for (Selector selector in selectors) { | 1981 for (Selector selector in selectors) { |
1858 if (selector.applies(member, compiler)) { | 1982 if (selector.applies(member, compiler)) { |
1859 selector = selector.asUntyped; | 1983 selector = selector.asUntyped; |
1860 if (generatedSelectors.contains(selector)) continue; | 1984 if (generatedSelectors.contains(selector)) continue; |
1861 generatedSelectors.add(selector); | 1985 generatedSelectors.add(selector); |
1862 | 1986 |
1863 String invocationName = namer.invocationName(selector); | 1987 String invocationName = namer.invocationName(selector); |
1864 Selector callSelector = new Selector.callClosureFrom(selector); | 1988 Selector callSelector = new Selector.callClosureFrom(selector); |
1865 String closureCallName = namer.invocationName(callSelector); | 1989 String closureCallName = namer.invocationName(callSelector); |
1866 | 1990 |
(...skipping 919 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2786 """; | 2910 """; |
2787 const String HOOKS_API_USAGE = """ | 2911 const String HOOKS_API_USAGE = """ |
2788 // The code supports the following hooks: | 2912 // The code supports the following hooks: |
2789 // dartPrint(message) - if this function is defined it is called | 2913 // dartPrint(message) - if this function is defined it is called |
2790 // instead of the Dart [print] method. | 2914 // instead of the Dart [print] method. |
2791 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2915 // dartMainRunner(main) - if this function is defined, the Dart [main] |
2792 // method will not be invoked directly. | 2916 // method will not be invoked directly. |
2793 // Instead, a closure that will invoke [main] is | 2917 // Instead, a closure that will invoke [main] is |
2794 // passed to [dartMainRunner]. | 2918 // passed to [dartMainRunner]. |
2795 """; | 2919 """; |
OLD | NEW |