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

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: Minor fix Created 7 years, 5 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 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1312 1336
1313 void generateIsTest(Element other) { 1337 void generateIsTest(Element other) {
1314 if (other == compiler.objectClass && other != classElement) { 1338 if (other == compiler.objectClass && other != classElement) {
1315 // Avoid emitting [:$isObject:] on all classes but [Object]. 1339 // Avoid emitting [:$isObject:] on all classes but [Object].
1316 return; 1340 return;
1317 } 1341 }
1318 other = backend.getImplementationClass(other); 1342 other = backend.getImplementationClass(other);
1319 builder.addProperty(namer.operatorIs(other), js('true')); 1343 builder.addProperty(namer.operatorIs(other), js('true'));
1320 } 1344 }
1321 1345
1346 void generateIsFunctionTypeTest(FunctionType type) {
1347 String operator = namer.operatorIsType(type);
1348 builder.addProperty(operator, new jsAst.LiteralBool(true));
1349 }
1350
1351 void generateFunctionTypeSignature(Element method, FunctionType type) {
1352 assert(method.isImplementation);
1353 String thisAccess = 'this';
1354 Node node = method.parseNode(compiler);
1355 ClosureClassMap closureData =
1356 compiler.closureToClassMapper.closureMappingCache[node];
1357 if (closureData != null) {
1358 Element thisElement =
1359 closureData.freeVariableMapping[closureData.thisElement];
1360 if (thisElement != null) {
1361 String thisName = backend.namer.getName(thisElement);
1362 thisAccess = 'this.$thisName';
1363 }
1364 }
1365 RuntimeTypes rti = backend.rti;
1366 String encoding = rti.getSignatureEncoding(type, () => '$thisAccess');
1367 String operatorSignature = namer.operatorSignature();
1368 builder.addProperty(operatorSignature,
1369 new jsAst.LiteralExpression(encoding));
1370 }
1371
1322 void generateSubstitution(Element other, {bool emitNull: false}) { 1372 void generateSubstitution(Element other, {bool emitNull: false}) {
1323 RuntimeTypes rti = backend.rti; 1373 RuntimeTypes rti = backend.rti;
1324 // TODO(karlklose): support typedefs with variables.
1325 jsAst.Expression expression; 1374 jsAst.Expression expression;
1326 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1375 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1327 if (other.kind == ElementKind.CLASS) { 1376 if (other.kind == ElementKind.CLASS) {
1328 String substitution = rti.getSupertypeSubstitution(classElement, other, 1377 String substitution = rti.getSupertypeSubstitution(classElement, other,
1329 alwaysGenerateFunction: true); 1378 alwaysGenerateFunction: true);
1330 if (substitution != null) { 1379 if (substitution != null) {
1331 expression = new jsAst.LiteralExpression(substitution); 1380 expression = new jsAst.LiteralExpression(substitution);
1332 } else if (emitNull || needsNativeCheck) { 1381 } else if (emitNull || needsNativeCheck) {
1333 expression = new jsAst.LiteralNull(); 1382 expression = new jsAst.LiteralNull();
1334 } 1383 }
1335 } 1384 }
1336 if (expression != null) { 1385 if (expression != null) {
1337 builder.addProperty(namer.substitutionName(other), expression); 1386 builder.addProperty(namer.substitutionName(other), expression);
1338 } 1387 }
1339 } 1388 }
1340 1389
1341 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); 1390 generateIsTestsOn(classElement, generateIsTest,
1391 generateIsFunctionTypeTest, generateFunctionTypeSignature,
1392 generateSubstitution);
1342 } 1393 }
1343 1394
1344 void emitRuntimeTypeSupport(CodeBuffer buffer) { 1395 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1345 RuntimeTypes rti = backend.rti; 1396 RuntimeTypes rti = backend.rti;
1346 TypeChecks typeChecks = rti.requiredChecks; 1397 TypeChecks typeChecks = rti.requiredChecks;
1347 1398
1348 // Add checks to the constructors of instantiated classes. 1399 // Add checks to the constructors of instantiated classes.
1349 for (ClassElement cls in typeChecks) { 1400 for (ClassElement cls in typeChecks) {
1350 String holder = namer.isolateAccess(backend.getImplementationClass(cls)); 1401 String holder = namer.isolateAccess(backend.getImplementationClass(cls));
1351 for (TypeCheck check in typeChecks[cls]) { 1402 for (TypeCheck check in typeChecks[cls]) {
1352 ClassElement cls = check.cls; 1403 ClassElement cls = check.cls;
1353 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N'); 1404 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
1354 Substitution substitution = check.substitution; 1405 Substitution substitution = check.substitution;
1355 if (substitution != null) { 1406 if (substitution != null) {
1356 String body = substitution.getCode(rti, false); 1407 String body = substitution.getCode(rti, false);
1357 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N'); 1408 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N');
1358 } 1409 }
1359 }; 1410 };
1360 } 1411 }
1412
1413 void addSignature(FunctionType type) {
1414 String encoding = rti.getTypeEncoding(type);
1415 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N');
1416 }
1417
1418 checkedNonGenericFunctionTypes.forEach(addSignature);
1419
1420 checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
1421 functionTypes.forEach(addSignature);
1422 });
1361 } 1423 }
1362 1424
1363 /** 1425 /**
1364 * Documentation wanted -- johnniwinther 1426 * Documentation wanted -- johnniwinther
1365 * 1427 *
1366 * Invariant: [classElement] must be a declaration element. 1428 * Invariant: [classElement] must be a declaration element.
1367 */ 1429 */
1368 void visitClassFields(ClassElement classElement, 1430 void visitClassFields(ClassElement classElement,
1369 void addField(Element member, 1431 void addField(Element member,
1370 String name, 1432 String name,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1482 } 1544 }
1483 1545
1484 void generateCheckedSetter(Element member, 1546 void generateCheckedSetter(Element member,
1485 String fieldName, 1547 String fieldName,
1486 String accessorName, 1548 String accessorName,
1487 ClassBuilder builder) { 1549 ClassBuilder builder) {
1488 assert(canGenerateCheckedSetter(member)); 1550 assert(canGenerateCheckedSetter(member));
1489 DartType type = member.computeType(compiler); 1551 DartType type = member.computeType(compiler);
1490 // TODO(ahe): Generate a dynamic type error here. 1552 // TODO(ahe): Generate a dynamic type error here.
1491 if (type.element.isErroneous()) return; 1553 if (type.element.isErroneous()) return;
1492 FunctionElement helperElement 1554 type = type.unalias(compiler);
1493 = backend.getCheckedModeHelper(type, typeCast: false); 1555 CheckedModeHelper helper =
1556 backend.getCheckedModeHelper(type, typeCast: false);
1557 FunctionElement helperElement = helper.getElement(compiler);
1494 String helperName = namer.isolateAccess(helperElement); 1558 String helperName = namer.isolateAccess(helperElement);
1495 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')]; 1559 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
1496 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1560 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1497 arguments.add(js.string(namer.operatorIs(type.element))); 1561 arguments.add(js.string(namer.operatorIsType(type)));
1498 } 1562 }
1499 1563
1500 String setterName = namer.setterNameFromAccessorName(accessorName); 1564 String setterName = namer.setterNameFromAccessorName(accessorName);
1501 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1565 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1502 ? 'receiver' : 'this'; 1566 ? 'receiver' : 'this';
1503 List<String> args = backend.isInterceptedMethod(member) 1567 List<String> args = backend.isInterceptedMethod(member)
1504 ? ['receiver', 'v'] 1568 ? ['receiver', 'v']
1505 : ['v']; 1569 : ['v'];
1506 builder.addProperty(setterName, 1570 builder.addProperty(setterName,
1507 js.fun(args, 1571 js.fun(args,
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 return arity; 1792 return arity;
1729 } 1793 }
1730 1794
1731 int _compareSelectorNames(Selector selector1, Selector selector2) { 1795 int _compareSelectorNames(Selector selector1, Selector selector2) {
1732 String name1 = selector1.name.toString(); 1796 String name1 = selector1.name.toString();
1733 String name2 = selector2.name.toString(); 1797 String name2 = selector2.name.toString();
1734 if (name1 != name2) return Comparable.compare(name1, name2); 1798 if (name1 != name2) return Comparable.compare(name1, name2);
1735 return _selectorRank(selector1) - _selectorRank(selector2); 1799 return _selectorRank(selector1) - _selectorRank(selector2);
1736 } 1800 }
1737 1801
1738 Iterable<Element> getTypedefChecksOn(DartType type) { 1802 /**
1739 bool isSubtype(TypedefElement typedef) { 1803 * Returns a mapping containing all checked function types for which [type]
1740 FunctionType typedefType = 1804 * can be a subtype. A function type is mapped to [:true:] if [type] is
1741 typedef.computeType(compiler).unalias(compiler); 1805 * statically known to be a subtype of it and to [:false:] if [type] might
1742 return compiler.types.isSubtype(type, typedefType); 1806 * be a subtype, provided with the right type arguments.
1807 */
1808 // TODO(johnniwinther): Change to return a mapping from function types to
1809 // a set of variable points and use this to detect statically/dynamically
1810 // known subtype relations.
1811 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) {
1812 Map<FunctionType, bool> functionTypeMap =
1813 new LinkedHashMap<FunctionType, bool>();
1814 for (FunctionType functionType in checkedFunctionTypes) {
1815 if (compiler.types.isSubtype(type, functionType)) {
1816 functionTypeMap[functionType] = true;
1817 } else if (compiler.types.isPotentialSubtype(type, functionType)) {
1818 functionTypeMap[functionType] = false;
1819 }
1743 } 1820 }
1744 return checkedTypedefs.where(isSubtype).toList() 1821 // TODO(johnniwinther): Ensure stable ordering of the keys.
1745 ..sort(Elements.compareByPosition); 1822 return functionTypeMap;
1746 } 1823 }
1747 1824
1748 /** 1825 /**
1749 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1826 * Generate "is tests" for [cls]: itself, and the "is tests" for the
1750 * classes it implements and type argument substitution functions for these 1827 * classes it implements and type argument substitution functions for these
1751 * tests. We don't need to add the "is tests" of the super class because 1828 * tests. We don't need to add the "is tests" of the super class because
1752 * they will be inherited at runtime, but we may need to generate the 1829 * they will be inherited at runtime, but we may need to generate the
1753 * substitutions, because they may have changed. 1830 * substitutions, because they may have changed.
1754 */ 1831 */
1755 void generateIsTestsOn(ClassElement cls, 1832 void generateIsTestsOn(ClassElement cls,
1756 void emitIsTest(Element element), 1833 void emitIsTest(Element element),
1757 void emitSubstitution(Element element, {emitNull})) { 1834 FunctionTypeTestEmitter emitIsFunctionTypeTest,
1835 FunctionTypeSignatureEmitter emitFunctionTypeSignature,
1836 SubstitutionEmitter emitSubstitution) {
1758 if (checkedClasses.contains(cls)) { 1837 if (checkedClasses.contains(cls)) {
1759 emitIsTest(cls); 1838 emitIsTest(cls);
1760 emitSubstitution(cls); 1839 emitSubstitution(cls);
1761 } 1840 }
1762 1841
1763 RuntimeTypes rti = backend.rti; 1842 RuntimeTypes rti = backend.rti;
1764 ClassElement superclass = cls.superclass; 1843 ClassElement superclass = cls.superclass;
1765 1844
1766 bool haveSameTypeVariables(ClassElement a, ClassElement b) { 1845 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
1767 if (a.isClosure()) return true; 1846 if (a.isClosure()) return true;
1768 return a.typeVariables == b.typeVariables; 1847 return a.typeVariables == b.typeVariables;
1769 } 1848 }
1770 1849
1771 if (superclass != null && superclass != compiler.objectClass && 1850 if (superclass != null && superclass != compiler.objectClass &&
1772 !haveSameTypeVariables(cls, superclass)) { 1851 !haveSameTypeVariables(cls, superclass)) {
1773 // We cannot inherit the generated substitutions, because the type 1852 // We cannot inherit the generated substitutions, because the type
1774 // variable layout for this class is different. Instead we generate 1853 // variable layout for this class is different. Instead we generate
1775 // substitutions for all checks and make emitSubstitution a NOP for the 1854 // substitutions for all checks and make emitSubstitution a NOP for the
1776 // rest of this function. 1855 // rest of this function.
1777 Set<ClassElement> emitted = new Set<ClassElement>(); 1856 Set<ClassElement> emitted = new Set<ClassElement>();
1778 // TODO(karlklose): move the computation of these checks to 1857 // TODO(karlklose): move the computation of these checks to
1779 // RuntimeTypeInformation. 1858 // RuntimeTypeInformation.
1780 if (backend.needsRti(cls)) { 1859 if (backend.classNeedsRti(cls)) {
1781 emitSubstitution(superclass, emitNull: true); 1860 emitSubstitution(superclass, emitNull: true);
1782 emitted.add(superclass); 1861 emitted.add(superclass);
1783 } 1862 }
1784 for (DartType supertype in cls.allSupertypes) { 1863 for (DartType supertype in cls.allSupertypes) {
1785 ClassElement superclass = supertype.element; 1864 ClassElement superclass = supertype.element;
1786 if (classesUsingTypeVariableTests.contains(superclass)) { 1865 if (classesUsingTypeVariableTests.contains(superclass)) {
1787 emitSubstitution(superclass, emitNull: true); 1866 emitSubstitution(superclass, emitNull: true);
1788 emitted.add(superclass); 1867 emitted.add(superclass);
1789 } 1868 }
1790 for (ClassElement check in checkedClasses) { 1869 for (ClassElement check in checkedClasses) {
1791 if (supertype.element == check && !emitted.contains(check)) { 1870 if (supertype.element == check && !emitted.contains(check)) {
1792 // Generate substitution. If no substitution is necessary, emit 1871 // Generate substitution. If no substitution is necessary, emit
1793 // [:null:] to overwrite a (possibly) existing substitution from the 1872 // [:null:] to overwrite a (possibly) existing substitution from the
1794 // super classes. 1873 // super classes.
1795 emitSubstitution(check, emitNull: true); 1874 emitSubstitution(check, emitNull: true);
1796 emitted.add(check); 1875 emitted.add(check);
1797 } 1876 }
1798 } 1877 }
1799 } 1878 }
1800 void emitNothing(_, {emitNull}) {}; 1879 void emitNothing(_, {emitNull}) {};
1801 emitSubstitution = emitNothing; 1880 emitSubstitution = emitNothing;
1802 } 1881 }
1803 1882
1804 Set<Element> generated = new Set<Element>(); 1883 Set<Element> generated = new Set<Element>();
1805 // A class that defines a [:call:] method implicitly implements 1884 // A class that defines a [:call:] method implicitly implements
1806 // [Function] and needs checks for all typedefs that are used in is-checks. 1885 // [Function] and needs checks for all typedefs that are used in is-checks.
1807 if (checkedClasses.contains(compiler.functionClass) || 1886 if (checkedClasses.contains(compiler.functionClass) ||
1808 !checkedTypedefs.isEmpty) { 1887 !checkedFunctionTypes.isEmpty) {
1809 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1888 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1810 if (call == null) { 1889 if (call == null) {
1811 // If [cls] is a closure, it has a synthetic call operator method. 1890 // If [cls] is a closure, it has a synthetic call operator method.
1812 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1891 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1813 } 1892 }
1814 if (call != null && call.isFunction()) { 1893 if (call != null && call.isFunction()) {
1815 generateInterfacesIsTests(compiler.functionClass, 1894 generateInterfacesIsTests(compiler.functionClass,
1816 emitIsTest, 1895 emitIsTest,
1817 emitSubstitution, 1896 emitSubstitution,
1818 generated); 1897 generated);
1819 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1898 FunctionType callType = call.computeType(compiler);
1820 } 1899 Map<FunctionType, bool> functionTypeChecks =
1900 getFunctionTypeChecksOn(callType);
1901 generateFunctionTypeTests(call, callType, functionTypeChecks,
1902 emitFunctionTypeSignature, emitIsFunctionTypeTest);
1903 }
1821 } 1904 }
1822 1905
1823 for (DartType interfaceType in cls.interfaces) { 1906 for (DartType interfaceType in cls.interfaces) {
1824 generateInterfacesIsTests(interfaceType.element, emitIsTest, 1907 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1825 emitSubstitution, generated); 1908 emitSubstitution, generated);
1826 } 1909 }
1827 } 1910 }
1828 1911
1829 /** 1912 /**
1830 * Generate "is tests" where [cls] is being implemented. 1913 * Generate "is tests" where [cls] is being implemented.
1831 */ 1914 */
1832 void generateInterfacesIsTests(ClassElement cls, 1915 void generateInterfacesIsTests(ClassElement cls,
1833 void emitIsTest(ClassElement element), 1916 void emitIsTest(ClassElement element),
1834 void emitSubstitution(ClassElement element), 1917 SubstitutionEmitter emitSubstitution,
1835 Set<Element> alreadyGenerated) { 1918 Set<Element> alreadyGenerated) {
1836 void tryEmitTest(ClassElement check) { 1919 void tryEmitTest(ClassElement check) {
1837 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { 1920 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
1838 alreadyGenerated.add(check); 1921 alreadyGenerated.add(check);
1839 emitIsTest(check); 1922 emitIsTest(check);
1840 emitSubstitution(check); 1923 emitSubstitution(check);
1841 } 1924 }
1842 }; 1925 };
1843 1926
1844 tryEmitTest(cls); 1927 tryEmitTest(cls);
1845 1928
1846 for (DartType interfaceType in cls.interfaces) { 1929 for (DartType interfaceType in cls.interfaces) {
1847 Element element = interfaceType.element; 1930 Element element = interfaceType.element;
1848 tryEmitTest(element); 1931 tryEmitTest(element);
1849 generateInterfacesIsTests(element, emitIsTest, emitSubstitution, 1932 generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
1850 alreadyGenerated); 1933 alreadyGenerated);
1851 } 1934 }
1852 1935
1853 // We need to also emit "is checks" for the superclass and its supertypes. 1936 // We need to also emit "is checks" for the superclass and its supertypes.
1854 ClassElement superclass = cls.superclass; 1937 ClassElement superclass = cls.superclass;
1855 if (superclass != null) { 1938 if (superclass != null) {
1856 tryEmitTest(superclass); 1939 tryEmitTest(superclass);
1857 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, 1940 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
1858 alreadyGenerated); 1941 alreadyGenerated);
1859 } 1942 }
1860 } 1943 }
1861 1944
1945 static const int MAX_FUNCTION_TYPE_PREDICATES = 10;
1946
1947 /**
1948 * Generates function type checks on [method] with type [methodType] against
1949 * the function type checks in [functionTypeChecks].
1950 */
1951 void generateFunctionTypeTests(
1952 Element method,
1953 FunctionType methodType,
1954 Map<FunctionType, bool> functionTypeChecks,
1955 FunctionTypeSignatureEmitter emitFunctionTypeSignature,
1956 FunctionTypeTestEmitter emitIsFunctionTypeTest) {
1957 bool hasDynamicFunctionTypeCheck = false;
1958 int neededPredicates = 0;
1959 functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
1960 if (!knownSubtype) {
1961 registerDynamicFunctionTypeCheck(functionType);
1962 hasDynamicFunctionTypeCheck = true;
1963 } else {
1964 neededPredicates++;
1965 }
1966 });
1967 bool alwaysUseSignature = false;
1968 if (hasDynamicFunctionTypeCheck ||
1969 neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) {
1970 emitFunctionTypeSignature(method, methodType);
1971 alwaysUseSignature = true;
1972 }
1973 functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
1974 if (knownSubtype) {
1975 if (alwaysUseSignature) {
1976 registerDynamicFunctionTypeCheck(functionType);
1977 } else {
1978 emitIsFunctionTypeTest(functionType);
1979 }
1980 }
1981 });
1982 }
1983
1862 /** 1984 /**
1863 * Return a function that returns true if its argument is a class 1985 * Return a function that returns true if its argument is a class
1864 * that needs to be emitted. 1986 * that needs to be emitted.
1865 */ 1987 */
1866 Function computeClassFilter() { 1988 Function computeClassFilter() {
1867 Set<ClassElement> unneededClasses = new Set<ClassElement>(); 1989 Set<ClassElement> unneededClasses = new Set<ClassElement>();
1868 // The [Bool] class is not marked as abstract, but has a factory 1990 // The [Bool] class is not marked as abstract, but has a factory
1869 // constructor that always throws. We never need to emit it. 1991 // constructor that always throws. We never need to emit it.
1870 unneededClasses.add(compiler.boolClass); 1992 unneededClasses.add(compiler.boolClass);
1871 1993
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
2014 ClassBuilder closureBuilder = new ClassBuilder(); 2136 ClassBuilder closureBuilder = new ClassBuilder();
2015 // If a static function is used as a closure we need to add its name 2137 // If a static function is used as a closure we need to add its name
2016 // in case it is used in spawnFunction. 2138 // in case it is used in spawnFunction.
2017 String methodName = namer.STATIC_CLOSURE_NAME_NAME; 2139 String methodName = namer.STATIC_CLOSURE_NAME_NAME;
2018 emitClosureClassHeader( 2140 emitClosureClassHeader(
2019 mangledName, superName, <String>[invocationName, methodName], 2141 mangledName, superName, <String>[invocationName, methodName],
2020 closureBuilder); 2142 closureBuilder);
2021 2143
2022 addParameterStubs(callElement, closureBuilder.addProperty); 2144 addParameterStubs(callElement, closureBuilder.addProperty);
2023 2145
2024 DartType type = element.computeType(compiler);
2025 getTypedefChecksOn(type).forEach((Element typedef) {
2026 String operator = namer.operatorIs(typedef);
2027 closureBuilder.addProperty(operator, js('true'));
2028 });
2029
2030 // TODO(ngeoffray): Cache common base classes for closures, bound 2146 // TODO(ngeoffray): Cache common base classes for closures, bound
2031 // closures, and static closures that have common type checks. 2147 // closures, and static closures that have common type checks.
2032 boundClosures.add( 2148 boundClosures.add(
2033 js('$classesCollector.$mangledName = #', 2149 js('$classesCollector.$mangledName = #',
2034 closureBuilder.toObjectInitializer())); 2150 closureBuilder.toObjectInitializer()));
2035 2151
2036 staticGetters[element] = closureClassElement; 2152 staticGetters[element] = closureClassElement;
2153
2154 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
2155 RuntimeTypes rti = backend.rti;
2156 // [:() => null:] is dummy encoding of [this] which is never needed for
2157 // the encoding of the type of the static [method].
2158 String encoding = rti.getSignatureEncoding(methodType, () => 'null');
2159 String operatorSignature = namer.operatorSignature();
2160 // TODO(johnniwinther): Make MiniJsParser support function expressions.
2161 closureBuilder.addProperty(operatorSignature,
2162 new jsAst.LiteralExpression(encoding));
2163 }
2164
2165 void emitIsFunctionTypeTest(FunctionType functionType) {
2166 String operator = namer.operatorIsType(functionType);
2167 closureBuilder.addProperty(operator, js('true'));
2168 }
2169
2170 FunctionType methodType = element.computeType(compiler);
2171 Map<FunctionType, bool> functionTypeChecks =
2172 getFunctionTypeChecksOn(methodType);
2173 generateFunctionTypeTests(element, methodType, functionTypeChecks,
2174 emitFunctionTypeSignature, emitIsFunctionTypeTest);
2037 } 2175 }
2038 } 2176 }
2039 2177
2040 void emitClosureClassHeader(String mangledName, 2178 void emitClosureClassHeader(String mangledName,
2041 String superName, 2179 String superName,
2042 List<String> fieldNames, 2180 List<String> fieldNames,
2043 ClassBuilder builder) { 2181 ClassBuilder builder) {
2044 builder.addProperty('', 2182 builder.addProperty('',
2045 js.string("$superName;${fieldNames.join(',')}")); 2183 js.string("$superName;${fieldNames.join(',')}"));
2046 } 2184 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2084 if (inInterceptor) { 2222 if (inInterceptor) {
2085 cache = interceptorClosureCache; 2223 cache = interceptorClosureCache;
2086 } else { 2224 } else {
2087 cache = boundClosureCache; 2225 cache = boundClosureCache;
2088 } 2226 }
2089 List<String> fieldNames = <String>[]; 2227 List<String> fieldNames = <String>[];
2090 compiler.boundClosureClass.forEachInstanceField((_, Element field) { 2228 compiler.boundClosureClass.forEachInstanceField((_, Element field) {
2091 fieldNames.add(namer.getName(field)); 2229 fieldNames.add(namer.getName(field));
2092 }); 2230 });
2093 2231
2094 Iterable<Element> typedefChecks = 2232 DartType memberType = member.computeType(compiler);
2095 getTypedefChecksOn(member.computeType(compiler)); 2233 Map<FunctionType, bool> functionTypeChecks =
2096 bool hasTypedefChecks = !typedefChecks.isEmpty; 2234 getFunctionTypeChecksOn(memberType);
2235 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty;
2097 2236
2098 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 2237 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks;
2099 2238
2239 ClassElement classElement = member.getEnclosingClass();
2100 String closureClass = canBeShared ? cache[parameterCount] : null; 2240 String closureClass = canBeShared ? cache[parameterCount] : null;
2101 if (closureClass == null) { 2241 if (closureClass == null) {
2102 // Either the class was not cached yet, or there are optional parameters. 2242 // Either the class was not cached yet, or there are optional parameters.
2103 // Create a new closure class. 2243 // Create a new closure class.
2104 String name; 2244 String name;
2105 if (canBeShared) { 2245 if (canBeShared) {
2106 if (inInterceptor) { 2246 if (inInterceptor) {
2107 name = 'BoundClosure\$i${parameterCount}'; 2247 name = 'BoundClosure\$i${parameterCount}';
2108 } else { 2248 } else {
2109 name = 'BoundClosure\$${parameterCount}'; 2249 name = 'BoundClosure\$${parameterCount}';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2145 arguments.add(js(name)); 2285 arguments.add(js(name));
2146 } 2286 }
2147 2287
2148 jsAst.Expression fun = js.fun( 2288 jsAst.Expression fun = js.fun(
2149 parameters, 2289 parameters,
2150 js.return_( 2290 js.return_(
2151 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments))); 2291 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments)));
2152 boundClosureBuilder.addProperty(invocationName, fun); 2292 boundClosureBuilder.addProperty(invocationName, fun);
2153 2293
2154 addParameterStubs(callElement, boundClosureBuilder.addProperty); 2294 addParameterStubs(callElement, boundClosureBuilder.addProperty);
2155 typedefChecks.forEach((Element typedef) { 2295
2156 String operator = namer.operatorIs(typedef); 2296 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
2157 boundClosureBuilder.addProperty(operator, js('true')); 2297 String encoding = backend.rti.getSignatureEncoding(
2158 }); 2298 methodType, () => 'this.${fieldNames[0]}');
2299 String operatorSignature = namer.operatorSignature();
2300 boundClosureBuilder.addProperty(operatorSignature,
2301 new jsAst.LiteralExpression(encoding));
2302 }
2303
2304 void emitIsFunctionTypeTest(FunctionType functionType) {
2305 String operator = namer.operatorIsType(functionType);
2306 boundClosureBuilder.addProperty(operator,
2307 new jsAst.LiteralBool(true));
2308 }
2309
2310 generateFunctionTypeTests(member, memberType, functionTypeChecks,
2311 emitFunctionTypeSignature, emitIsFunctionTypeTest);
2159 2312
2160 boundClosures.add( 2313 boundClosures.add(
2161 js('$classesCollector.$mangledName = #', 2314 js('$classesCollector.$mangledName = #',
2162 boundClosureBuilder.toObjectInitializer())); 2315 boundClosureBuilder.toObjectInitializer()));
2163 2316
2164 closureClass = namer.isolateAccess(closureClassElement); 2317 closureClass = namer.isolateAccess(closureClassElement);
2165 2318
2166 // Cache it. 2319 // Cache it.
2167 if (canBeShared) { 2320 if (canBeShared) {
2168 cache[parameterCount] = closureClass; 2321 cache[parameterCount] = closureClass;
(...skipping 11 matching lines...) Expand all
2180 if (inInterceptor) { 2333 if (inInterceptor) {
2181 String receiverArg = fieldNames[2]; 2334 String receiverArg = fieldNames[2];
2182 parameters.add(receiverArg); 2335 parameters.add(receiverArg);
2183 arguments.add(js(receiverArg)); 2336 arguments.add(js(receiverArg));
2184 } else { 2337 } else {
2185 // Put null in the intercepted receiver field. 2338 // Put null in the intercepted receiver field.
2186 arguments.add(new jsAst.LiteralNull()); 2339 arguments.add(new jsAst.LiteralNull());
2187 } 2340 }
2188 2341
2189 jsAst.Expression getterFunction = js.fun( 2342 jsAst.Expression getterFunction = js.fun(
2190 parameters, 2343 parameters, js.return_(js(closureClass).newWith(arguments)));
2191 js.return_(js(closureClass).newWith(arguments)));
2192 2344
2193 defineStub(getterName, getterFunction); 2345 defineStub(getterName, getterFunction);
2194 } 2346 }
2195 2347
2196 /** 2348 /**
2197 * Documentation wanted -- johnniwinther 2349 * Documentation wanted -- johnniwinther
2198 * 2350 *
2199 * Invariant: [member] must be a declaration element. 2351 * Invariant: [member] must be a declaration element.
2200 */ 2352 */
2201 void emitCallStubForGetter(Element member, 2353 void emitCallStubForGetter(Element member,
(...skipping 19 matching lines...) Expand all
2221 ? member.fixedBackendName() 2373 ? member.fixedBackendName()
2222 : namer.instanceFieldName(member); 2374 : namer.instanceFieldName(member);
2223 return js('this')[fieldName]; 2375 return js('this')[fieldName];
2224 } 2376 }
2225 } 2377 }
2226 2378
2227 // Two selectors may match but differ only in type. To avoid generating 2379 // Two selectors may match but differ only in type. To avoid generating
2228 // identical stubs for each we track untyped selectors which already have 2380 // identical stubs for each we track untyped selectors which already have
2229 // stubs. 2381 // stubs.
2230 Set<Selector> generatedSelectors = new Set<Selector>(); 2382 Set<Selector> generatedSelectors = new Set<Selector>();
2231
2232 for (Selector selector in selectors) { 2383 for (Selector selector in selectors) {
2233 if (selector.applies(member, compiler)) { 2384 if (selector.applies(member, compiler)) {
2234 selector = selector.asUntyped; 2385 selector = selector.asUntyped;
2235 if (generatedSelectors.contains(selector)) continue; 2386 if (generatedSelectors.contains(selector)) continue;
2236 generatedSelectors.add(selector); 2387 generatedSelectors.add(selector);
2237 2388
2238 String invocationName = namer.invocationName(selector); 2389 String invocationName = namer.invocationName(selector);
2239 Selector callSelector = new Selector.callClosureFrom(selector); 2390 Selector callSelector = new Selector.callClosureFrom(selector);
2240 String closureCallName = namer.invocationName(callSelector); 2391 String closureCallName = namer.invocationName(callSelector);
2241 2392
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after
2826 }); 2977 });
2827 2978
2828 // 3b. Add classes that are referenced by substitutions in object checks and 2979 // 3b. Add classes that are referenced by substitutions in object checks and
2829 // their superclasses. 2980 // their superclasses.
2830 TypeChecks requiredChecks = 2981 TypeChecks requiredChecks =
2831 backend.rti.computeChecks(neededClasses, checkedClasses); 2982 backend.rti.computeChecks(neededClasses, checkedClasses);
2832 Set<ClassElement> classesUsedInSubstitutions = 2983 Set<ClassElement> classesUsedInSubstitutions =
2833 rti.getClassesUsedInSubstitutions(backend, requiredChecks); 2984 rti.getClassesUsedInSubstitutions(backend, requiredChecks);
2834 addClassesWithSuperclasses(classesUsedInSubstitutions); 2985 addClassesWithSuperclasses(classesUsedInSubstitutions);
2835 2986
2987 // 3c. Add classes that contain checked generic function types. These are
2988 // needed to store the signature encoding.
2989 for (FunctionType type in checkedFunctionTypes) {
2990 ClassElement contextClass = Types.getClassContext(type);
2991 if (contextClass != null) {
2992 neededClasses.add(contextClass);
2993 }
2994 }
2995
2836 // 4. Finally, sort the classes. 2996 // 4. Finally, sort the classes.
2837 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); 2997 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
2838 2998
2839 // If we need noSuchMethod support, we run through all needed 2999 // If we need noSuchMethod support, we run through all needed
2840 // classes to figure out if we need the support on any native 3000 // classes to figure out if we need the support on any native
2841 // class. If so, we let the native emitter deal with it. 3001 // class. If so, we let the native emitter deal with it.
2842 if (compiler.enabledNoSuchMethod) { 3002 if (compiler.enabledNoSuchMethod) {
2843 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD; 3003 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD;
2844 Selector noSuchMethodSelector = compiler.noSuchMethodSelector; 3004 Selector noSuchMethodSelector = compiler.noSuchMethodSelector;
2845 for (ClassElement element in sortedClasses) { 3005 for (ClassElement element in sortedClasses) {
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after
3480 3640
3481 const String HOOKS_API_USAGE = """ 3641 const String HOOKS_API_USAGE = """
3482 // The code supports the following hooks: 3642 // The code supports the following hooks:
3483 // dartPrint(message) - if this function is defined it is called 3643 // dartPrint(message) - if this function is defined it is called
3484 // instead of the Dart [print] method. 3644 // instead of the Dart [print] method.
3485 // dartMainRunner(main) - if this function is defined, the Dart [main] 3645 // dartMainRunner(main) - if this function is defined, the Dart [main]
3486 // method will not be invoked directly. 3646 // method will not be invoked directly.
3487 // Instead, a closure that will invoke [main] is 3647 // Instead, a closure that will invoke [main] is
3488 // passed to [dartMainRunner]. 3648 // passed to [dartMainRunner].
3489 """; 3649 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698