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 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 |