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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
99 /** | 99 /** |
100 * Raw ClassElement symbols occuring in is-checks and type assertions. If the | 100 * Raw ClassElement symbols occuring in is-checks and type assertions. If the |
101 * program contains parameterized checks `x is Set<int>` and | 101 * program contains parameterized checks `x is Set<int>` and |
102 * `x is Set<String>` then the ClassElement `Set` will occur once in | 102 * `x is Set<String>` then the ClassElement `Set` will occur once in |
103 * [checkedClasses]. | 103 * [checkedClasses]. |
104 */ | 104 */ |
105 Set<ClassElement> checkedClasses; | 105 Set<ClassElement> checkedClasses; |
106 | 106 |
107 /** | 107 /** |
108 * Raw Typedef symbols occuring in is-checks and type assertions. If the | 108 * Raw Typedef symbols occuring in is-checks and type assertions. If the |
109 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement | 109 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement |
karlklose
2013/03/22 13:17:46
Please update comment and change to use [::] inste
Johnni Winther
2013/06/21 12:19:14
Done.
| |
110 * `F` will occur once in [checkedTypedefs]. | 110 * `F` will occur once in [checkedTypedefs]. |
111 */ | 111 */ |
112 Set<TypedefElement> checkedTypedefs; | 112 Set<FunctionType> checkedFunctionTypes; |
113 | |
114 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes | |
115 = new Map<ClassElement, Set<FunctionType>>(); | |
karlklose
2013/03/22 13:17:46
Break after '='.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
116 | |
117 Set<FunctionType> checkedNonGenericFunctionTypes | |
karlklose
2013/03/22 13:17:46
Ditto.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
118 = new Set<FunctionType>(); | |
119 | |
120 void registerDynamicFunctionTypeCheck(FunctionType functionType) { | |
121 ClassElement classElement = Types.getClassContext(functionType); | |
122 if (classElement != null) { | |
123 checkedGenericFunctionTypes.putIfAbsent(classElement, | |
124 () => new Set<FunctionType>()).add(functionType); | |
125 } else { | |
126 checkedNonGenericFunctionTypes.add(functionType); | |
127 } | |
128 } | |
113 | 129 |
114 final bool generateSourceMap; | 130 final bool generateSourceMap; |
115 | 131 |
116 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; | 132 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; |
117 | 133 |
118 Iterable<ClassElement> get classesUsingTypeVariableTests { | 134 Iterable<ClassElement> get classesUsingTypeVariableTests { |
119 if (cachedClassesUsingTypeVariableTests == null) { | 135 if (cachedClassesUsingTypeVariableTests == null) { |
120 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks | 136 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks |
121 .where((DartType t) => t is TypeVariableType) | 137 .where((DartType t) => t is TypeVariableType) |
122 .map((TypeVariableType v) => v.element.getEnclosingClass()) | 138 .map((TypeVariableType v) => v.element.getEnclosingClass()) |
(...skipping 10 matching lines...) Expand all Loading... | |
133 constantEmitter = new ConstantEmitter(compiler, namer), | 149 constantEmitter = new ConstantEmitter(compiler, namer), |
134 super(compiler) { | 150 super(compiler) { |
135 nativeEmitter = new NativeEmitter(this); | 151 nativeEmitter = new NativeEmitter(this); |
136 } | 152 } |
137 | 153 |
138 void addComment(String comment, CodeBuffer buffer) { | 154 void addComment(String comment, CodeBuffer buffer) { |
139 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); | 155 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); |
140 } | 156 } |
141 | 157 |
142 void computeRequiredTypeChecks() { | 158 void computeRequiredTypeChecks() { |
143 assert(checkedClasses == null && checkedTypedefs == null); | 159 assert(checkedClasses == null && checkedFunctionTypes == null); |
144 | 160 |
145 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); | 161 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); |
146 | 162 |
147 checkedClasses = new Set<ClassElement>(); | 163 checkedClasses = new Set<ClassElement>(); |
148 checkedTypedefs = new Set<TypedefElement>(); | 164 checkedFunctionTypes = new Set<FunctionType>(); |
149 compiler.codegenWorld.isChecks.forEach((DartType t) { | 165 compiler.codegenWorld.isChecks.forEach((DartType t) { |
150 if (t is InterfaceType) { | 166 if (t is InterfaceType) { |
151 checkedClasses.add(t.element); | 167 checkedClasses.add(t.element); |
152 } else if (t is TypedefType) { | 168 } else if (t is FunctionType) { |
153 checkedTypedefs.add(t.element); | 169 checkedFunctionTypes.add(t); |
154 } | 170 } |
155 }); | 171 }); |
156 } | 172 } |
157 | 173 |
158 jsAst.Expression constantReference(Constant value) { | 174 jsAst.Expression constantReference(Constant value) { |
159 return constantEmitter.reference(value); | 175 return constantEmitter.reference(value); |
160 } | 176 } |
161 | 177 |
162 jsAst.Expression constantInitializerExpression(Constant value) { | 178 jsAst.Expression constantInitializerExpression(Constant value) { |
163 return constantEmitter.initializationExpression(value); | 179 return constantEmitter.initializationExpression(value); |
(...skipping 1033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1197 return; | 1213 return; |
1198 } | 1214 } |
1199 if (nativeEmitter.requiresNativeIsCheck(other)) { | 1215 if (nativeEmitter.requiresNativeIsCheck(other)) { |
1200 code = js.fun([], [js.return_(true)]); | 1216 code = js.fun([], [js.return_(true)]); |
1201 } else { | 1217 } else { |
1202 code = new jsAst.LiteralBool(true); | 1218 code = new jsAst.LiteralBool(true); |
1203 } | 1219 } |
1204 builder.addProperty(namer.operatorIs(other), code); | 1220 builder.addProperty(namer.operatorIs(other), code); |
1205 } | 1221 } |
1206 | 1222 |
1223 void generateIsFunctionTypeTest(FunctionType type) { | |
1224 String operator = namer.operatorIsType(type); | |
1225 builder.addProperty(operator, new jsAst.LiteralBool(true)); | |
1226 } | |
1227 | |
1228 void generateFunctionTypeSignature(Element method, FunctionType type) { | |
1229 assert(method.isImplementation); | |
1230 String thisAccess = 'this'; | |
1231 Node node = method.parseNode(compiler); | |
1232 ClosureClassMap closureData = | |
1233 compiler.closureToClassMapper.closureMappingCache[node]; | |
1234 if (closureData != null) { | |
1235 Element thisElement = | |
1236 closureData.freeVariableMapping[closureData.thisElement]; | |
1237 if (thisElement != null) { | |
1238 String thisName = backend.namer.getName(thisElement); | |
1239 thisAccess = 'this.$thisName'; | |
1240 } | |
1241 } | |
1242 RuntimeTypes rti = backend.rti; | |
1243 String encoding = rti.getSignatureEncoding(type, () => '$thisAccess'); | |
1244 String operatorSignature = namer.operatorSignature(); | |
1245 builder.addProperty(operatorSignature, | |
1246 new jsAst.LiteralExpression(encoding)); | |
1247 } | |
1248 | |
1207 void generateSubstitution(Element other, {bool emitNull: false}) { | 1249 void generateSubstitution(Element other, {bool emitNull: false}) { |
1208 RuntimeTypes rti = backend.rti; | 1250 RuntimeTypes rti = backend.rti; |
1209 // TODO(karlklose): support typedefs with variables. | 1251 // TODO(karlklose): support typedefs with variables. |
1210 jsAst.Expression expression; | 1252 jsAst.Expression expression; |
1211 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); | 1253 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); |
1212 if (other.kind == ElementKind.CLASS) { | 1254 if (other.kind == ElementKind.CLASS) { |
1213 String substitution = rti.getSupertypeSubstitution(classElement, other, | 1255 String substitution = rti.getSupertypeSubstitution(classElement, other, |
1214 alwaysGenerateFunction: true); | 1256 alwaysGenerateFunction: true); |
1215 if (substitution != null) { | 1257 if (substitution != null) { |
1216 expression = new jsAst.LiteralExpression(substitution); | 1258 expression = new jsAst.LiteralExpression(substitution); |
1217 } else if (emitNull || needsNativeCheck) { | 1259 } else if (emitNull || needsNativeCheck) { |
1218 expression = new jsAst.LiteralNull(); | 1260 expression = new jsAst.LiteralNull(); |
1219 } | 1261 } |
1220 } | 1262 } |
1221 if (expression != null) { | 1263 if (expression != null) { |
1222 if (needsNativeCheck) { | 1264 if (needsNativeCheck) { |
1223 expression = js.fun([], js.return_(expression)); | 1265 expression = js.fun([], js.return_(expression)); |
1224 } | 1266 } |
1225 builder.addProperty(namer.substitutionName(other), expression); | 1267 builder.addProperty(namer.substitutionName(other), expression); |
1226 } | 1268 } |
1227 } | 1269 } |
1228 | 1270 |
1229 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); | 1271 generateIsTestsOn(classElement, generateIsTest, |
1272 generateIsFunctionTypeTest, generateFunctionTypeSignature, | |
1273 generateSubstitution); | |
1230 | 1274 |
1231 if (identical(classElement, compiler.objectClass) | 1275 if (identical(classElement, compiler.objectClass) |
1232 && compiler.enabledNoSuchMethod) { | 1276 && compiler.enabledNoSuchMethod) { |
1233 // Emit the noSuchMethod handlers on the Object prototype now, | 1277 // Emit the noSuchMethod handlers on the Object prototype now, |
1234 // so that the code in the dynamicFunction helper can find | 1278 // so that the code in the dynamicFunction helper can find |
1235 // them. Note that this helper is invoked before analyzing the | 1279 // them. Note that this helper is invoked before analyzing the |
1236 // full JS script. | 1280 // full JS script. |
1237 if (!nativeEmitter.handleNoSuchMethod) { | 1281 if (!nativeEmitter.handleNoSuchMethod) { |
1238 emitNoSuchMethodHandlers(builder.addProperty); | 1282 emitNoSuchMethodHandlers(builder.addProperty); |
1239 } | 1283 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1273 } | 1317 } |
1274 | 1318 |
1275 // Add checks to the constructors of instantiated classes or to the created | 1319 // Add checks to the constructors of instantiated classes or to the created |
1276 // holder object. | 1320 // holder object. |
1277 for (ClassElement cls in typeChecks) { | 1321 for (ClassElement cls in typeChecks) { |
1278 String holder = namer.isolateAccess(cls); | 1322 String holder = namer.isolateAccess(cls); |
1279 for (ClassElement check in typeChecks[cls]) { | 1323 for (ClassElement check in typeChecks[cls]) { |
1280 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); | 1324 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); |
1281 String body = rti.getSupertypeSubstitution(cls, check); | 1325 String body = rti.getSupertypeSubstitution(cls, check); |
1282 if (body != null) { | 1326 if (body != null) { |
1283 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ; | 1327 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ; |
karlklose
2013/03/22 13:17:46
Long line.
Johnni Winther
2013/06/21 12:19:14
Stale.
| |
1284 } | 1328 } |
1285 }; | 1329 }; |
1286 } | 1330 } |
1331 | |
1332 checkedNonGenericFunctionTypes.forEach((FunctionType type) { | |
1333 String encoding = rti.getTypeEncoding(type); | |
1334 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N'); | |
1335 }); | |
1336 | |
1337 checkedGenericFunctionTypes.forEach( | |
1338 (ClassElement cls, Set<FunctionType> functionTypes) { | |
1339 for (FunctionType type in functionTypes) { | |
karlklose
2013/03/22 13:17:46
I would indent the body of the function by two spa
Johnni Winther
2013/06/21 12:19:14
Stale.
| |
1340 ClassElement contextClass = Types.getClassContext(type); | |
1341 if (contextClass != null) { | |
1342 maybeGenerateHolder(contextClass); | |
1343 } | |
1344 String encoding = rti.getTypeEncoding(type); | |
1345 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N'); | |
1346 } | |
1347 }); | |
1287 } | 1348 } |
1288 | 1349 |
1289 void visitNativeMixins(ClassElement classElement, | 1350 void visitNativeMixins(ClassElement classElement, |
1290 void visit(MixinApplicationElement mixinApplication)) { | 1351 void visit(MixinApplicationElement mixinApplication)) { |
1291 if (!classElement.isNative()) return; | 1352 if (!classElement.isNative()) return; |
1292 // Use recursion to make sure to visit the superclasses before the | 1353 // Use recursion to make sure to visit the superclasses before the |
1293 // subclasses. Once we start keeping track of the emitted fields | 1354 // subclasses. Once we start keeping track of the emitted fields |
1294 // and members, we're going to want to visit these in the other | 1355 // and members, we're going to want to visit these in the other |
1295 // order so we get the most specialized definition first. | 1356 // order so we get the most specialized definition first. |
1296 void recurse(ClassElement cls) { | 1357 void recurse(ClassElement cls) { |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1439 ClassBuilder builder) { | 1500 ClassBuilder builder) { |
1440 assert(canGenerateCheckedSetter(member)); | 1501 assert(canGenerateCheckedSetter(member)); |
1441 DartType type = member.computeType(compiler); | 1502 DartType type = member.computeType(compiler); |
1442 // TODO(ahe): Generate a dynamic type error here. | 1503 // TODO(ahe): Generate a dynamic type error here. |
1443 if (type.element.isErroneous()) return; | 1504 if (type.element.isErroneous()) return; |
1444 FunctionElement helperElement | 1505 FunctionElement helperElement |
1445 = backend.getCheckedModeHelper(type, typeCast: false); | 1506 = backend.getCheckedModeHelper(type, typeCast: false); |
1446 String helperName = namer.isolateAccess(helperElement); | 1507 String helperName = namer.isolateAccess(helperElement); |
1447 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; | 1508 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; |
1448 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 1509 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
1449 arguments.add(js.string(namer.operatorIs(type.element))); | 1510 arguments.add(js.string(namer.operatorIsType(type))); |
1450 } | 1511 } |
1451 | 1512 |
1452 String setterName = namer.setterNameFromAccessorName(accessorName); | 1513 String setterName = namer.setterNameFromAccessorName(accessorName); |
1453 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1514 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) |
1454 ? 'receiver' : 'this'; | 1515 ? 'receiver' : 'this'; |
1455 List<String> args = backend.isInterceptedMethod(member) | 1516 List<String> args = backend.isInterceptedMethod(member) |
1456 ? ['receiver', 'v'] | 1517 ? ['receiver', 'v'] |
1457 : ['v']; | 1518 : ['v']; |
1458 builder.addProperty(setterName, | 1519 builder.addProperty(setterName, |
1459 js.fun(args, | 1520 js.fun(args, |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1616 return arity; | 1677 return arity; |
1617 } | 1678 } |
1618 | 1679 |
1619 int _compareSelectorNames(Selector selector1, Selector selector2) { | 1680 int _compareSelectorNames(Selector selector1, Selector selector2) { |
1620 String name1 = selector1.name.toString(); | 1681 String name1 = selector1.name.toString(); |
1621 String name2 = selector2.name.toString(); | 1682 String name2 = selector2.name.toString(); |
1622 if (name1 != name2) return Comparable.compare(name1, name2); | 1683 if (name1 != name2) return Comparable.compare(name1, name2); |
1623 return _selectorRank(selector1) - _selectorRank(selector2); | 1684 return _selectorRank(selector1) - _selectorRank(selector2); |
1624 } | 1685 } |
1625 | 1686 |
1626 Iterable<Element> getTypedefChecksOn(DartType type) { | 1687 /** |
1627 bool isSubtype(TypedefElement typedef) { | 1688 * Returns a mapping containing all checked function types for which [type] |
1628 FunctionType typedefType = | 1689 * can be a subtype. A function type is mapped to [:true:] if [type] is |
1629 typedef.computeType(compiler).unalias(compiler); | 1690 * statically known to be a subtype of it. |
karlklose
2013/03/22 13:17:46
Explain what being false means.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
1630 return compiler.types.isSubtype(type, typedefType); | 1691 */ |
1692 // TODO(johnniwinther): Change to return a mapping from function types to | |
1693 // a set of variable points and use this to detect statically/dynamically | |
1694 // known subtype relations. | |
1695 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) { | |
1696 Map<FunctionType, bool> functionTypeMap = | |
1697 new LinkedHashMap<FunctionType, bool>(); | |
1698 for (FunctionType functionType in checkedFunctionTypes) { | |
1699 if (compiler.types.isSubtype(type, functionType)) { | |
1700 functionTypeMap[functionType] = true; | |
1701 } else if (compiler.types.isPotentialSubtype(type, functionType)) { | |
1702 functionTypeMap[functionType] = false; | |
1703 } | |
1631 } | 1704 } |
1632 return checkedTypedefs.where(isSubtype).toList() | 1705 // TODO(johnniwinther): Ensure stable ordering of the keys. |
1633 ..sort(Elements.compareByPosition); | 1706 return functionTypeMap; |
1634 } | 1707 } |
1635 | 1708 |
1636 /** | 1709 /** |
1637 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1710 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
1638 * classes it implements and type argument substitution functions for these | 1711 * classes it implements and type argument substitution functions for these |
1639 * tests. We don't need to add the "is tests" of the super class because | 1712 * tests. We don't need to add the "is tests" of the super class because |
1640 * they will be inherited at runtime, but we may need to generate the | 1713 * they will be inherited at runtime, but we may need to generate the |
1641 * substitutions, because they may have changed. | 1714 * substitutions, because they may have changed. |
1642 */ | 1715 */ |
1643 void generateIsTestsOn(ClassElement cls, | 1716 void generateIsTestsOn(ClassElement cls, |
1644 void emitIsTest(Element element), | 1717 void emitIsTest(Element element), |
1718 void emitIsFunctionTypeTest(FunctionType type), | |
1719 void emitFunctionTypeSignature(Element method, Function Type type), | |
karlklose
2013/03/22 13:17:46
Long line.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
1645 void emitSubstitution(Element element, {emitNull})) { | 1720 void emitSubstitution(Element element, {emitNull})) { |
1646 if (checkedClasses.contains(cls)) { | 1721 if (checkedClasses.contains(cls)) { |
1647 emitIsTest(cls); | 1722 emitIsTest(cls); |
1648 emitSubstitution(cls); | 1723 emitSubstitution(cls); |
1649 } | 1724 } |
1650 | 1725 |
1651 RuntimeTypes rti = backend.rti; | 1726 RuntimeTypes rti = backend.rti; |
1652 ClassElement superclass = cls.superclass; | 1727 ClassElement superclass = cls.superclass; |
1653 | 1728 |
1654 bool haveSameTypeVariables(ClassElement a, ClassElement b) { | 1729 bool haveSameTypeVariables(ClassElement a, ClassElement b) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1686 } | 1761 } |
1687 } | 1762 } |
1688 void emitNothing(_, {emitNull}) {}; | 1763 void emitNothing(_, {emitNull}) {}; |
1689 emitSubstitution = emitNothing; | 1764 emitSubstitution = emitNothing; |
1690 } | 1765 } |
1691 | 1766 |
1692 Set<Element> generated = new Set<Element>(); | 1767 Set<Element> generated = new Set<Element>(); |
1693 // A class that defines a [:call:] method implicitly implements | 1768 // A class that defines a [:call:] method implicitly implements |
1694 // [Function] and needs checks for all typedefs that are used in is-checks. | 1769 // [Function] and needs checks for all typedefs that are used in is-checks. |
1695 if (checkedClasses.contains(compiler.functionClass) || | 1770 if (checkedClasses.contains(compiler.functionClass) || |
1696 !checkedTypedefs.isEmpty) { | 1771 !checkedFunctionTypes.isEmpty) { |
1697 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1772 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
1698 if (call == null) { | 1773 if (call == null) { |
1699 // If [cls] is a closure, it has a synthetic call operator method. | 1774 // If [cls] is a closure, it has a synthetic call operator method. |
1700 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1775 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
1701 } | 1776 } |
1702 if (call != null) { | 1777 if (call != null) { |
1703 generateInterfacesIsTests(compiler.functionClass, | 1778 generateInterfacesIsTests(compiler.functionClass, |
1704 emitIsTest, | 1779 emitIsTest, |
1705 emitSubstitution, | 1780 emitSubstitution, |
1706 generated); | 1781 generated); |
1707 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1782 FunctionType callType = call.computeType(compiler); |
1708 } | 1783 generateFunctionTypeTests(call, callType, |
1784 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
1785 } | |
1709 } | 1786 } |
1710 | 1787 |
1711 for (DartType interfaceType in cls.interfaces) { | 1788 for (DartType interfaceType in cls.interfaces) { |
1712 generateInterfacesIsTests(interfaceType.element, emitIsTest, | 1789 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
1713 emitSubstitution, generated); | 1790 emitSubstitution, generated); |
1714 } | 1791 } |
1715 | 1792 |
1716 // For native classes, we also have to run through their mixin | 1793 // For native classes, we also have to run through their mixin |
1717 // applications and make sure we deal with 'is' tests correctly | 1794 // applications and make sure we deal with 'is' tests correctly |
1718 // for those. | 1795 // for those. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1751 | 1828 |
1752 // We need to also emit "is checks" for the superclass and its supertypes. | 1829 // We need to also emit "is checks" for the superclass and its supertypes. |
1753 ClassElement superclass = cls.superclass; | 1830 ClassElement superclass = cls.superclass; |
1754 if (superclass != null) { | 1831 if (superclass != null) { |
1755 tryEmitTest(superclass); | 1832 tryEmitTest(superclass); |
1756 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, | 1833 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
1757 alreadyGenerated); | 1834 alreadyGenerated); |
1758 } | 1835 } |
1759 } | 1836 } |
1760 | 1837 |
1838 void generateFunctionTypeTests( | |
1839 Element method, | |
1840 FunctionType methodType, | |
1841 void emitFunctionTypeSignature(Element method, FunctionType methodType), | |
1842 void emitIsFunctionTypeTest(FunctionType functionType)) { | |
1843 Map<FunctionType, bool> functionTypeChecks = | |
1844 getFunctionTypeChecksOn(methodType); | |
1845 generateFunctionTypeTestsInternal(method, methodType, functionTypeChecks, | |
1846 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
1847 } | |
1848 | |
1849 const int MAX_FUNCTION_TYPE_PREDICATES = 10; | |
1850 | |
1851 void generateFunctionTypeTestsInternal( | |
1852 Element method, | |
1853 FunctionType methodType, | |
1854 Map<FunctionType, bool> functionTypeChecks, | |
1855 void emitFunctionTypeSignature(Element method, FunctionType methodType), | |
1856 void emitIsFunctionTypeTest(FunctionType functionType)) { | |
1857 bool hasDynamicFunctionTypeCheck = false; | |
1858 int neededPredicates = 0; | |
1859 functionTypeChecks.forEach((FunctionType functionType, | |
1860 bool knownSubtype) { | |
karlklose
2013/03/22 13:17:46
Align with '(FunctionType...'.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
1861 if (!knownSubtype) { | |
1862 registerDynamicFunctionTypeCheck(functionType); | |
karlklose
2013/03/22 13:17:46
Why are we registering it in the emitter. Shouldn'
Johnni Winther
2013/06/21 12:19:14
Which function type check that are dynamic depends
| |
1863 hasDynamicFunctionTypeCheck = true; | |
1864 } else { | |
1865 neededPredicates++; | |
1866 } | |
1867 }); | |
1868 bool hasSignature = false; | |
karlklose
2013/03/22 13:17:46
'signatureEmitted'?
Johnni Winther
2013/06/21 12:19:14
Done.
| |
1869 if (hasDynamicFunctionTypeCheck || | |
1870 neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) { | |
1871 emitFunctionTypeSignature(method, methodType); | |
1872 hasSignature = true; | |
1873 } | |
1874 functionTypeChecks.forEach((FunctionType functionType, | |
1875 bool knownSubtype) { | |
karlklose
2013/03/22 13:17:46
Align.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
1876 if (knownSubtype || !hasDynamicFunctionTypeCheck) { | |
1877 if (hasSignature) { | |
1878 registerDynamicFunctionTypeCheck(functionType); | |
1879 } else { | |
1880 emitIsFunctionTypeTest(functionType); | |
1881 } | |
1882 } | |
1883 }); | |
1884 } | |
1885 | |
1761 /** | 1886 /** |
1762 * Return a function that returns true if its argument is a class | 1887 * Return a function that returns true if its argument is a class |
1763 * that needs to be emitted. | 1888 * that needs to be emitted. |
1764 */ | 1889 */ |
1765 Function computeClassFilter() { | 1890 Function computeClassFilter() { |
1766 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 1891 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
1767 // The [Bool] class is not marked as abstract, but has a factory | 1892 // The [Bool] class is not marked as abstract, but has a factory |
1768 // constructor that always throws. We never need to emit it. | 1893 // constructor that always throws. We never need to emit it. |
1769 unneededClasses.add(compiler.boolClass); | 1894 unneededClasses.add(compiler.boolClass); |
1770 | 1895 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1880 jsAst.Expression assignment = | 2005 jsAst.Expression assignment = |
1881 js[isolateProperties][staticName][name].assign(value); | 2006 js[isolateProperties][staticName][name].assign(value); |
1882 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); | 2007 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); |
1883 buffer.write('$N'); | 2008 buffer.write('$N'); |
1884 }); | 2009 }); |
1885 | 2010 |
1886 // If a static function is used as a closure we need to add its name | 2011 // If a static function is used as a closure we need to add its name |
1887 // in case it is used in spawnFunction. | 2012 // in case it is used in spawnFunction. |
1888 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 2013 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
1889 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); | 2014 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); |
1890 getTypedefChecksOn(element.computeType(compiler)).forEach( | 2015 |
1891 (Element typedef) { | 2016 void emitFunctionTypeSignature(Element method, FunctionType methodType) { |
1892 String operator = namer.operatorIs(typedef); | 2017 RuntimeTypes rti = backend.rti; |
1893 buffer.write('$fieldAccess.$operator$_=${_}true$N'); | 2018 String encoding = rti.getSignatureEncoding(methodType, () => 'null'); |
karlklose
2013/03/22 13:17:46
Please explain what null means here.
Johnni Winther
2013/06/21 12:19:14
Done.
| |
1894 } | 2019 String operatorSignature = namer.operatorSignature(); |
1895 ); | 2020 buffer.add('$fieldAccess.$operatorSignature$_=${_}$encoding$N'); |
2021 } | |
2022 | |
2023 void emitIsFunctionTypeTest(FunctionType functionType) { | |
2024 String operator = namer.operatorIsType(functionType); | |
2025 buffer.write('$fieldAccess.$operator$_=${_}true$N'); | |
2026 } | |
2027 | |
2028 generateFunctionTypeTests(element, element.computeType(compiler), | |
2029 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
1896 } | 2030 } |
1897 } | 2031 } |
1898 | 2032 |
1899 void emitBoundClosureClassHeader(String mangledName, | 2033 void emitBoundClosureClassHeader(String mangledName, |
1900 String superName, | 2034 String superName, |
1901 List<String> fieldNames, | 2035 List<String> fieldNames, |
1902 ClassBuilder builder) { | 2036 ClassBuilder builder) { |
1903 builder.addProperty('', | 2037 builder.addProperty('', |
1904 js.string("$superName;${fieldNames.join(',')}")); | 2038 js.string("$superName;${fieldNames.join(',')}")); |
1905 } | 2039 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1946 extraArg = 'receiver'; | 2080 extraArg = 'receiver'; |
1947 } else { | 2081 } else { |
1948 cache = boundClosureCache; | 2082 cache = boundClosureCache; |
1949 } | 2083 } |
1950 List<String> fieldNames = compiler.enableMinification | 2084 List<String> fieldNames = compiler.enableMinification |
1951 ? inInterceptor ? const ['a', 'b', 'c'] | 2085 ? inInterceptor ? const ['a', 'b', 'c'] |
1952 : const ['a', 'b'] | 2086 : const ['a', 'b'] |
1953 : inInterceptor ? const ['self', 'target', 'receiver'] | 2087 : inInterceptor ? const ['self', 'target', 'receiver'] |
1954 : const ['self', 'target']; | 2088 : const ['self', 'target']; |
1955 | 2089 |
1956 Iterable<Element> typedefChecks = | 2090 DartType memberType = member.computeType(compiler); |
1957 getTypedefChecksOn(member.computeType(compiler)); | 2091 Map<FunctionType, bool> functionTypeChecks = |
1958 bool hasTypedefChecks = !typedefChecks.isEmpty; | 2092 getFunctionTypeChecksOn(memberType); |
2093 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty; | |
1959 | 2094 |
1960 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; | 2095 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks; |
1961 | 2096 |
2097 ClassElement classElement = member.getEnclosingClass(); | |
1962 String closureClass = canBeShared ? cache[parameterCount] : null; | 2098 String closureClass = canBeShared ? cache[parameterCount] : null; |
1963 if (closureClass == null) { | 2099 if (closureClass == null) { |
1964 // Either the class was not cached yet, or there are optional parameters. | 2100 // Either the class was not cached yet, or there are optional parameters. |
1965 // Create a new closure class. | 2101 // Create a new closure class. |
1966 String name; | 2102 String name; |
1967 if (canBeShared) { | 2103 if (canBeShared) { |
1968 if (inInterceptor) { | 2104 if (inInterceptor) { |
1969 name = 'BoundClosure\$i${parameterCount}'; | 2105 name = 'BoundClosure\$i${parameterCount}'; |
1970 } else { | 2106 } else { |
1971 name = 'BoundClosure\$${parameterCount}'; | 2107 name = 'BoundClosure\$${parameterCount}'; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2008 arguments.add(js[name]); | 2144 arguments.add(js[name]); |
2009 } | 2145 } |
2010 | 2146 |
2011 jsAst.Expression fun = js.fun( | 2147 jsAst.Expression fun = js.fun( |
2012 parameters, | 2148 parameters, |
2013 js.return_( | 2149 js.return_( |
2014 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments))); | 2150 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments))); |
2015 boundClosureBuilder.addProperty(invocationName, fun); | 2151 boundClosureBuilder.addProperty(invocationName, fun); |
2016 | 2152 |
2017 addParameterStubs(callElement, boundClosureBuilder.addProperty); | 2153 addParameterStubs(callElement, boundClosureBuilder.addProperty); |
2018 typedefChecks.forEach((Element typedef) { | 2154 |
2019 String operator = namer.operatorIs(typedef); | 2155 void emitFunctionTypeSignature(Element method, FunctionType methodType) { |
2020 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true)); | 2156 RuntimeTypes rti = backend.rti; |
2021 }); | 2157 String encoding = rti.getSignatureEncoding( |
2158 methodType, () => 'this.${fieldNames[0]}'); | |
2159 String operatorSignature = namer.operatorSignature(); | |
2160 boundClosureBuilder.addProperty(operatorSignature, | |
2161 new jsAst.LiteralExpression(encoding)); | |
2162 } | |
2163 | |
2164 void emitIsFunctionTypeTest(FunctionType functionType) { | |
2165 String operator = namer.operatorIsType(functionType); | |
2166 boundClosureBuilder.addProperty(operator, | |
2167 new jsAst.LiteralBool(true)); | |
2168 } | |
2169 | |
2170 generateFunctionTypeTestsInternal(member, memberType, functionTypeChecks, | |
2171 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
2022 | 2172 |
2023 boundClosures.add( | 2173 boundClosures.add( |
2024 js[classesCollector][mangledName].assign( | 2174 js[classesCollector][mangledName].assign( |
2025 boundClosureBuilder.toObjectInitializer())); | 2175 boundClosureBuilder.toObjectInitializer())); |
2026 | 2176 |
2027 closureClass = namer.isolateAccess(closureClassElement); | 2177 closureClass = namer.isolateAccess(closureClassElement); |
2028 | 2178 |
2029 // Cache it. | 2179 // Cache it. |
2030 if (canBeShared) { | 2180 if (canBeShared) { |
2031 cache[parameterCount] = closureClass; | 2181 cache[parameterCount] = closureClass; |
2032 } | 2182 } |
2033 } | 2183 } |
2034 | 2184 |
2035 // And finally the getter. | 2185 // And finally the getter. |
2036 String getterName = namer.getterName(member); | 2186 String getterName = namer.getterName(member); |
2037 String targetName = namer.instanceMethodName(member); | 2187 String targetName = namer.instanceMethodName(member); |
2038 | 2188 |
2039 List<String> parameters = <String>[]; | 2189 List<String> parameters = <String>[]; |
2040 List<jsAst.Expression> arguments = <jsAst.Expression>[]; | 2190 List<jsAst.Expression> arguments = <jsAst.Expression>[]; |
2041 arguments.add(js['this']); | 2191 arguments.add(js['this']); |
2042 arguments.add(js.string(targetName)); | 2192 arguments.add(js.string(targetName)); |
2043 if (inInterceptor) { | 2193 if (inInterceptor) { |
2044 parameters.add(extraArg); | 2194 parameters.add(extraArg); |
2045 arguments.add(js[extraArg]); | 2195 arguments.add(js[extraArg]); |
2046 } | 2196 } |
2047 | 2197 |
2198 jsAst.Expression newClosure = js[closureClass].newWith(arguments); | |
2048 jsAst.Expression getterFunction = js.fun( | 2199 jsAst.Expression getterFunction = js.fun( |
2049 parameters, | 2200 parameters, js.return_(newClosure)); |
2050 js.return_(js[closureClass].newWith(arguments))); | |
2051 | 2201 |
2052 defineStub(getterName, getterFunction); | 2202 defineStub(getterName, getterFunction); |
2053 } | 2203 } |
2054 | 2204 |
2055 /** | 2205 /** |
2056 * Documentation wanted -- johnniwinther | 2206 * Documentation wanted -- johnniwinther |
2057 * | 2207 * |
2058 * Invariant: [member] must be a declaration element. | 2208 * Invariant: [member] must be a declaration element. |
2059 */ | 2209 */ |
2060 void emitCallStubForGetter(Element member, | 2210 void emitCallStubForGetter(Element member, |
(...skipping 19 matching lines...) Expand all Loading... | |
2080 ? member.fixedBackendName() | 2230 ? member.fixedBackendName() |
2081 : namer.instanceFieldName(member); | 2231 : namer.instanceFieldName(member); |
2082 return js['this'][fieldName]; | 2232 return js['this'][fieldName]; |
2083 } | 2233 } |
2084 } | 2234 } |
2085 | 2235 |
2086 // Two selectors may match but differ only in type. To avoid generating | 2236 // Two selectors may match but differ only in type. To avoid generating |
2087 // identical stubs for each we track untyped selectors which already have | 2237 // identical stubs for each we track untyped selectors which already have |
2088 // stubs. | 2238 // stubs. |
2089 Set<Selector> generatedSelectors = new Set<Selector>(); | 2239 Set<Selector> generatedSelectors = new Set<Selector>(); |
2090 | 2240 DartType memberType = member.computeType(compiler); |
2091 for (Selector selector in selectors) { | 2241 for (Selector selector in selectors) { |
2092 if (selector.applies(member, compiler)) { | 2242 if (selector.applies(member, compiler)) { |
2093 selector = selector.asUntyped; | 2243 selector = selector.asUntyped; |
2094 if (generatedSelectors.contains(selector)) continue; | 2244 if (generatedSelectors.contains(selector)) continue; |
2095 generatedSelectors.add(selector); | 2245 generatedSelectors.add(selector); |
2096 | 2246 |
2097 String invocationName = namer.invocationName(selector); | 2247 String invocationName = namer.invocationName(selector); |
2098 Selector callSelector = new Selector.callClosureFrom(selector); | 2248 Selector callSelector = new Selector.callClosureFrom(selector); |
2099 String closureCallName = namer.invocationName(callSelector); | 2249 String closureCallName = namer.invocationName(callSelector); |
2100 | 2250 |
(...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3058 """; | 3208 """; |
3059 const String HOOKS_API_USAGE = """ | 3209 const String HOOKS_API_USAGE = """ |
3060 // The code supports the following hooks: | 3210 // The code supports the following hooks: |
3061 // dartPrint(message) - if this function is defined it is called | 3211 // dartPrint(message) - if this function is defined it is called |
3062 // instead of the Dart [print] method. | 3212 // instead of the Dart [print] method. |
3063 // dartMainRunner(main) - if this function is defined, the Dart [main] | 3213 // dartMainRunner(main) - if this function is defined, the Dart [main] |
3064 // method will not be invoked directly. | 3214 // method will not be invoked directly. |
3065 // Instead, a closure that will invoke [main] is | 3215 // Instead, a closure that will invoke [main] is |
3066 // passed to [dartMainRunner]. | 3216 // passed to [dartMainRunner]. |
3067 """; | 3217 """; |
OLD | NEW |