Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(286)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 12334070: Support runtime check of function types. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix status files Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698