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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
103 | 103 |
104 /** | 104 /** |
105 * Raw ClassElement symbols occuring in is-checks and type assertions. If the | 105 * Raw ClassElement symbols occuring in is-checks and type assertions. If the |
106 * program contains parameterized checks `x is Set<int>` and | 106 * program contains parameterized checks `x is Set<int>` and |
107 * `x is Set<String>` then the ClassElement `Set` will occur once in | 107 * `x is Set<String>` then the ClassElement `Set` will occur once in |
108 * [checkedClasses]. | 108 * [checkedClasses]. |
109 */ | 109 */ |
110 Set<ClassElement> checkedClasses; | 110 Set<ClassElement> checkedClasses; |
111 | 111 |
112 /** | 112 /** |
113 * Raw Typedef symbols occuring in is-checks and type assertions. If the | 113 * Raw Typedef symbols occuring in is-checks and type assertions. If the |
karlklose
2013/06/19 14:37:05
Please update the comment.
Johnni Winther
2013/06/21 12:19:15
Done.
| |
114 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement | 114 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement |
115 * `F` will occur once in [checkedTypedefs]. | 115 * `F` will occur once in [checkedTypedefs]. |
116 */ | 116 */ |
117 Set<TypedefElement> checkedTypedefs; | 117 Set<FunctionType> checkedFunctionTypes; |
118 | |
119 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes | |
120 = new Map<ClassElement, Set<FunctionType>>(); | |
121 | |
122 Set<FunctionType> checkedNonGenericFunctionTypes | |
123 = new Set<FunctionType>(); | |
124 | |
125 void registerDynamicFunctionTypeCheck(FunctionType functionType) { | |
126 ClassElement classElement = Types.getClassContext(functionType); | |
127 if (classElement != null) { | |
128 checkedGenericFunctionTypes.putIfAbsent(classElement, | |
129 () => new Set<FunctionType>()).add(functionType); | |
130 } else { | |
131 checkedNonGenericFunctionTypes.add(functionType); | |
132 } | |
133 } | |
118 | 134 |
119 final bool generateSourceMap; | 135 final bool generateSourceMap; |
120 | 136 |
121 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; | 137 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; |
122 | 138 |
123 Iterable<ClassElement> get classesUsingTypeVariableTests { | 139 Iterable<ClassElement> get classesUsingTypeVariableTests { |
124 if (cachedClassesUsingTypeVariableTests == null) { | 140 if (cachedClassesUsingTypeVariableTests == null) { |
125 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks | 141 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks |
126 .where((DartType t) => t is TypeVariableType) | 142 .where((DartType t) => t is TypeVariableType) |
127 .map((TypeVariableType v) => v.element.getEnclosingClass()) | 143 .map((TypeVariableType v) => v.element.getEnclosingClass()) |
(...skipping 10 matching lines...) Expand all Loading... | |
138 constantEmitter = new ConstantEmitter(compiler, namer), | 154 constantEmitter = new ConstantEmitter(compiler, namer), |
139 super(compiler) { | 155 super(compiler) { |
140 nativeEmitter = new NativeEmitter(this); | 156 nativeEmitter = new NativeEmitter(this); |
141 } | 157 } |
142 | 158 |
143 void addComment(String comment, CodeBuffer buffer) { | 159 void addComment(String comment, CodeBuffer buffer) { |
144 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); | 160 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); |
145 } | 161 } |
146 | 162 |
147 void computeRequiredTypeChecks() { | 163 void computeRequiredTypeChecks() { |
148 assert(checkedClasses == null && checkedTypedefs == null); | 164 assert(checkedClasses == null && checkedFunctionTypes == null); |
149 | 165 |
150 backend.rti.addImplicitChecks(compiler.codegenWorld, | 166 backend.rti.addImplicitChecks(compiler.codegenWorld, |
151 classesUsingTypeVariableTests); | 167 classesUsingTypeVariableTests); |
152 | 168 |
153 checkedClasses = new Set<ClassElement>(); | 169 checkedClasses = new Set<ClassElement>(); |
154 checkedTypedefs = new Set<TypedefElement>(); | 170 checkedFunctionTypes = new Set<FunctionType>(); |
155 compiler.codegenWorld.isChecks.forEach((DartType t) { | 171 compiler.codegenWorld.isChecks.forEach((DartType t) { |
156 if (t is InterfaceType) { | 172 if (!t.isMalformed) { |
157 checkedClasses.add(t.element); | 173 if (t is InterfaceType) { |
158 } else if (t is TypedefType) { | 174 checkedClasses.add(t.element); |
159 checkedTypedefs.add(t.element); | 175 } else if (t is FunctionType) { |
176 checkedFunctionTypes.add(t); | |
177 } | |
160 } | 178 } |
161 }); | 179 }); |
162 } | 180 } |
163 | 181 |
164 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) { | 182 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) { |
165 ClassElement mixin = mixinApplication.mixin; | 183 ClassElement mixin = mixinApplication.mixin; |
166 while (mixin.isMixinApplication) { | 184 while (mixin.isMixinApplication) { |
167 mixinApplication = mixin; | 185 mixinApplication = mixin; |
168 mixin = mixinApplication.mixin; | 186 mixin = mixinApplication.mixin; |
169 } | 187 } |
(...skipping 1086 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1256 | 1274 |
1257 void generateIsTest(Element other) { | 1275 void generateIsTest(Element other) { |
1258 if (other == compiler.objectClass && other != classElement) { | 1276 if (other == compiler.objectClass && other != classElement) { |
1259 // Avoid emitting [:$isObject:] on all classes but [Object]. | 1277 // Avoid emitting [:$isObject:] on all classes but [Object]. |
1260 return; | 1278 return; |
1261 } | 1279 } |
1262 other = backend.getImplementationClass(other); | 1280 other = backend.getImplementationClass(other); |
1263 builder.addProperty(namer.operatorIs(other), js('true')); | 1281 builder.addProperty(namer.operatorIs(other), js('true')); |
1264 } | 1282 } |
1265 | 1283 |
1284 void generateIsFunctionTypeTest(FunctionType type) { | |
1285 String operator = namer.operatorIsType(type); | |
1286 builder.addProperty(operator, new jsAst.LiteralBool(true)); | |
1287 } | |
1288 | |
1289 void generateFunctionTypeSignature(Element method, FunctionType type) { | |
1290 assert(method.isImplementation); | |
1291 String thisAccess = 'this'; | |
1292 Node node = method.parseNode(compiler); | |
1293 ClosureClassMap closureData = | |
1294 compiler.closureToClassMapper.closureMappingCache[node]; | |
1295 if (closureData != null) { | |
1296 Element thisElement = | |
1297 closureData.freeVariableMapping[closureData.thisElement]; | |
1298 if (thisElement != null) { | |
1299 String thisName = backend.namer.getName(thisElement); | |
1300 thisAccess = 'this.$thisName'; | |
1301 } | |
1302 } | |
1303 RuntimeTypes rti = backend.rti; | |
1304 String encoding = rti.getSignatureEncoding(type, () => '$thisAccess'); | |
1305 String operatorSignature = namer.operatorSignature(); | |
1306 builder.addProperty(operatorSignature, | |
1307 new jsAst.LiteralExpression(encoding)); | |
1308 } | |
1309 | |
1266 void generateSubstitution(Element other, {bool emitNull: false}) { | 1310 void generateSubstitution(Element other, {bool emitNull: false}) { |
1267 RuntimeTypes rti = backend.rti; | 1311 RuntimeTypes rti = backend.rti; |
1268 // TODO(karlklose): support typedefs with variables. | 1312 // TODO(karlklose): support typedefs with variables. |
karlklose
2013/06/19 14:37:05
This TODO is obsolete now, isn't it?
Johnni Winther
2013/06/21 12:19:15
Yes. Removed.
| |
1269 jsAst.Expression expression; | 1313 jsAst.Expression expression; |
1270 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); | 1314 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); |
1271 if (other.kind == ElementKind.CLASS) { | 1315 if (other.kind == ElementKind.CLASS) { |
1272 String substitution = rti.getSupertypeSubstitution(classElement, other, | 1316 String substitution = rti.getSupertypeSubstitution(classElement, other, |
1273 alwaysGenerateFunction: true); | 1317 alwaysGenerateFunction: true); |
1274 if (substitution != null) { | 1318 if (substitution != null) { |
1275 expression = new jsAst.LiteralExpression(substitution); | 1319 expression = new jsAst.LiteralExpression(substitution); |
1276 } else if (emitNull || needsNativeCheck) { | 1320 } else if (emitNull || needsNativeCheck) { |
1277 expression = new jsAst.LiteralNull(); | 1321 expression = new jsAst.LiteralNull(); |
1278 } | 1322 } |
1279 } | 1323 } |
1280 if (expression != null) { | 1324 if (expression != null) { |
1281 builder.addProperty(namer.substitutionName(other), expression); | 1325 builder.addProperty(namer.substitutionName(other), expression); |
1282 } | 1326 } |
1283 } | 1327 } |
1284 | 1328 |
1285 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); | 1329 generateIsTestsOn(classElement, generateIsTest, |
1330 generateIsFunctionTypeTest, generateFunctionTypeSignature, | |
1331 generateSubstitution); | |
1286 } | 1332 } |
1287 | 1333 |
1288 void emitRuntimeTypeSupport(CodeBuffer buffer) { | 1334 void emitRuntimeTypeSupport(CodeBuffer buffer) { |
1289 RuntimeTypes rti = backend.rti; | 1335 RuntimeTypes rti = backend.rti; |
1290 TypeChecks typeChecks = rti.requiredChecks; | 1336 TypeChecks typeChecks = rti.requiredChecks; |
1291 | 1337 |
1292 // Add checks to the constructors of instantiated classes. | 1338 // Add checks to the constructors of instantiated classes. |
1293 for (ClassElement cls in typeChecks) { | 1339 for (ClassElement cls in typeChecks) { |
1294 String holder = namer.isolateAccess(backend.getImplementationClass(cls)); | 1340 String holder = namer.isolateAccess(backend.getImplementationClass(cls)); |
1295 for (TypeCheck check in typeChecks[cls]) { | 1341 for (TypeCheck check in typeChecks[cls]) { |
1296 ClassElement cls = check.cls; | 1342 ClassElement cls = check.cls; |
1297 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N'); | 1343 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N'); |
1298 Substitution substitution = check.substitution; | 1344 Substitution substitution = check.substitution; |
1299 if (substitution != null) { | 1345 if (substitution != null) { |
1300 String body = substitution.getCode(rti, false); | 1346 String body = substitution.getCode(rti, false); |
1301 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N'); | 1347 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N'); |
1302 } | 1348 } |
1303 }; | 1349 }; |
1304 } | 1350 } |
1351 | |
1352 checkedNonGenericFunctionTypes.forEach((FunctionType type) { | |
1353 String encoding = rti.getTypeEncoding(type); | |
karlklose
2013/06/19 14:37:05
Create a function addEncoding for l.1353-1354 and
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1354 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N'); | |
1355 }); | |
1356 | |
1357 checkedGenericFunctionTypes.forEach( | |
1358 (ClassElement cls, Set<FunctionType> functionTypes) { | |
karlklose
2013/06/19 14:37:05
If you replace 'ClassElement cls' with '_' I think
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1359 for (FunctionType type in functionTypes) { | |
1360 String encoding = rti.getTypeEncoding(type); | |
1361 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N'); | |
1362 } | |
1363 }); | |
1305 } | 1364 } |
1306 | 1365 |
1307 /** | 1366 /** |
1308 * Documentation wanted -- johnniwinther | 1367 * Documentation wanted -- johnniwinther |
1309 * | 1368 * |
1310 * Invariant: [classElement] must be a declaration element. | 1369 * Invariant: [classElement] must be a declaration element. |
1311 */ | 1370 */ |
1312 void visitClassFields(ClassElement classElement, | 1371 void visitClassFields(ClassElement classElement, |
1313 void addField(Element member, | 1372 void addField(Element member, |
1314 String name, | 1373 String name, |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1426 } | 1485 } |
1427 | 1486 |
1428 void generateCheckedSetter(Element member, | 1487 void generateCheckedSetter(Element member, |
1429 String fieldName, | 1488 String fieldName, |
1430 String accessorName, | 1489 String accessorName, |
1431 ClassBuilder builder) { | 1490 ClassBuilder builder) { |
1432 assert(canGenerateCheckedSetter(member)); | 1491 assert(canGenerateCheckedSetter(member)); |
1433 DartType type = member.computeType(compiler); | 1492 DartType type = member.computeType(compiler); |
1434 // TODO(ahe): Generate a dynamic type error here. | 1493 // TODO(ahe): Generate a dynamic type error here. |
1435 if (type.element.isErroneous()) return; | 1494 if (type.element.isErroneous()) return; |
1436 FunctionElement helperElement | 1495 type = type.unalias(compiler); |
1437 = backend.getCheckedModeHelper(type, typeCast: false); | 1496 CheckedModeHelper helper = |
1497 backend.getCheckedModeHelper(type, typeCast: false); | |
1498 FunctionElement helperElement = helper.getElement(compiler); | |
1438 String helperName = namer.isolateAccess(helperElement); | 1499 String helperName = namer.isolateAccess(helperElement); |
karlklose
2013/06/19 14:37:05
You can inline helperElement here (it would remove
Johnni Winther
2013/06/21 12:19:15
No. [helperElement] is used below.
| |
1439 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')]; | 1500 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')]; |
1440 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 1501 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
1441 arguments.add(js.string(namer.operatorIs(type.element))); | 1502 arguments.add(js.string(namer.operatorIsType(type))); |
1442 } | 1503 } |
1443 | 1504 |
1444 String setterName = namer.setterNameFromAccessorName(accessorName); | 1505 String setterName = namer.setterNameFromAccessorName(accessorName); |
1445 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) | 1506 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) |
1446 ? 'receiver' : 'this'; | 1507 ? 'receiver' : 'this'; |
1447 List<String> args = backend.isInterceptedMethod(member) | 1508 List<String> args = backend.isInterceptedMethod(member) |
1448 ? ['receiver', 'v'] | 1509 ? ['receiver', 'v'] |
1449 : ['v']; | 1510 : ['v']; |
1450 builder.addProperty(setterName, | 1511 builder.addProperty(setterName, |
1451 js.fun(args, | 1512 js.fun(args, |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1664 return arity; | 1725 return arity; |
1665 } | 1726 } |
1666 | 1727 |
1667 int _compareSelectorNames(Selector selector1, Selector selector2) { | 1728 int _compareSelectorNames(Selector selector1, Selector selector2) { |
1668 String name1 = selector1.name.toString(); | 1729 String name1 = selector1.name.toString(); |
1669 String name2 = selector2.name.toString(); | 1730 String name2 = selector2.name.toString(); |
1670 if (name1 != name2) return Comparable.compare(name1, name2); | 1731 if (name1 != name2) return Comparable.compare(name1, name2); |
1671 return _selectorRank(selector1) - _selectorRank(selector2); | 1732 return _selectorRank(selector1) - _selectorRank(selector2); |
1672 } | 1733 } |
1673 | 1734 |
1674 Iterable<Element> getTypedefChecksOn(DartType type) { | 1735 /** |
1675 bool isSubtype(TypedefElement typedef) { | 1736 * Returns a mapping containing all checked function types for which [type] |
1676 FunctionType typedefType = | 1737 * can be a subtype. A function type is mapped to [:true:] if [type] is |
1677 typedef.computeType(compiler).unalias(compiler); | 1738 * statically known to be a subtype of it. |
1678 return compiler.types.isSubtype(type, typedefType); | 1739 */ |
1740 // TODO(johnniwinther): Change to return a mapping from function types to | |
1741 // a set of variable points and use this to detect statically/dynamically | |
1742 // known subtype relations. | |
1743 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) { | |
1744 Map<FunctionType, bool> functionTypeMap = | |
1745 new LinkedHashMap<FunctionType, bool>(); | |
1746 for (FunctionType functionType in checkedFunctionTypes) { | |
1747 if (compiler.types.isSubtype(type, functionType)) { | |
1748 functionTypeMap[functionType] = true; | |
1749 } else if (compiler.types.isPotentialSubtype(type, functionType)) { | |
1750 functionTypeMap[functionType] = false; | |
1751 } | |
1679 } | 1752 } |
1680 return checkedTypedefs.where(isSubtype).toList() | 1753 // TODO(johnniwinther): Ensure stable ordering of the keys. |
1681 ..sort(Elements.compareByPosition); | 1754 return functionTypeMap; |
1682 } | 1755 } |
1683 | 1756 |
1684 /** | 1757 /** |
1685 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1758 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
1686 * classes it implements and type argument substitution functions for these | 1759 * classes it implements and type argument substitution functions for these |
1687 * tests. We don't need to add the "is tests" of the super class because | 1760 * tests. We don't need to add the "is tests" of the super class because |
1688 * they will be inherited at runtime, but we may need to generate the | 1761 * they will be inherited at runtime, but we may need to generate the |
1689 * substitutions, because they may have changed. | 1762 * substitutions, because they may have changed. |
1690 */ | 1763 */ |
1691 void generateIsTestsOn(ClassElement cls, | 1764 void generateIsTestsOn(ClassElement cls, |
1692 void emitIsTest(Element element), | 1765 void emitIsTest(Element element), |
1766 void emitIsFunctionTypeTest(FunctionType type), | |
karlklose
2013/06/19 14:37:05
You could add Typedefs for these three function ty
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1767 void emitFunctionTypeSignature(Element method, Function Type type), | |
1693 void emitSubstitution(Element element, {emitNull})) { | 1768 void emitSubstitution(Element element, {emitNull})) { |
1694 if (checkedClasses.contains(cls)) { | 1769 if (checkedClasses.contains(cls)) { |
1695 emitIsTest(cls); | 1770 emitIsTest(cls); |
1696 emitSubstitution(cls); | 1771 emitSubstitution(cls); |
1697 } | 1772 } |
1698 | 1773 |
1699 RuntimeTypes rti = backend.rti; | 1774 RuntimeTypes rti = backend.rti; |
1700 ClassElement superclass = cls.superclass; | 1775 ClassElement superclass = cls.superclass; |
1701 | 1776 |
1702 bool haveSameTypeVariables(ClassElement a, ClassElement b) { | 1777 bool haveSameTypeVariables(ClassElement a, ClassElement b) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1734 } | 1809 } |
1735 } | 1810 } |
1736 void emitNothing(_, {emitNull}) {}; | 1811 void emitNothing(_, {emitNull}) {}; |
1737 emitSubstitution = emitNothing; | 1812 emitSubstitution = emitNothing; |
1738 } | 1813 } |
1739 | 1814 |
1740 Set<Element> generated = new Set<Element>(); | 1815 Set<Element> generated = new Set<Element>(); |
1741 // A class that defines a [:call:] method implicitly implements | 1816 // A class that defines a [:call:] method implicitly implements |
1742 // [Function] and needs checks for all typedefs that are used in is-checks. | 1817 // [Function] and needs checks for all typedefs that are used in is-checks. |
1743 if (checkedClasses.contains(compiler.functionClass) || | 1818 if (checkedClasses.contains(compiler.functionClass) || |
1744 !checkedTypedefs.isEmpty) { | 1819 !checkedFunctionTypes.isEmpty) { |
1745 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1820 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
1746 if (call == null) { | 1821 if (call == null) { |
1747 // If [cls] is a closure, it has a synthetic call operator method. | 1822 // If [cls] is a closure, it has a synthetic call operator method. |
1748 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1823 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
1749 } | 1824 } |
1750 if (call != null && call.isFunction()) { | 1825 if (call != null && call.isFunction()) { |
1751 generateInterfacesIsTests(compiler.functionClass, | 1826 generateInterfacesIsTests(compiler.functionClass, |
1752 emitIsTest, | 1827 emitIsTest, |
1753 emitSubstitution, | 1828 emitSubstitution, |
1754 generated); | 1829 generated); |
1755 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); | 1830 FunctionType callType = call.computeType(compiler); |
1756 } | 1831 generateFunctionTypeTests(call, callType, |
1832 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
1833 } | |
1757 } | 1834 } |
1758 | 1835 |
1759 for (DartType interfaceType in cls.interfaces) { | 1836 for (DartType interfaceType in cls.interfaces) { |
1760 generateInterfacesIsTests(interfaceType.element, emitIsTest, | 1837 generateInterfacesIsTests(interfaceType.element, emitIsTest, |
1761 emitSubstitution, generated); | 1838 emitSubstitution, generated); |
1762 } | 1839 } |
1763 } | 1840 } |
1764 | 1841 |
1765 /** | 1842 /** |
1766 * Generate "is tests" where [cls] is being implemented. | 1843 * Generate "is tests" where [cls] is being implemented. |
(...skipping 21 matching lines...) Expand all Loading... | |
1788 | 1865 |
1789 // We need to also emit "is checks" for the superclass and its supertypes. | 1866 // We need to also emit "is checks" for the superclass and its supertypes. |
1790 ClassElement superclass = cls.superclass; | 1867 ClassElement superclass = cls.superclass; |
1791 if (superclass != null) { | 1868 if (superclass != null) { |
1792 tryEmitTest(superclass); | 1869 tryEmitTest(superclass); |
1793 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, | 1870 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, |
1794 alreadyGenerated); | 1871 alreadyGenerated); |
1795 } | 1872 } |
1796 } | 1873 } |
1797 | 1874 |
1875 void generateFunctionTypeTests( | |
karlklose
2013/06/19 14:37:05
Could you get rid of this method? I don't think it
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1876 Element method, | |
1877 FunctionType methodType, | |
1878 void emitFunctionTypeSignature(Element method, FunctionType methodType), | |
1879 void emitIsFunctionTypeTest(FunctionType functionType)) { | |
1880 Map<FunctionType, bool> functionTypeChecks = | |
1881 getFunctionTypeChecksOn(methodType); | |
1882 generateFunctionTypeTestsInternal(method, methodType, functionTypeChecks, | |
1883 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
1884 } | |
1885 | |
1886 const int MAX_FUNCTION_TYPE_PREDICATES = 10; | |
1887 | |
1888 void generateFunctionTypeTestsInternal( | |
1889 Element method, | |
1890 FunctionType methodType, | |
1891 Map<FunctionType, bool> functionTypeChecks, | |
1892 void emitFunctionTypeSignature(Element method, FunctionType methodType), | |
1893 void emitIsFunctionTypeTest(FunctionType functionType)) { | |
1894 bool hasDynamicFunctionTypeCheck = false; | |
1895 int neededPredicates = 0; | |
1896 functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) { | |
1897 if (!knownSubtype) { | |
1898 registerDynamicFunctionTypeCheck(functionType); | |
1899 hasDynamicFunctionTypeCheck = true; | |
1900 } else { | |
1901 neededPredicates++; | |
1902 } | |
1903 }); | |
1904 bool hasSignature = false; | |
karlklose
2013/06/19 14:37:05
Perhaps alwaysUseSignature would be clearer.
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1905 if (hasDynamicFunctionTypeCheck || | |
1906 neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) { | |
1907 emitFunctionTypeSignature(method, methodType); | |
1908 hasSignature = true; | |
1909 } | |
1910 functionTypeChecks.forEach((FunctionType functionType, | |
1911 bool knownSubtype) { | |
karlklose
2013/06/19 14:37:05
This should fit on one line.
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1912 if (knownSubtype || !hasDynamicFunctionTypeCheck) { | |
karlklose
2013/06/19 14:37:05
!knownSubtype implies hasDynamicFunctionTypeCheck,
Johnni Winther
2013/06/21 12:19:15
Done.
| |
1913 if (hasSignature) { | |
1914 registerDynamicFunctionTypeCheck(functionType); | |
1915 } else { | |
1916 emitIsFunctionTypeTest(functionType); | |
1917 } | |
1918 } | |
1919 }); | |
1920 } | |
1921 | |
1798 /** | 1922 /** |
1799 * Return a function that returns true if its argument is a class | 1923 * Return a function that returns true if its argument is a class |
1800 * that needs to be emitted. | 1924 * that needs to be emitted. |
1801 */ | 1925 */ |
1802 Function computeClassFilter() { | 1926 Function computeClassFilter() { |
1803 Set<ClassElement> unneededClasses = new Set<ClassElement>(); | 1927 Set<ClassElement> unneededClasses = new Set<ClassElement>(); |
1804 // The [Bool] class is not marked as abstract, but has a factory | 1928 // The [Bool] class is not marked as abstract, but has a factory |
1805 // constructor that always throws. We never need to emit it. | 1929 // constructor that always throws. We never need to emit it. |
1806 unneededClasses.add(compiler.boolClass); | 1930 unneededClasses.add(compiler.boolClass); |
1807 | 1931 |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1946 ClassBuilder closureBuilder = new ClassBuilder(); | 2070 ClassBuilder closureBuilder = new ClassBuilder(); |
1947 // If a static function is used as a closure we need to add its name | 2071 // If a static function is used as a closure we need to add its name |
1948 // in case it is used in spawnFunction. | 2072 // in case it is used in spawnFunction. |
1949 String methodName = namer.STATIC_CLOSURE_NAME_NAME; | 2073 String methodName = namer.STATIC_CLOSURE_NAME_NAME; |
1950 emitClosureClassHeader( | 2074 emitClosureClassHeader( |
1951 mangledName, superName, <String>[invocationName, methodName], | 2075 mangledName, superName, <String>[invocationName, methodName], |
1952 closureBuilder); | 2076 closureBuilder); |
1953 | 2077 |
1954 addParameterStubs(callElement, closureBuilder.addProperty); | 2078 addParameterStubs(callElement, closureBuilder.addProperty); |
1955 | 2079 |
1956 DartType type = element.computeType(compiler); | |
1957 getTypedefChecksOn(type).forEach((Element typedef) { | |
1958 String operator = namer.operatorIs(typedef); | |
1959 closureBuilder.addProperty(operator, js('true')); | |
1960 }); | |
1961 | |
1962 // TODO(ngeoffray): Cache common base classes for closures, bound | 2080 // TODO(ngeoffray): Cache common base classes for closures, bound |
1963 // closures, and static closures that have common type checks. | 2081 // closures, and static closures that have common type checks. |
1964 boundClosures.add( | 2082 boundClosures.add( |
1965 js('$classesCollector.$mangledName = #', | 2083 js('$classesCollector.$mangledName = #', |
1966 closureBuilder.toObjectInitializer())); | 2084 closureBuilder.toObjectInitializer())); |
1967 | 2085 |
1968 staticGetters[element] = closureClassElement; | 2086 staticGetters[element] = closureClassElement; |
2087 | |
2088 void emitFunctionTypeSignature(Element method, FunctionType methodType) { | |
2089 RuntimeTypes rti = backend.rti; | |
2090 String encoding = rti.getSignatureEncoding(methodType, () => 'null'); | |
2091 String operatorSignature = namer.operatorSignature(); | |
2092 // TODO(johnniwinther): Make MiniJsParser support function expressions. | |
2093 closureBuilder.addProperty(operatorSignature, | |
2094 new jsAst.LiteralExpression(encoding)); | |
2095 } | |
2096 | |
2097 void emitIsFunctionTypeTest(FunctionType functionType) { | |
2098 String operator = namer.operatorIsType(functionType); | |
2099 closureBuilder.addProperty(operator, js('true')); | |
2100 } | |
2101 | |
2102 generateFunctionTypeTests(element, element.computeType(compiler), | |
2103 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
1969 } | 2104 } |
1970 } | 2105 } |
1971 | 2106 |
1972 void emitClosureClassHeader(String mangledName, | 2107 void emitClosureClassHeader(String mangledName, |
1973 String superName, | 2108 String superName, |
1974 List<String> fieldNames, | 2109 List<String> fieldNames, |
1975 ClassBuilder builder) { | 2110 ClassBuilder builder) { |
1976 builder.addProperty('', | 2111 builder.addProperty('', |
1977 js.string("$superName;${fieldNames.join(',')}")); | 2112 js.string("$superName;${fieldNames.join(',')}")); |
1978 } | 2113 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2016 if (inInterceptor) { | 2151 if (inInterceptor) { |
2017 cache = interceptorClosureCache; | 2152 cache = interceptorClosureCache; |
2018 } else { | 2153 } else { |
2019 cache = boundClosureCache; | 2154 cache = boundClosureCache; |
2020 } | 2155 } |
2021 List<String> fieldNames = <String>[]; | 2156 List<String> fieldNames = <String>[]; |
2022 compiler.boundClosureClass.forEachInstanceField((_, Element field) { | 2157 compiler.boundClosureClass.forEachInstanceField((_, Element field) { |
2023 fieldNames.add(namer.getName(field)); | 2158 fieldNames.add(namer.getName(field)); |
2024 }); | 2159 }); |
2025 | 2160 |
2026 Iterable<Element> typedefChecks = | 2161 DartType memberType = member.computeType(compiler); |
2027 getTypedefChecksOn(member.computeType(compiler)); | 2162 Map<FunctionType, bool> functionTypeChecks = |
2028 bool hasTypedefChecks = !typedefChecks.isEmpty; | 2163 getFunctionTypeChecksOn(memberType); |
2164 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty; | |
2029 | 2165 |
2030 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; | 2166 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks; |
2031 | 2167 |
2168 ClassElement classElement = member.getEnclosingClass(); | |
2032 String closureClass = canBeShared ? cache[parameterCount] : null; | 2169 String closureClass = canBeShared ? cache[parameterCount] : null; |
2033 if (closureClass == null) { | 2170 if (closureClass == null) { |
2034 // Either the class was not cached yet, or there are optional parameters. | 2171 // Either the class was not cached yet, or there are optional parameters. |
2035 // Create a new closure class. | 2172 // Create a new closure class. |
2036 String name; | 2173 String name; |
2037 if (canBeShared) { | 2174 if (canBeShared) { |
2038 if (inInterceptor) { | 2175 if (inInterceptor) { |
2039 name = 'BoundClosure\$i${parameterCount}'; | 2176 name = 'BoundClosure\$i${parameterCount}'; |
2040 } else { | 2177 } else { |
2041 name = 'BoundClosure\$${parameterCount}'; | 2178 name = 'BoundClosure\$${parameterCount}'; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2077 arguments.add(js(name)); | 2214 arguments.add(js(name)); |
2078 } | 2215 } |
2079 | 2216 |
2080 jsAst.Expression fun = js.fun( | 2217 jsAst.Expression fun = js.fun( |
2081 parameters, | 2218 parameters, |
2082 js.return_( | 2219 js.return_( |
2083 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments))); | 2220 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments))); |
2084 boundClosureBuilder.addProperty(invocationName, fun); | 2221 boundClosureBuilder.addProperty(invocationName, fun); |
2085 | 2222 |
2086 addParameterStubs(callElement, boundClosureBuilder.addProperty); | 2223 addParameterStubs(callElement, boundClosureBuilder.addProperty); |
2087 typedefChecks.forEach((Element typedef) { | 2224 |
2088 String operator = namer.operatorIs(typedef); | 2225 void emitFunctionTypeSignature(Element method, FunctionType methodType) { |
2089 boundClosureBuilder.addProperty(operator, js('true')); | 2226 RuntimeTypes rti = backend.rti; |
karlklose
2013/06/19 14:37:05
You can inline rti.
Johnni Winther
2013/06/21 12:19:15
Done.
| |
2090 }); | 2227 String encoding = rti.getSignatureEncoding( |
2228 methodType, () => 'this.${fieldNames[0]}'); | |
2229 String operatorSignature = namer.operatorSignature(); | |
2230 boundClosureBuilder.addProperty(operatorSignature, | |
2231 new jsAst.LiteralExpression(encoding)); | |
2232 } | |
2233 | |
2234 void emitIsFunctionTypeTest(FunctionType functionType) { | |
karlklose
2013/06/19 14:37:05
I think we should be more careful with names in th
Johnni Winther
2013/06/21 12:19:15
Yes. Added a TODO to the newly added typedef for t
| |
2235 String operator = namer.operatorIsType(functionType); | |
2236 boundClosureBuilder.addProperty(operator, | |
2237 new jsAst.LiteralBool(true)); | |
2238 } | |
2239 | |
2240 generateFunctionTypeTestsInternal(member, memberType, functionTypeChecks, | |
2241 emitFunctionTypeSignature, emitIsFunctionTypeTest); | |
2091 | 2242 |
2092 boundClosures.add( | 2243 boundClosures.add( |
2093 js('$classesCollector.$mangledName = #', | 2244 js('$classesCollector.$mangledName = #', |
2094 boundClosureBuilder.toObjectInitializer())); | 2245 boundClosureBuilder.toObjectInitializer())); |
2095 | 2246 |
2096 closureClass = namer.isolateAccess(closureClassElement); | 2247 closureClass = namer.isolateAccess(closureClassElement); |
2097 | 2248 |
2098 // Cache it. | 2249 // Cache it. |
2099 if (canBeShared) { | 2250 if (canBeShared) { |
2100 cache[parameterCount] = closureClass; | 2251 cache[parameterCount] = closureClass; |
(...skipping 10 matching lines...) Expand all Loading... | |
2111 arguments.add(js.string(targetName)); | 2262 arguments.add(js.string(targetName)); |
2112 if (inInterceptor) { | 2263 if (inInterceptor) { |
2113 String receiverArg = fieldNames[2]; | 2264 String receiverArg = fieldNames[2]; |
2114 parameters.add(receiverArg); | 2265 parameters.add(receiverArg); |
2115 arguments.add(js(receiverArg)); | 2266 arguments.add(js(receiverArg)); |
2116 } else { | 2267 } else { |
2117 // Put null in the intercepted receiver field. | 2268 // Put null in the intercepted receiver field. |
2118 arguments.add(new jsAst.LiteralNull()); | 2269 arguments.add(new jsAst.LiteralNull()); |
2119 } | 2270 } |
2120 | 2271 |
2272 jsAst.Expression newClosure = js(closureClass).newWith(arguments); | |
karlklose
2013/06/19 14:37:05
Why this change?
Johnni Winther
2013/06/21 12:19:15
It was needed in a previous iteration. Removed.
| |
2121 jsAst.Expression getterFunction = js.fun( | 2273 jsAst.Expression getterFunction = js.fun( |
2122 parameters, | 2274 parameters, js.return_(newClosure)); |
2123 js.return_(js(closureClass).newWith(arguments))); | |
2124 | 2275 |
2125 defineStub(getterName, getterFunction); | 2276 defineStub(getterName, getterFunction); |
2126 } | 2277 } |
2127 | 2278 |
2128 /** | 2279 /** |
2129 * Documentation wanted -- johnniwinther | 2280 * Documentation wanted -- johnniwinther |
2130 * | 2281 * |
2131 * Invariant: [member] must be a declaration element. | 2282 * Invariant: [member] must be a declaration element. |
2132 */ | 2283 */ |
2133 void emitCallStubForGetter(Element member, | 2284 void emitCallStubForGetter(Element member, |
(...skipping 19 matching lines...) Expand all Loading... | |
2153 ? member.fixedBackendName() | 2304 ? member.fixedBackendName() |
2154 : namer.instanceFieldName(member); | 2305 : namer.instanceFieldName(member); |
2155 return js('this')[fieldName]; | 2306 return js('this')[fieldName]; |
2156 } | 2307 } |
2157 } | 2308 } |
2158 | 2309 |
2159 // Two selectors may match but differ only in type. To avoid generating | 2310 // Two selectors may match but differ only in type. To avoid generating |
2160 // identical stubs for each we track untyped selectors which already have | 2311 // identical stubs for each we track untyped selectors which already have |
2161 // stubs. | 2312 // stubs. |
2162 Set<Selector> generatedSelectors = new Set<Selector>(); | 2313 Set<Selector> generatedSelectors = new Set<Selector>(); |
2163 | 2314 DartType memberType = member.computeType(compiler); |
karlklose
2013/06/19 14:37:05
This is not used.
Johnni Winther
2013/06/21 12:19:15
Removed.
| |
2164 for (Selector selector in selectors) { | 2315 for (Selector selector in selectors) { |
2165 if (selector.applies(member, compiler)) { | 2316 if (selector.applies(member, compiler)) { |
2166 selector = selector.asUntyped; | 2317 selector = selector.asUntyped; |
2167 if (generatedSelectors.contains(selector)) continue; | 2318 if (generatedSelectors.contains(selector)) continue; |
2168 generatedSelectors.add(selector); | 2319 generatedSelectors.add(selector); |
2169 | 2320 |
2170 String invocationName = namer.invocationName(selector); | 2321 String invocationName = namer.invocationName(selector); |
2171 Selector callSelector = new Selector.callClosureFrom(selector); | 2322 Selector callSelector = new Selector.callClosureFrom(selector); |
2172 String closureCallName = namer.invocationName(callSelector); | 2323 String closureCallName = namer.invocationName(callSelector); |
2173 | 2324 |
(...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2754 }); | 2905 }); |
2755 | 2906 |
2756 // 3b. Add classes that are referenced by substitutions in object checks and | 2907 // 3b. Add classes that are referenced by substitutions in object checks and |
2757 // their superclasses. | 2908 // their superclasses. |
2758 TypeChecks requiredChecks = | 2909 TypeChecks requiredChecks = |
2759 backend.rti.computeChecks(neededClasses, checkedClasses); | 2910 backend.rti.computeChecks(neededClasses, checkedClasses); |
2760 Set<ClassElement> classesUsedInSubstitutions = | 2911 Set<ClassElement> classesUsedInSubstitutions = |
2761 rti.getClassesUsedInSubstitutions(backend, requiredChecks); | 2912 rti.getClassesUsedInSubstitutions(backend, requiredChecks); |
2762 addClassesWithSuperclasses(classesUsedInSubstitutions); | 2913 addClassesWithSuperclasses(classesUsedInSubstitutions); |
2763 | 2914 |
2915 // 3c. Add classes that contain checked generic function types. These are | |
2916 // needed to store the signature encoding. | |
2917 for (FunctionType type in checkedFunctionTypes) { | |
2918 ClassElement contextClass = Types.getClassContext(type); | |
2919 if (contextClass != null) { | |
2920 neededClasses.add(contextClass); | |
2921 } | |
2922 } | |
2923 | |
2764 // 4. Finally, sort the classes. | 2924 // 4. Finally, sort the classes. |
2765 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); | 2925 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); |
2766 | 2926 |
2767 // If we need noSuchMethod support, we run through all needed | 2927 // If we need noSuchMethod support, we run through all needed |
2768 // classes to figure out if we need the support on any native | 2928 // classes to figure out if we need the support on any native |
2769 // class. If so, we let the native emitter deal with it. | 2929 // class. If so, we let the native emitter deal with it. |
2770 if (compiler.enabledNoSuchMethod) { | 2930 if (compiler.enabledNoSuchMethod) { |
2771 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD; | 2931 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD; |
2772 Selector noSuchMethodSelector = compiler.noSuchMethodSelector; | 2932 Selector noSuchMethodSelector = compiler.noSuchMethodSelector; |
2773 for (ClassElement element in sortedClasses) { | 2933 for (ClassElement element in sortedClasses) { |
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3385 | 3545 |
3386 const String HOOKS_API_USAGE = """ | 3546 const String HOOKS_API_USAGE = """ |
3387 // The code supports the following hooks: | 3547 // The code supports the following hooks: |
3388 // dartPrint(message) - if this function is defined it is called | 3548 // dartPrint(message) - if this function is defined it is called |
3389 // instead of the Dart [print] method. | 3549 // instead of the Dart [print] method. |
3390 // dartMainRunner(main) - if this function is defined, the Dart [main] | 3550 // dartMainRunner(main) - if this function is defined, the Dart [main] |
3391 // method will not be invoked directly. | 3551 // method will not be invoked directly. |
3392 // Instead, a closure that will invoke [main] is | 3552 // Instead, a closure that will invoke [main] is |
3393 // passed to [dartMainRunner]. | 3553 // passed to [dartMainRunner]. |
3394 """; | 3554 """; |
OLD | NEW |