Chromium Code Reviews| 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 |