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

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: Updated cf. comments. 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 30 matching lines...) Expand all
41 // Has the same signature as [DefineStubFunction]. 41 // Has the same signature as [DefineStubFunction].
42 void addProperty(String name, jsAst.Expression value) { 42 void addProperty(String name, jsAst.Expression value) {
43 properties.add(new jsAst.Property(js.string(name), value)); 43 properties.add(new jsAst.Property(js.string(name), value));
44 } 44 }
45 45
46 jsAst.Expression toObjectInitializer() { 46 jsAst.Expression toObjectInitializer() {
47 return new jsAst.ObjectInitializer(properties); 47 return new jsAst.ObjectInitializer(properties);
48 } 48 }
49 } 49 }
50 50
51 // Function signatures used in the generation of runtime type information.
52 typedef void FunctionTypeSignatureEmitter(Element method,
53 FunctionType methodType);
54 // TODO(johnniwinther): Clean up terminology for rti in the emitter.
55 typedef void FunctionTypeTestEmitter(FunctionType functionType);
56 typedef void SubstitutionEmitter(Element element, {bool emitNull});
57
51 /** 58 /**
52 * Generates the code for all used classes in the program. Static fields (even 59 * Generates the code for all used classes in the program. Static fields (even
53 * in classes) are ignored, since they can be treated as non-class elements. 60 * in classes) are ignored, since they can be treated as non-class elements.
54 * 61 *
55 * The code for the containing (used) methods must exist in the [:universe:]. 62 * The code for the containing (used) methods must exist in the [:universe:].
56 */ 63 */
57 class CodeEmitterTask extends CompilerTask { 64 class CodeEmitterTask extends CompilerTask {
58 bool needsInheritFunction = false; 65 bool needsInheritFunction = false;
59 bool needsDefineClass = false; 66 bool needsDefineClass = false;
60 bool needsMixinSupport = false; 67 bool needsMixinSupport = false;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 112
106 /** 113 /**
107 * Raw ClassElement symbols occuring in is-checks and type assertions. If the 114 * Raw ClassElement symbols occuring in is-checks and type assertions. If the
108 * program contains parameterized checks `x is Set<int>` and 115 * program contains parameterized checks `x is Set<int>` and
109 * `x is Set<String>` then the ClassElement `Set` will occur once in 116 * `x is Set<String>` then the ClassElement `Set` will occur once in
110 * [checkedClasses]. 117 * [checkedClasses].
111 */ 118 */
112 Set<ClassElement> checkedClasses; 119 Set<ClassElement> checkedClasses;
113 120
114 /** 121 /**
115 * Raw Typedef symbols occuring in is-checks and type assertions. If the 122 * The set of function types that checked, both explicity through tests of
116 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement 123 * typedefs and implicitly through type annotations in checked mode.
117 * `F` will occur once in [checkedTypedefs].
118 */ 124 */
119 Set<TypedefElement> checkedTypedefs; 125 Set<FunctionType> checkedFunctionTypes;
126
127 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes =
128 new Map<ClassElement, Set<FunctionType>>();
129
130 Set<FunctionType> checkedNonGenericFunctionTypes =
131 new Set<FunctionType>();
132
133 void registerDynamicFunctionTypeCheck(FunctionType functionType) {
134 ClassElement classElement = Types.getClassContext(functionType);
135 if (classElement != null) {
136 checkedGenericFunctionTypes.putIfAbsent(classElement,
137 () => new Set<FunctionType>()).add(functionType);
138 } else {
139 checkedNonGenericFunctionTypes.add(functionType);
140 }
141 }
120 142
121 final bool generateSourceMap; 143 final bool generateSourceMap;
122 144
123 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; 145 Iterable<ClassElement> cachedClassesUsingTypeVariableTests;
124 146
125 Iterable<ClassElement> get classesUsingTypeVariableTests { 147 Iterable<ClassElement> get classesUsingTypeVariableTests {
126 if (cachedClassesUsingTypeVariableTests == null) { 148 if (cachedClassesUsingTypeVariableTests == null) {
127 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks 149 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks
128 .where((DartType t) => t is TypeVariableType) 150 .where((DartType t) => t is TypeVariableType)
129 .map((TypeVariableType v) => v.element.getEnclosingClass()) 151 .map((TypeVariableType v) => v.element.getEnclosingClass())
(...skipping 10 matching lines...) Expand all
140 constantEmitter = new ConstantEmitter(compiler, namer), 162 constantEmitter = new ConstantEmitter(compiler, namer),
141 super(compiler) { 163 super(compiler) {
142 nativeEmitter = new NativeEmitter(this); 164 nativeEmitter = new NativeEmitter(this);
143 } 165 }
144 166
145 void addComment(String comment, CodeBuffer buffer) { 167 void addComment(String comment, CodeBuffer buffer) {
146 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); 168 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler));
147 } 169 }
148 170
149 void computeRequiredTypeChecks() { 171 void computeRequiredTypeChecks() {
150 assert(checkedClasses == null && checkedTypedefs == null); 172 assert(checkedClasses == null && checkedFunctionTypes == null);
151 173
152 backend.rti.addImplicitChecks(compiler.codegenWorld, 174 backend.rti.addImplicitChecks(compiler.codegenWorld,
153 classesUsingTypeVariableTests); 175 classesUsingTypeVariableTests);
154 176
155 checkedClasses = new Set<ClassElement>(); 177 checkedClasses = new Set<ClassElement>();
156 checkedTypedefs = new Set<TypedefElement>(); 178 checkedFunctionTypes = new Set<FunctionType>();
157 compiler.codegenWorld.isChecks.forEach((DartType t) { 179 compiler.codegenWorld.isChecks.forEach((DartType t) {
158 if (t is InterfaceType) { 180 if (!t.isMalformed) {
159 checkedClasses.add(t.element); 181 if (t is InterfaceType) {
160 } else if (t is TypedefType) { 182 checkedClasses.add(t.element);
161 checkedTypedefs.add(t.element); 183 } else if (t is FunctionType) {
184 checkedFunctionTypes.add(t);
185 }
162 } 186 }
163 }); 187 });
164 } 188 }
165 189
166 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) { 190 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) {
167 ClassElement mixin = mixinApplication.mixin; 191 ClassElement mixin = mixinApplication.mixin;
168 while (mixin.isMixinApplication) { 192 while (mixin.isMixinApplication) {
169 mixinApplication = mixin; 193 mixinApplication = mixin;
170 mixin = mixinApplication.mixin; 194 mixin = mixinApplication.mixin;
171 } 195 }
(...skipping 1115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1287 1311
1288 void generateIsTest(Element other) { 1312 void generateIsTest(Element other) {
1289 if (other == compiler.objectClass && other != classElement) { 1313 if (other == compiler.objectClass && other != classElement) {
1290 // Avoid emitting [:$isObject:] on all classes but [Object]. 1314 // Avoid emitting [:$isObject:] on all classes but [Object].
1291 return; 1315 return;
1292 } 1316 }
1293 other = backend.getImplementationClass(other); 1317 other = backend.getImplementationClass(other);
1294 builder.addProperty(namer.operatorIs(other), js('true')); 1318 builder.addProperty(namer.operatorIs(other), js('true'));
1295 } 1319 }
1296 1320
1321 void generateIsFunctionTypeTest(FunctionType type) {
1322 String operator = namer.operatorIsType(type);
1323 builder.addProperty(operator, new jsAst.LiteralBool(true));
1324 }
1325
1326 void generateFunctionTypeSignature(Element method, FunctionType type) {
1327 assert(method.isImplementation);
1328 String thisAccess = 'this';
1329 Node node = method.parseNode(compiler);
1330 ClosureClassMap closureData =
1331 compiler.closureToClassMapper.closureMappingCache[node];
1332 if (closureData != null) {
1333 Element thisElement =
1334 closureData.freeVariableMapping[closureData.thisElement];
1335 if (thisElement != null) {
1336 String thisName = backend.namer.getName(thisElement);
1337 thisAccess = 'this.$thisName';
1338 }
1339 }
1340 RuntimeTypes rti = backend.rti;
1341 String encoding = rti.getSignatureEncoding(type, () => '$thisAccess');
1342 String operatorSignature = namer.operatorSignature();
1343 builder.addProperty(operatorSignature,
1344 new jsAst.LiteralExpression(encoding));
1345 }
1346
1297 void generateSubstitution(Element other, {bool emitNull: false}) { 1347 void generateSubstitution(Element other, {bool emitNull: false}) {
1298 RuntimeTypes rti = backend.rti; 1348 RuntimeTypes rti = backend.rti;
1299 // TODO(karlklose): support typedefs with variables.
1300 jsAst.Expression expression; 1349 jsAst.Expression expression;
1301 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1350 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1302 if (other.kind == ElementKind.CLASS) { 1351 if (other.kind == ElementKind.CLASS) {
1303 String substitution = rti.getSupertypeSubstitution(classElement, other, 1352 String substitution = rti.getSupertypeSubstitution(classElement, other,
1304 alwaysGenerateFunction: true); 1353 alwaysGenerateFunction: true);
1305 if (substitution != null) { 1354 if (substitution != null) {
1306 expression = new jsAst.LiteralExpression(substitution); 1355 expression = new jsAst.LiteralExpression(substitution);
1307 } else if (emitNull || needsNativeCheck) { 1356 } else if (emitNull || needsNativeCheck) {
1308 expression = new jsAst.LiteralNull(); 1357 expression = new jsAst.LiteralNull();
1309 } 1358 }
1310 } 1359 }
1311 if (expression != null) { 1360 if (expression != null) {
1312 builder.addProperty(namer.substitutionName(other), expression); 1361 builder.addProperty(namer.substitutionName(other), expression);
1313 } 1362 }
1314 } 1363 }
1315 1364
1316 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); 1365 generateIsTestsOn(classElement, generateIsTest,
1366 generateIsFunctionTypeTest, generateFunctionTypeSignature,
1367 generateSubstitution);
1317 } 1368 }
1318 1369
1319 void emitRuntimeTypeSupport(CodeBuffer buffer) { 1370 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1320 RuntimeTypes rti = backend.rti; 1371 RuntimeTypes rti = backend.rti;
1321 TypeChecks typeChecks = rti.requiredChecks; 1372 TypeChecks typeChecks = rti.requiredChecks;
1322 1373
1323 // Add checks to the constructors of instantiated classes. 1374 // Add checks to the constructors of instantiated classes.
1324 for (ClassElement cls in typeChecks) { 1375 for (ClassElement cls in typeChecks) {
1325 String holder = namer.isolateAccess(backend.getImplementationClass(cls)); 1376 String holder = namer.isolateAccess(backend.getImplementationClass(cls));
1326 for (TypeCheck check in typeChecks[cls]) { 1377 for (TypeCheck check in typeChecks[cls]) {
1327 ClassElement cls = check.cls; 1378 ClassElement cls = check.cls;
1328 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N'); 1379 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
1329 Substitution substitution = check.substitution; 1380 Substitution substitution = check.substitution;
1330 if (substitution != null) { 1381 if (substitution != null) {
1331 String body = substitution.getCode(rti, false); 1382 String body = substitution.getCode(rti, false);
1332 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N'); 1383 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N');
1333 } 1384 }
1334 }; 1385 };
1335 } 1386 }
1387
1388 void addSignature(FunctionType type) {
1389 String encoding = rti.getTypeEncoding(type);
1390 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N');
1391 }
1392
1393 checkedNonGenericFunctionTypes.forEach(addSignature);
1394
1395 checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
1396 functionTypes.forEach(addSignature);
1397 });
1336 } 1398 }
1337 1399
1338 /** 1400 /**
1339 * Documentation wanted -- johnniwinther 1401 * Documentation wanted -- johnniwinther
1340 * 1402 *
1341 * Invariant: [classElement] must be a declaration element. 1403 * Invariant: [classElement] must be a declaration element.
1342 */ 1404 */
1343 void visitClassFields(ClassElement classElement, 1405 void visitClassFields(ClassElement classElement,
1344 void addField(Element member, 1406 void addField(Element member,
1345 String name, 1407 String name,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1457 } 1519 }
1458 1520
1459 void generateCheckedSetter(Element member, 1521 void generateCheckedSetter(Element member,
1460 String fieldName, 1522 String fieldName,
1461 String accessorName, 1523 String accessorName,
1462 ClassBuilder builder) { 1524 ClassBuilder builder) {
1463 assert(canGenerateCheckedSetter(member)); 1525 assert(canGenerateCheckedSetter(member));
1464 DartType type = member.computeType(compiler); 1526 DartType type = member.computeType(compiler);
1465 // TODO(ahe): Generate a dynamic type error here. 1527 // TODO(ahe): Generate a dynamic type error here.
1466 if (type.element.isErroneous()) return; 1528 if (type.element.isErroneous()) return;
1467 FunctionElement helperElement 1529 type = type.unalias(compiler);
1468 = backend.getCheckedModeHelper(type, typeCast: false); 1530 CheckedModeHelper helper =
1531 backend.getCheckedModeHelper(type, typeCast: false);
1532 FunctionElement helperElement = helper.getElement(compiler);
1469 String helperName = namer.isolateAccess(helperElement); 1533 String helperName = namer.isolateAccess(helperElement);
1470 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')]; 1534 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
1471 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1535 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1472 arguments.add(js.string(namer.operatorIs(type.element))); 1536 arguments.add(js.string(namer.operatorIsType(type)));
1473 } 1537 }
1474 1538
1475 String setterName = namer.setterNameFromAccessorName(accessorName); 1539 String setterName = namer.setterNameFromAccessorName(accessorName);
1476 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1540 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1477 ? 'receiver' : 'this'; 1541 ? 'receiver' : 'this';
1478 List<String> args = backend.isInterceptedMethod(member) 1542 List<String> args = backend.isInterceptedMethod(member)
1479 ? ['receiver', 'v'] 1543 ? ['receiver', 'v']
1480 : ['v']; 1544 : ['v'];
1481 builder.addProperty(setterName, 1545 builder.addProperty(setterName,
1482 js.fun(args, 1546 js.fun(args,
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
1703 return arity; 1767 return arity;
1704 } 1768 }
1705 1769
1706 int _compareSelectorNames(Selector selector1, Selector selector2) { 1770 int _compareSelectorNames(Selector selector1, Selector selector2) {
1707 String name1 = selector1.name.toString(); 1771 String name1 = selector1.name.toString();
1708 String name2 = selector2.name.toString(); 1772 String name2 = selector2.name.toString();
1709 if (name1 != name2) return Comparable.compare(name1, name2); 1773 if (name1 != name2) return Comparable.compare(name1, name2);
1710 return _selectorRank(selector1) - _selectorRank(selector2); 1774 return _selectorRank(selector1) - _selectorRank(selector2);
1711 } 1775 }
1712 1776
1713 Iterable<Element> getTypedefChecksOn(DartType type) { 1777 /**
1714 bool isSubtype(TypedefElement typedef) { 1778 * Returns a mapping containing all checked function types for which [type]
1715 FunctionType typedefType = 1779 * can be a subtype. A function type is mapped to [:true:] if [type] is
1716 typedef.computeType(compiler).unalias(compiler); 1780 * statically known to be a subtype of it and to [:false:] if [type] might
1717 return compiler.types.isSubtype(type, typedefType); 1781 * be a subtype, provided with the right type arguments.
1782 */
1783 // TODO(johnniwinther): Change to return a mapping from function types to
1784 // a set of variable points and use this to detect statically/dynamically
1785 // known subtype relations.
1786 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) {
1787 Map<FunctionType, bool> functionTypeMap =
1788 new LinkedHashMap<FunctionType, bool>();
1789 for (FunctionType functionType in checkedFunctionTypes) {
1790 if (compiler.types.isSubtype(type, functionType)) {
1791 functionTypeMap[functionType] = true;
1792 } else if (compiler.types.isPotentialSubtype(type, functionType)) {
1793 functionTypeMap[functionType] = false;
1794 }
1718 } 1795 }
1719 return checkedTypedefs.where(isSubtype).toList() 1796 // TODO(johnniwinther): Ensure stable ordering of the keys.
1720 ..sort(Elements.compareByPosition); 1797 return functionTypeMap;
1721 } 1798 }
1722 1799
1723 /** 1800 /**
1724 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1801 * Generate "is tests" for [cls]: itself, and the "is tests" for the
1725 * classes it implements and type argument substitution functions for these 1802 * classes it implements and type argument substitution functions for these
1726 * tests. We don't need to add the "is tests" of the super class because 1803 * tests. We don't need to add the "is tests" of the super class because
1727 * they will be inherited at runtime, but we may need to generate the 1804 * they will be inherited at runtime, but we may need to generate the
1728 * substitutions, because they may have changed. 1805 * substitutions, because they may have changed.
1729 */ 1806 */
1730 void generateIsTestsOn(ClassElement cls, 1807 void generateIsTestsOn(ClassElement cls,
1731 void emitIsTest(Element element), 1808 void emitIsTest(Element element),
1732 void emitSubstitution(Element element, {emitNull})) { 1809 FunctionTypeTestEmitter emitIsFunctionTypeTest,
1810 FunctionTypeSignatureEmitter emitFunctionTypeSignature,
1811 SubstitutionEmitter emitSubstitution) {
1733 if (checkedClasses.contains(cls)) { 1812 if (checkedClasses.contains(cls)) {
1734 emitIsTest(cls); 1813 emitIsTest(cls);
1735 emitSubstitution(cls); 1814 emitSubstitution(cls);
1736 } 1815 }
1737 1816
1738 RuntimeTypes rti = backend.rti; 1817 RuntimeTypes rti = backend.rti;
1739 ClassElement superclass = cls.superclass; 1818 ClassElement superclass = cls.superclass;
1740 1819
1741 bool haveSameTypeVariables(ClassElement a, ClassElement b) { 1820 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
1742 if (a.isClosure()) return true; 1821 if (a.isClosure()) return true;
1743 return a.typeVariables == b.typeVariables; 1822 return a.typeVariables == b.typeVariables;
1744 } 1823 }
1745 1824
1746 if (superclass != null && superclass != compiler.objectClass && 1825 if (superclass != null && superclass != compiler.objectClass &&
1747 !haveSameTypeVariables(cls, superclass)) { 1826 !haveSameTypeVariables(cls, superclass)) {
1748 // We cannot inherit the generated substitutions, because the type 1827 // We cannot inherit the generated substitutions, because the type
1749 // variable layout for this class is different. Instead we generate 1828 // variable layout for this class is different. Instead we generate
1750 // substitutions for all checks and make emitSubstitution a NOP for the 1829 // substitutions for all checks and make emitSubstitution a NOP for the
1751 // rest of this function. 1830 // rest of this function.
1752 Set<ClassElement> emitted = new Set<ClassElement>(); 1831 Set<ClassElement> emitted = new Set<ClassElement>();
1753 // TODO(karlklose): move the computation of these checks to 1832 // TODO(karlklose): move the computation of these checks to
1754 // RuntimeTypeInformation. 1833 // RuntimeTypeInformation.
1755 if (backend.needsRti(cls)) { 1834 if (backend.classNeedsRti(cls)) {
1756 emitSubstitution(superclass, emitNull: true); 1835 emitSubstitution(superclass, emitNull: true);
1757 emitted.add(superclass); 1836 emitted.add(superclass);
1758 } 1837 }
1759 for (DartType supertype in cls.allSupertypes) { 1838 for (DartType supertype in cls.allSupertypes) {
1760 ClassElement superclass = supertype.element; 1839 ClassElement superclass = supertype.element;
1761 if (classesUsingTypeVariableTests.contains(superclass)) { 1840 if (classesUsingTypeVariableTests.contains(superclass)) {
1762 emitSubstitution(superclass, emitNull: true); 1841 emitSubstitution(superclass, emitNull: true);
1763 emitted.add(superclass); 1842 emitted.add(superclass);
1764 } 1843 }
1765 for (ClassElement check in checkedClasses) { 1844 for (ClassElement check in checkedClasses) {
1766 if (supertype.element == check && !emitted.contains(check)) { 1845 if (supertype.element == check && !emitted.contains(check)) {
1767 // Generate substitution. If no substitution is necessary, emit 1846 // Generate substitution. If no substitution is necessary, emit
1768 // [:null:] to overwrite a (possibly) existing substitution from the 1847 // [:null:] to overwrite a (possibly) existing substitution from the
1769 // super classes. 1848 // super classes.
1770 emitSubstitution(check, emitNull: true); 1849 emitSubstitution(check, emitNull: true);
1771 emitted.add(check); 1850 emitted.add(check);
1772 } 1851 }
1773 } 1852 }
1774 } 1853 }
1775 void emitNothing(_, {emitNull}) {}; 1854 void emitNothing(_, {emitNull}) {};
1776 emitSubstitution = emitNothing; 1855 emitSubstitution = emitNothing;
1777 } 1856 }
1778 1857
1779 Set<Element> generated = new Set<Element>(); 1858 Set<Element> generated = new Set<Element>();
1780 // A class that defines a [:call:] method implicitly implements 1859 // A class that defines a [:call:] method implicitly implements
1781 // [Function] and needs checks for all typedefs that are used in is-checks. 1860 // [Function] and needs checks for all typedefs that are used in is-checks.
1782 if (checkedClasses.contains(compiler.functionClass) || 1861 if (checkedClasses.contains(compiler.functionClass) ||
1783 !checkedTypedefs.isEmpty) { 1862 !checkedFunctionTypes.isEmpty) {
1784 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1863 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1785 if (call == null) { 1864 if (call == null) {
1786 // If [cls] is a closure, it has a synthetic call operator method. 1865 // If [cls] is a closure, it has a synthetic call operator method.
1787 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1866 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1788 } 1867 }
1789 if (call != null && call.isFunction()) { 1868 if (call != null && call.isFunction()) {
1790 generateInterfacesIsTests(compiler.functionClass, 1869 generateInterfacesIsTests(compiler.functionClass,
1791 emitIsTest, 1870 emitIsTest,
1792 emitSubstitution, 1871 emitSubstitution,
1793 generated); 1872 generated);
1794 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1873 FunctionType callType = call.computeType(compiler);
1795 } 1874 Map<FunctionType, bool> functionTypeChecks =
1875 getFunctionTypeChecksOn(callType);
1876 generateFunctionTypeTests(call, callType, functionTypeChecks,
1877 emitFunctionTypeSignature, emitIsFunctionTypeTest);
1878 }
1796 } 1879 }
1797 1880
1798 for (DartType interfaceType in cls.interfaces) { 1881 for (DartType interfaceType in cls.interfaces) {
1799 generateInterfacesIsTests(interfaceType.element, emitIsTest, 1882 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1800 emitSubstitution, generated); 1883 emitSubstitution, generated);
1801 } 1884 }
1802 } 1885 }
1803 1886
1804 /** 1887 /**
1805 * Generate "is tests" where [cls] is being implemented. 1888 * Generate "is tests" where [cls] is being implemented.
1806 */ 1889 */
1807 void generateInterfacesIsTests(ClassElement cls, 1890 void generateInterfacesIsTests(ClassElement cls,
1808 void emitIsTest(ClassElement element), 1891 void emitIsTest(ClassElement element),
1809 void emitSubstitution(ClassElement element), 1892 SubstitutionEmitter emitSubstitution,
1810 Set<Element> alreadyGenerated) { 1893 Set<Element> alreadyGenerated) {
1811 void tryEmitTest(ClassElement check) { 1894 void tryEmitTest(ClassElement check) {
1812 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { 1895 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
1813 alreadyGenerated.add(check); 1896 alreadyGenerated.add(check);
1814 emitIsTest(check); 1897 emitIsTest(check);
1815 emitSubstitution(check); 1898 emitSubstitution(check);
1816 } 1899 }
1817 }; 1900 };
1818 1901
1819 tryEmitTest(cls); 1902 tryEmitTest(cls);
1820 1903
1821 for (DartType interfaceType in cls.interfaces) { 1904 for (DartType interfaceType in cls.interfaces) {
1822 Element element = interfaceType.element; 1905 Element element = interfaceType.element;
1823 tryEmitTest(element); 1906 tryEmitTest(element);
1824 generateInterfacesIsTests(element, emitIsTest, emitSubstitution, 1907 generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
1825 alreadyGenerated); 1908 alreadyGenerated);
1826 } 1909 }
1827 1910
1828 // We need to also emit "is checks" for the superclass and its supertypes. 1911 // We need to also emit "is checks" for the superclass and its supertypes.
1829 ClassElement superclass = cls.superclass; 1912 ClassElement superclass = cls.superclass;
1830 if (superclass != null) { 1913 if (superclass != null) {
1831 tryEmitTest(superclass); 1914 tryEmitTest(superclass);
1832 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, 1915 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
1833 alreadyGenerated); 1916 alreadyGenerated);
1834 } 1917 }
1835 } 1918 }
1836 1919
1920 const int MAX_FUNCTION_TYPE_PREDICATES = 10;
1921
1922 /**
1923 * Generates function type checks on [method] with type [methodType] against
1924 * the function type checks in [functionTypeChecks].
1925 */
1926 void generateFunctionTypeTests(
1927 Element method,
1928 FunctionType methodType,
1929 Map<FunctionType, bool> functionTypeChecks,
1930 FunctionTypeSignatureEmitter emitFunctionTypeSignature,
1931 FunctionTypeTestEmitter emitIsFunctionTypeTest) {
1932 bool hasDynamicFunctionTypeCheck = false;
1933 int neededPredicates = 0;
1934 functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
1935 if (!knownSubtype) {
1936 registerDynamicFunctionTypeCheck(functionType);
1937 hasDynamicFunctionTypeCheck = true;
1938 } else {
1939 neededPredicates++;
1940 }
1941 });
1942 bool alwaysUseSignature = false;
1943 if (hasDynamicFunctionTypeCheck ||
1944 neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) {
1945 emitFunctionTypeSignature(method, methodType);
1946 alwaysUseSignature = true;
1947 }
1948 functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
1949 if (knownSubtype) {
1950 if (alwaysUseSignature) {
1951 registerDynamicFunctionTypeCheck(functionType);
1952 } else {
1953 emitIsFunctionTypeTest(functionType);
1954 }
1955 }
1956 });
1957 }
1958
1837 /** 1959 /**
1838 * Return a function that returns true if its argument is a class 1960 * Return a function that returns true if its argument is a class
1839 * that needs to be emitted. 1961 * that needs to be emitted.
1840 */ 1962 */
1841 Function computeClassFilter() { 1963 Function computeClassFilter() {
1842 Set<ClassElement> unneededClasses = new Set<ClassElement>(); 1964 Set<ClassElement> unneededClasses = new Set<ClassElement>();
1843 // The [Bool] class is not marked as abstract, but has a factory 1965 // The [Bool] class is not marked as abstract, but has a factory
1844 // constructor that always throws. We never need to emit it. 1966 // constructor that always throws. We never need to emit it.
1845 unneededClasses.add(compiler.boolClass); 1967 unneededClasses.add(compiler.boolClass);
1846 1968
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1989 ClassBuilder closureBuilder = new ClassBuilder(); 2111 ClassBuilder closureBuilder = new ClassBuilder();
1990 // If a static function is used as a closure we need to add its name 2112 // If a static function is used as a closure we need to add its name
1991 // in case it is used in spawnFunction. 2113 // in case it is used in spawnFunction.
1992 String methodName = namer.STATIC_CLOSURE_NAME_NAME; 2114 String methodName = namer.STATIC_CLOSURE_NAME_NAME;
1993 emitClosureClassHeader( 2115 emitClosureClassHeader(
1994 mangledName, superName, <String>[invocationName, methodName], 2116 mangledName, superName, <String>[invocationName, methodName],
1995 closureBuilder); 2117 closureBuilder);
1996 2118
1997 addParameterStubs(callElement, closureBuilder.addProperty); 2119 addParameterStubs(callElement, closureBuilder.addProperty);
1998 2120
1999 DartType type = element.computeType(compiler);
2000 getTypedefChecksOn(type).forEach((Element typedef) {
2001 String operator = namer.operatorIs(typedef);
2002 closureBuilder.addProperty(operator, js('true'));
2003 });
2004
2005 // TODO(ngeoffray): Cache common base classes for closures, bound 2121 // TODO(ngeoffray): Cache common base classes for closures, bound
2006 // closures, and static closures that have common type checks. 2122 // closures, and static closures that have common type checks.
2007 boundClosures.add( 2123 boundClosures.add(
2008 js('$classesCollector.$mangledName = #', 2124 js('$classesCollector.$mangledName = #',
2009 closureBuilder.toObjectInitializer())); 2125 closureBuilder.toObjectInitializer()));
2010 2126
2011 staticGetters[element] = closureClassElement; 2127 staticGetters[element] = closureClassElement;
2128
2129 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
2130 RuntimeTypes rti = backend.rti;
2131 // [:() => null:] is dummy encoding of [this] which is never needed for
2132 // the encoding of the type of the static [method].
2133 String encoding = rti.getSignatureEncoding(methodType, () => 'null');
2134 String operatorSignature = namer.operatorSignature();
2135 // TODO(johnniwinther): Make MiniJsParser support function expressions.
2136 closureBuilder.addProperty(operatorSignature,
2137 new jsAst.LiteralExpression(encoding));
2138 }
2139
2140 void emitIsFunctionTypeTest(FunctionType functionType) {
2141 String operator = namer.operatorIsType(functionType);
2142 closureBuilder.addProperty(operator, js('true'));
2143 }
2144
2145 FunctionType methodType = element.computeType(compiler);
2146 Map<FunctionType, bool> functionTypeChecks =
2147 getFunctionTypeChecksOn(methodType);
2148 generateFunctionTypeTests(element, methodType, functionTypeChecks,
2149 emitFunctionTypeSignature, emitIsFunctionTypeTest);
2012 } 2150 }
2013 } 2151 }
2014 2152
2015 void emitClosureClassHeader(String mangledName, 2153 void emitClosureClassHeader(String mangledName,
2016 String superName, 2154 String superName,
2017 List<String> fieldNames, 2155 List<String> fieldNames,
2018 ClassBuilder builder) { 2156 ClassBuilder builder) {
2019 builder.addProperty('', 2157 builder.addProperty('',
2020 js.string("$superName;${fieldNames.join(',')}")); 2158 js.string("$superName;${fieldNames.join(',')}"));
2021 } 2159 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2059 if (inInterceptor) { 2197 if (inInterceptor) {
2060 cache = interceptorClosureCache; 2198 cache = interceptorClosureCache;
2061 } else { 2199 } else {
2062 cache = boundClosureCache; 2200 cache = boundClosureCache;
2063 } 2201 }
2064 List<String> fieldNames = <String>[]; 2202 List<String> fieldNames = <String>[];
2065 compiler.boundClosureClass.forEachInstanceField((_, Element field) { 2203 compiler.boundClosureClass.forEachInstanceField((_, Element field) {
2066 fieldNames.add(namer.getName(field)); 2204 fieldNames.add(namer.getName(field));
2067 }); 2205 });
2068 2206
2069 Iterable<Element> typedefChecks = 2207 DartType memberType = member.computeType(compiler);
2070 getTypedefChecksOn(member.computeType(compiler)); 2208 Map<FunctionType, bool> functionTypeChecks =
2071 bool hasTypedefChecks = !typedefChecks.isEmpty; 2209 getFunctionTypeChecksOn(memberType);
2210 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty;
2072 2211
2073 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 2212 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks;
2074 2213
2214 ClassElement classElement = member.getEnclosingClass();
2075 String closureClass = canBeShared ? cache[parameterCount] : null; 2215 String closureClass = canBeShared ? cache[parameterCount] : null;
2076 if (closureClass == null) { 2216 if (closureClass == null) {
2077 // Either the class was not cached yet, or there are optional parameters. 2217 // Either the class was not cached yet, or there are optional parameters.
2078 // Create a new closure class. 2218 // Create a new closure class.
2079 String name; 2219 String name;
2080 if (canBeShared) { 2220 if (canBeShared) {
2081 if (inInterceptor) { 2221 if (inInterceptor) {
2082 name = 'BoundClosure\$i${parameterCount}'; 2222 name = 'BoundClosure\$i${parameterCount}';
2083 } else { 2223 } else {
2084 name = 'BoundClosure\$${parameterCount}'; 2224 name = 'BoundClosure\$${parameterCount}';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2120 arguments.add(js(name)); 2260 arguments.add(js(name));
2121 } 2261 }
2122 2262
2123 jsAst.Expression fun = js.fun( 2263 jsAst.Expression fun = js.fun(
2124 parameters, 2264 parameters,
2125 js.return_( 2265 js.return_(
2126 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments))); 2266 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments)));
2127 boundClosureBuilder.addProperty(invocationName, fun); 2267 boundClosureBuilder.addProperty(invocationName, fun);
2128 2268
2129 addParameterStubs(callElement, boundClosureBuilder.addProperty); 2269 addParameterStubs(callElement, boundClosureBuilder.addProperty);
2130 typedefChecks.forEach((Element typedef) { 2270
2131 String operator = namer.operatorIs(typedef); 2271 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
2132 boundClosureBuilder.addProperty(operator, js('true')); 2272 String encoding = backend.rti.getSignatureEncoding(
2133 }); 2273 methodType, () => 'this.${fieldNames[0]}');
2274 String operatorSignature = namer.operatorSignature();
2275 boundClosureBuilder.addProperty(operatorSignature,
2276 new jsAst.LiteralExpression(encoding));
2277 }
2278
2279 void emitIsFunctionTypeTest(FunctionType functionType) {
2280 String operator = namer.operatorIsType(functionType);
2281 boundClosureBuilder.addProperty(operator,
2282 new jsAst.LiteralBool(true));
2283 }
2284
2285 generateFunctionTypeTests(member, memberType, functionTypeChecks,
2286 emitFunctionTypeSignature, emitIsFunctionTypeTest);
2134 2287
2135 boundClosures.add( 2288 boundClosures.add(
2136 js('$classesCollector.$mangledName = #', 2289 js('$classesCollector.$mangledName = #',
2137 boundClosureBuilder.toObjectInitializer())); 2290 boundClosureBuilder.toObjectInitializer()));
2138 2291
2139 closureClass = namer.isolateAccess(closureClassElement); 2292 closureClass = namer.isolateAccess(closureClassElement);
2140 2293
2141 // Cache it. 2294 // Cache it.
2142 if (canBeShared) { 2295 if (canBeShared) {
2143 cache[parameterCount] = closureClass; 2296 cache[parameterCount] = closureClass;
(...skipping 11 matching lines...) Expand all
2155 if (inInterceptor) { 2308 if (inInterceptor) {
2156 String receiverArg = fieldNames[2]; 2309 String receiverArg = fieldNames[2];
2157 parameters.add(receiverArg); 2310 parameters.add(receiverArg);
2158 arguments.add(js(receiverArg)); 2311 arguments.add(js(receiverArg));
2159 } else { 2312 } else {
2160 // Put null in the intercepted receiver field. 2313 // Put null in the intercepted receiver field.
2161 arguments.add(new jsAst.LiteralNull()); 2314 arguments.add(new jsAst.LiteralNull());
2162 } 2315 }
2163 2316
2164 jsAst.Expression getterFunction = js.fun( 2317 jsAst.Expression getterFunction = js.fun(
2165 parameters, 2318 parameters, js.return_(js(closureClass).newWith(arguments)));
2166 js.return_(js(closureClass).newWith(arguments)));
2167 2319
2168 defineStub(getterName, getterFunction); 2320 defineStub(getterName, getterFunction);
2169 } 2321 }
2170 2322
2171 /** 2323 /**
2172 * Documentation wanted -- johnniwinther 2324 * Documentation wanted -- johnniwinther
2173 * 2325 *
2174 * Invariant: [member] must be a declaration element. 2326 * Invariant: [member] must be a declaration element.
2175 */ 2327 */
2176 void emitCallStubForGetter(Element member, 2328 void emitCallStubForGetter(Element member,
(...skipping 19 matching lines...) Expand all
2196 ? member.fixedBackendName() 2348 ? member.fixedBackendName()
2197 : namer.instanceFieldName(member); 2349 : namer.instanceFieldName(member);
2198 return js('this')[fieldName]; 2350 return js('this')[fieldName];
2199 } 2351 }
2200 } 2352 }
2201 2353
2202 // Two selectors may match but differ only in type. To avoid generating 2354 // Two selectors may match but differ only in type. To avoid generating
2203 // identical stubs for each we track untyped selectors which already have 2355 // identical stubs for each we track untyped selectors which already have
2204 // stubs. 2356 // stubs.
2205 Set<Selector> generatedSelectors = new Set<Selector>(); 2357 Set<Selector> generatedSelectors = new Set<Selector>();
2206
2207 for (Selector selector in selectors) { 2358 for (Selector selector in selectors) {
2208 if (selector.applies(member, compiler)) { 2359 if (selector.applies(member, compiler)) {
2209 selector = selector.asUntyped; 2360 selector = selector.asUntyped;
2210 if (generatedSelectors.contains(selector)) continue; 2361 if (generatedSelectors.contains(selector)) continue;
2211 generatedSelectors.add(selector); 2362 generatedSelectors.add(selector);
2212 2363
2213 String invocationName = namer.invocationName(selector); 2364 String invocationName = namer.invocationName(selector);
2214 Selector callSelector = new Selector.callClosureFrom(selector); 2365 Selector callSelector = new Selector.callClosureFrom(selector);
2215 String closureCallName = namer.invocationName(callSelector); 2366 String closureCallName = namer.invocationName(callSelector);
2216 2367
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after
2801 }); 2952 });
2802 2953
2803 // 3b. Add classes that are referenced by substitutions in object checks and 2954 // 3b. Add classes that are referenced by substitutions in object checks and
2804 // their superclasses. 2955 // their superclasses.
2805 TypeChecks requiredChecks = 2956 TypeChecks requiredChecks =
2806 backend.rti.computeChecks(neededClasses, checkedClasses); 2957 backend.rti.computeChecks(neededClasses, checkedClasses);
2807 Set<ClassElement> classesUsedInSubstitutions = 2958 Set<ClassElement> classesUsedInSubstitutions =
2808 rti.getClassesUsedInSubstitutions(backend, requiredChecks); 2959 rti.getClassesUsedInSubstitutions(backend, requiredChecks);
2809 addClassesWithSuperclasses(classesUsedInSubstitutions); 2960 addClassesWithSuperclasses(classesUsedInSubstitutions);
2810 2961
2962 // 3c. Add classes that contain checked generic function types. These are
2963 // needed to store the signature encoding.
2964 for (FunctionType type in checkedFunctionTypes) {
2965 ClassElement contextClass = Types.getClassContext(type);
2966 if (contextClass != null) {
2967 neededClasses.add(contextClass);
2968 }
2969 }
2970
2811 // 4. Finally, sort the classes. 2971 // 4. Finally, sort the classes.
2812 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); 2972 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
2813 2973
2814 // If we need noSuchMethod support, we run through all needed 2974 // If we need noSuchMethod support, we run through all needed
2815 // classes to figure out if we need the support on any native 2975 // classes to figure out if we need the support on any native
2816 // class. If so, we let the native emitter deal with it. 2976 // class. If so, we let the native emitter deal with it.
2817 if (compiler.enabledNoSuchMethod) { 2977 if (compiler.enabledNoSuchMethod) {
2818 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD; 2978 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD;
2819 Selector noSuchMethodSelector = compiler.noSuchMethodSelector; 2979 Selector noSuchMethodSelector = compiler.noSuchMethodSelector;
2820 for (ClassElement element in sortedClasses) { 2980 for (ClassElement element in sortedClasses) {
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after
3452 3612
3453 const String HOOKS_API_USAGE = """ 3613 const String HOOKS_API_USAGE = """
3454 // The code supports the following hooks: 3614 // The code supports the following hooks:
3455 // dartPrint(message) - if this function is defined it is called 3615 // dartPrint(message) - if this function is defined it is called
3456 // instead of the Dart [print] method. 3616 // instead of the Dart [print] method.
3457 // dartMainRunner(main) - if this function is defined, the Dart [main] 3617 // dartMainRunner(main) - if this function is defined, the Dart [main]
3458 // method will not be invoked directly. 3618 // method will not be invoked directly.
3459 // Instead, a closure that will invoke [main] is 3619 // Instead, a closure that will invoke [main] is
3460 // passed to [dartMainRunner]. 3620 // passed to [dartMainRunner].
3461 """; 3621 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698