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

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

Issue 17413013: Revert "Support runtime check of function types." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
58 /** 51 /**
59 * Generates the code for all used classes in the program. Static fields (even 52 * Generates the code for all used classes in the program. Static fields (even
60 * in classes) are ignored, since they can be treated as non-class elements. 53 * in classes) are ignored, since they can be treated as non-class elements.
61 * 54 *
62 * The code for the containing (used) methods must exist in the [:universe:]. 55 * The code for the containing (used) methods must exist in the [:universe:].
63 */ 56 */
64 class CodeEmitterTask extends CompilerTask { 57 class CodeEmitterTask extends CompilerTask {
65 bool needsInheritFunction = false; 58 bool needsInheritFunction = false;
66 bool needsDefineClass = false; 59 bool needsDefineClass = false;
67 bool needsMixinSupport = false; 60 bool needsMixinSupport = false;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 105
113 /** 106 /**
114 * Raw ClassElement symbols occuring in is-checks and type assertions. If the 107 * Raw ClassElement symbols occuring in is-checks and type assertions. If the
115 * program contains parameterized checks `x is Set<int>` and 108 * program contains parameterized checks `x is Set<int>` and
116 * `x is Set<String>` then the ClassElement `Set` will occur once in 109 * `x is Set<String>` then the ClassElement `Set` will occur once in
117 * [checkedClasses]. 110 * [checkedClasses].
118 */ 111 */
119 Set<ClassElement> checkedClasses; 112 Set<ClassElement> checkedClasses;
120 113
121 /** 114 /**
122 * The set of function types that checked, both explicity through tests of 115 * Raw Typedef symbols occuring in is-checks and type assertions. If the
123 * typedefs and implicitly through type annotations in checked mode. 116 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement
117 * `F` will occur once in [checkedTypedefs].
124 */ 118 */
125 Set<FunctionType> checkedFunctionTypes; 119 Set<TypedefElement> checkedTypedefs;
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 }
142 120
143 final bool generateSourceMap; 121 final bool generateSourceMap;
144 122
145 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; 123 Iterable<ClassElement> cachedClassesUsingTypeVariableTests;
146 124
147 Iterable<ClassElement> get classesUsingTypeVariableTests { 125 Iterable<ClassElement> get classesUsingTypeVariableTests {
148 if (cachedClassesUsingTypeVariableTests == null) { 126 if (cachedClassesUsingTypeVariableTests == null) {
149 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks 127 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks
150 .where((DartType t) => t is TypeVariableType) 128 .where((DartType t) => t is TypeVariableType)
151 .map((TypeVariableType v) => v.element.getEnclosingClass()) 129 .map((TypeVariableType v) => v.element.getEnclosingClass())
(...skipping 10 matching lines...) Expand all
162 constantEmitter = new ConstantEmitter(compiler, namer), 140 constantEmitter = new ConstantEmitter(compiler, namer),
163 super(compiler) { 141 super(compiler) {
164 nativeEmitter = new NativeEmitter(this); 142 nativeEmitter = new NativeEmitter(this);
165 } 143 }
166 144
167 void addComment(String comment, CodeBuffer buffer) { 145 void addComment(String comment, CodeBuffer buffer) {
168 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); 146 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler));
169 } 147 }
170 148
171 void computeRequiredTypeChecks() { 149 void computeRequiredTypeChecks() {
172 assert(checkedClasses == null && checkedFunctionTypes == null); 150 assert(checkedClasses == null && checkedTypedefs == null);
173 151
174 backend.rti.addImplicitChecks(compiler.codegenWorld, 152 backend.rti.addImplicitChecks(compiler.codegenWorld,
175 classesUsingTypeVariableTests); 153 classesUsingTypeVariableTests);
176 154
177 checkedClasses = new Set<ClassElement>(); 155 checkedClasses = new Set<ClassElement>();
178 checkedFunctionTypes = new Set<FunctionType>(); 156 checkedTypedefs = new Set<TypedefElement>();
179 compiler.codegenWorld.isChecks.forEach((DartType t) { 157 compiler.codegenWorld.isChecks.forEach((DartType t) {
180 if (!t.isMalformed) { 158 if (t is InterfaceType) {
181 if (t is InterfaceType) { 159 checkedClasses.add(t.element);
182 checkedClasses.add(t.element); 160 } else if (t is TypedefType) {
183 } else if (t is FunctionType) { 161 checkedTypedefs.add(t.element);
184 checkedFunctionTypes.add(t);
185 }
186 } 162 }
187 }); 163 });
188 } 164 }
189 165
190 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) { 166 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) {
191 ClassElement mixin = mixinApplication.mixin; 167 ClassElement mixin = mixinApplication.mixin;
192 while (mixin.isMixinApplication) { 168 while (mixin.isMixinApplication) {
193 mixinApplication = mixin; 169 mixinApplication = mixin;
194 mixin = mixinApplication.mixin; 170 mixin = mixinApplication.mixin;
195 } 171 }
(...skipping 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1336 1312
1337 void generateIsTest(Element other) { 1313 void generateIsTest(Element other) {
1338 if (other == compiler.objectClass && other != classElement) { 1314 if (other == compiler.objectClass && other != classElement) {
1339 // Avoid emitting [:$isObject:] on all classes but [Object]. 1315 // Avoid emitting [:$isObject:] on all classes but [Object].
1340 return; 1316 return;
1341 } 1317 }
1342 other = backend.getImplementationClass(other); 1318 other = backend.getImplementationClass(other);
1343 builder.addProperty(namer.operatorIs(other), js('true')); 1319 builder.addProperty(namer.operatorIs(other), js('true'));
1344 } 1320 }
1345 1321
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
1372 void generateSubstitution(Element other, {bool emitNull: false}) { 1322 void generateSubstitution(Element other, {bool emitNull: false}) {
1373 RuntimeTypes rti = backend.rti; 1323 RuntimeTypes rti = backend.rti;
1324 // TODO(karlklose): support typedefs with variables.
1374 jsAst.Expression expression; 1325 jsAst.Expression expression;
1375 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1326 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1376 if (other.kind == ElementKind.CLASS) { 1327 if (other.kind == ElementKind.CLASS) {
1377 String substitution = rti.getSupertypeSubstitution(classElement, other, 1328 String substitution = rti.getSupertypeSubstitution(classElement, other,
1378 alwaysGenerateFunction: true); 1329 alwaysGenerateFunction: true);
1379 if (substitution != null) { 1330 if (substitution != null) {
1380 expression = new jsAst.LiteralExpression(substitution); 1331 expression = new jsAst.LiteralExpression(substitution);
1381 } else if (emitNull || needsNativeCheck) { 1332 } else if (emitNull || needsNativeCheck) {
1382 expression = new jsAst.LiteralNull(); 1333 expression = new jsAst.LiteralNull();
1383 } 1334 }
1384 } 1335 }
1385 if (expression != null) { 1336 if (expression != null) {
1386 builder.addProperty(namer.substitutionName(other), expression); 1337 builder.addProperty(namer.substitutionName(other), expression);
1387 } 1338 }
1388 } 1339 }
1389 1340
1390 generateIsTestsOn(classElement, generateIsTest, 1341 generateIsTestsOn(classElement, generateIsTest, generateSubstitution);
1391 generateIsFunctionTypeTest, generateFunctionTypeSignature,
1392 generateSubstitution);
1393 } 1342 }
1394 1343
1395 void emitRuntimeTypeSupport(CodeBuffer buffer) { 1344 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1396 RuntimeTypes rti = backend.rti; 1345 RuntimeTypes rti = backend.rti;
1397 TypeChecks typeChecks = rti.requiredChecks; 1346 TypeChecks typeChecks = rti.requiredChecks;
1398 1347
1399 // Add checks to the constructors of instantiated classes. 1348 // Add checks to the constructors of instantiated classes.
1400 for (ClassElement cls in typeChecks) { 1349 for (ClassElement cls in typeChecks) {
1401 String holder = namer.isolateAccess(backend.getImplementationClass(cls)); 1350 String holder = namer.isolateAccess(backend.getImplementationClass(cls));
1402 for (TypeCheck check in typeChecks[cls]) { 1351 for (TypeCheck check in typeChecks[cls]) {
1403 ClassElement cls = check.cls; 1352 ClassElement cls = check.cls;
1404 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N'); 1353 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
1405 Substitution substitution = check.substitution; 1354 Substitution substitution = check.substitution;
1406 if (substitution != null) { 1355 if (substitution != null) {
1407 String body = substitution.getCode(rti, false); 1356 String body = substitution.getCode(rti, false);
1408 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N'); 1357 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N');
1409 } 1358 }
1410 }; 1359 };
1411 } 1360 }
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 });
1423 } 1361 }
1424 1362
1425 /** 1363 /**
1426 * Documentation wanted -- johnniwinther 1364 * Documentation wanted -- johnniwinther
1427 * 1365 *
1428 * Invariant: [classElement] must be a declaration element. 1366 * Invariant: [classElement] must be a declaration element.
1429 */ 1367 */
1430 void visitClassFields(ClassElement classElement, 1368 void visitClassFields(ClassElement classElement,
1431 void addField(Element member, 1369 void addField(Element member,
1432 String name, 1370 String name,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1544 } 1482 }
1545 1483
1546 void generateCheckedSetter(Element member, 1484 void generateCheckedSetter(Element member,
1547 String fieldName, 1485 String fieldName,
1548 String accessorName, 1486 String accessorName,
1549 ClassBuilder builder) { 1487 ClassBuilder builder) {
1550 assert(canGenerateCheckedSetter(member)); 1488 assert(canGenerateCheckedSetter(member));
1551 DartType type = member.computeType(compiler); 1489 DartType type = member.computeType(compiler);
1552 // TODO(ahe): Generate a dynamic type error here. 1490 // TODO(ahe): Generate a dynamic type error here.
1553 if (type.element.isErroneous()) return; 1491 if (type.element.isErroneous()) return;
1554 type = type.unalias(compiler); 1492 FunctionElement helperElement
1555 CheckedModeHelper helper = 1493 = backend.getCheckedModeHelper(type, typeCast: false);
1556 backend.getCheckedModeHelper(type, typeCast: false);
1557 FunctionElement helperElement = helper.getElement(compiler);
1558 String helperName = namer.isolateAccess(helperElement); 1494 String helperName = namer.isolateAccess(helperElement);
1559 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')]; 1495 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
1560 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1496 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1561 arguments.add(js.string(namer.operatorIsType(type))); 1497 arguments.add(js.string(namer.operatorIs(type.element)));
1562 } 1498 }
1563 1499
1564 String setterName = namer.setterNameFromAccessorName(accessorName); 1500 String setterName = namer.setterNameFromAccessorName(accessorName);
1565 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1501 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1566 ? 'receiver' : 'this'; 1502 ? 'receiver' : 'this';
1567 List<String> args = backend.isInterceptedMethod(member) 1503 List<String> args = backend.isInterceptedMethod(member)
1568 ? ['receiver', 'v'] 1504 ? ['receiver', 'v']
1569 : ['v']; 1505 : ['v'];
1570 builder.addProperty(setterName, 1506 builder.addProperty(setterName,
1571 js.fun(args, 1507 js.fun(args,
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
1792 return arity; 1728 return arity;
1793 } 1729 }
1794 1730
1795 int _compareSelectorNames(Selector selector1, Selector selector2) { 1731 int _compareSelectorNames(Selector selector1, Selector selector2) {
1796 String name1 = selector1.name.toString(); 1732 String name1 = selector1.name.toString();
1797 String name2 = selector2.name.toString(); 1733 String name2 = selector2.name.toString();
1798 if (name1 != name2) return Comparable.compare(name1, name2); 1734 if (name1 != name2) return Comparable.compare(name1, name2);
1799 return _selectorRank(selector1) - _selectorRank(selector2); 1735 return _selectorRank(selector1) - _selectorRank(selector2);
1800 } 1736 }
1801 1737
1802 /** 1738 Iterable<Element> getTypedefChecksOn(DartType type) {
1803 * Returns a mapping containing all checked function types for which [type] 1739 bool isSubtype(TypedefElement typedef) {
1804 * can be a subtype. A function type is mapped to [:true:] if [type] is 1740 FunctionType typedefType =
1805 * statically known to be a subtype of it and to [:false:] if [type] might 1741 typedef.computeType(compiler).unalias(compiler);
1806 * be a subtype, provided with the right type arguments. 1742 return compiler.types.isSubtype(type, typedefType);
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 }
1820 } 1743 }
1821 // TODO(johnniwinther): Ensure stable ordering of the keys. 1744 return checkedTypedefs.where(isSubtype).toList()
1822 return functionTypeMap; 1745 ..sort(Elements.compareByPosition);
1823 } 1746 }
1824 1747
1825 /** 1748 /**
1826 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1749 * Generate "is tests" for [cls]: itself, and the "is tests" for the
1827 * classes it implements and type argument substitution functions for these 1750 * classes it implements and type argument substitution functions for these
1828 * tests. We don't need to add the "is tests" of the super class because 1751 * tests. We don't need to add the "is tests" of the super class because
1829 * they will be inherited at runtime, but we may need to generate the 1752 * they will be inherited at runtime, but we may need to generate the
1830 * substitutions, because they may have changed. 1753 * substitutions, because they may have changed.
1831 */ 1754 */
1832 void generateIsTestsOn(ClassElement cls, 1755 void generateIsTestsOn(ClassElement cls,
1833 void emitIsTest(Element element), 1756 void emitIsTest(Element element),
1834 FunctionTypeTestEmitter emitIsFunctionTypeTest, 1757 void emitSubstitution(Element element, {emitNull})) {
1835 FunctionTypeSignatureEmitter emitFunctionTypeSignature,
1836 SubstitutionEmitter emitSubstitution) {
1837 if (checkedClasses.contains(cls)) { 1758 if (checkedClasses.contains(cls)) {
1838 emitIsTest(cls); 1759 emitIsTest(cls);
1839 emitSubstitution(cls); 1760 emitSubstitution(cls);
1840 } 1761 }
1841 1762
1842 RuntimeTypes rti = backend.rti; 1763 RuntimeTypes rti = backend.rti;
1843 ClassElement superclass = cls.superclass; 1764 ClassElement superclass = cls.superclass;
1844 1765
1845 bool haveSameTypeVariables(ClassElement a, ClassElement b) { 1766 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
1846 if (a.isClosure()) return true; 1767 if (a.isClosure()) return true;
1847 return a.typeVariables == b.typeVariables; 1768 return a.typeVariables == b.typeVariables;
1848 } 1769 }
1849 1770
1850 if (superclass != null && superclass != compiler.objectClass && 1771 if (superclass != null && superclass != compiler.objectClass &&
1851 !haveSameTypeVariables(cls, superclass)) { 1772 !haveSameTypeVariables(cls, superclass)) {
1852 // We cannot inherit the generated substitutions, because the type 1773 // We cannot inherit the generated substitutions, because the type
1853 // variable layout for this class is different. Instead we generate 1774 // variable layout for this class is different. Instead we generate
1854 // substitutions for all checks and make emitSubstitution a NOP for the 1775 // substitutions for all checks and make emitSubstitution a NOP for the
1855 // rest of this function. 1776 // rest of this function.
1856 Set<ClassElement> emitted = new Set<ClassElement>(); 1777 Set<ClassElement> emitted = new Set<ClassElement>();
1857 // TODO(karlklose): move the computation of these checks to 1778 // TODO(karlklose): move the computation of these checks to
1858 // RuntimeTypeInformation. 1779 // RuntimeTypeInformation.
1859 if (backend.classNeedsRti(cls)) { 1780 if (backend.needsRti(cls)) {
1860 emitSubstitution(superclass, emitNull: true); 1781 emitSubstitution(superclass, emitNull: true);
1861 emitted.add(superclass); 1782 emitted.add(superclass);
1862 } 1783 }
1863 for (DartType supertype in cls.allSupertypes) { 1784 for (DartType supertype in cls.allSupertypes) {
1864 ClassElement superclass = supertype.element; 1785 ClassElement superclass = supertype.element;
1865 if (classesUsingTypeVariableTests.contains(superclass)) { 1786 if (classesUsingTypeVariableTests.contains(superclass)) {
1866 emitSubstitution(superclass, emitNull: true); 1787 emitSubstitution(superclass, emitNull: true);
1867 emitted.add(superclass); 1788 emitted.add(superclass);
1868 } 1789 }
1869 for (ClassElement check in checkedClasses) { 1790 for (ClassElement check in checkedClasses) {
1870 if (supertype.element == check && !emitted.contains(check)) { 1791 if (supertype.element == check && !emitted.contains(check)) {
1871 // Generate substitution. If no substitution is necessary, emit 1792 // Generate substitution. If no substitution is necessary, emit
1872 // [:null:] to overwrite a (possibly) existing substitution from the 1793 // [:null:] to overwrite a (possibly) existing substitution from the
1873 // super classes. 1794 // super classes.
1874 emitSubstitution(check, emitNull: true); 1795 emitSubstitution(check, emitNull: true);
1875 emitted.add(check); 1796 emitted.add(check);
1876 } 1797 }
1877 } 1798 }
1878 } 1799 }
1879 void emitNothing(_, {emitNull}) {}; 1800 void emitNothing(_, {emitNull}) {};
1880 emitSubstitution = emitNothing; 1801 emitSubstitution = emitNothing;
1881 } 1802 }
1882 1803
1883 Set<Element> generated = new Set<Element>(); 1804 Set<Element> generated = new Set<Element>();
1884 // A class that defines a [:call:] method implicitly implements 1805 // A class that defines a [:call:] method implicitly implements
1885 // [Function] and needs checks for all typedefs that are used in is-checks. 1806 // [Function] and needs checks for all typedefs that are used in is-checks.
1886 if (checkedClasses.contains(compiler.functionClass) || 1807 if (checkedClasses.contains(compiler.functionClass) ||
1887 !checkedFunctionTypes.isEmpty) { 1808 !checkedTypedefs.isEmpty) {
1888 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1809 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1889 if (call == null) { 1810 if (call == null) {
1890 // If [cls] is a closure, it has a synthetic call operator method. 1811 // If [cls] is a closure, it has a synthetic call operator method.
1891 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1812 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1892 } 1813 }
1893 if (call != null && call.isFunction()) { 1814 if (call != null && call.isFunction()) {
1894 generateInterfacesIsTests(compiler.functionClass, 1815 generateInterfacesIsTests(compiler.functionClass,
1895 emitIsTest, 1816 emitIsTest,
1896 emitSubstitution, 1817 emitSubstitution,
1897 generated); 1818 generated);
1898 FunctionType callType = call.computeType(compiler); 1819 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest);
1899 Map<FunctionType, bool> functionTypeChecks = 1820 }
1900 getFunctionTypeChecksOn(callType);
1901 generateFunctionTypeTests(call, callType, functionTypeChecks,
1902 emitFunctionTypeSignature, emitIsFunctionTypeTest);
1903 }
1904 } 1821 }
1905 1822
1906 for (DartType interfaceType in cls.interfaces) { 1823 for (DartType interfaceType in cls.interfaces) {
1907 generateInterfacesIsTests(interfaceType.element, emitIsTest, 1824 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1908 emitSubstitution, generated); 1825 emitSubstitution, generated);
1909 } 1826 }
1910 } 1827 }
1911 1828
1912 /** 1829 /**
1913 * Generate "is tests" where [cls] is being implemented. 1830 * Generate "is tests" where [cls] is being implemented.
1914 */ 1831 */
1915 void generateInterfacesIsTests(ClassElement cls, 1832 void generateInterfacesIsTests(ClassElement cls,
1916 void emitIsTest(ClassElement element), 1833 void emitIsTest(ClassElement element),
1917 SubstitutionEmitter emitSubstitution, 1834 void emitSubstitution(ClassElement element),
1918 Set<Element> alreadyGenerated) { 1835 Set<Element> alreadyGenerated) {
1919 void tryEmitTest(ClassElement check) { 1836 void tryEmitTest(ClassElement check) {
1920 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) { 1837 if (!alreadyGenerated.contains(check) && checkedClasses.contains(check)) {
1921 alreadyGenerated.add(check); 1838 alreadyGenerated.add(check);
1922 emitIsTest(check); 1839 emitIsTest(check);
1923 emitSubstitution(check); 1840 emitSubstitution(check);
1924 } 1841 }
1925 }; 1842 };
1926 1843
1927 tryEmitTest(cls); 1844 tryEmitTest(cls);
1928 1845
1929 for (DartType interfaceType in cls.interfaces) { 1846 for (DartType interfaceType in cls.interfaces) {
1930 Element element = interfaceType.element; 1847 Element element = interfaceType.element;
1931 tryEmitTest(element); 1848 tryEmitTest(element);
1932 generateInterfacesIsTests(element, emitIsTest, emitSubstitution, 1849 generateInterfacesIsTests(element, emitIsTest, emitSubstitution,
1933 alreadyGenerated); 1850 alreadyGenerated);
1934 } 1851 }
1935 1852
1936 // We need to also emit "is checks" for the superclass and its supertypes. 1853 // We need to also emit "is checks" for the superclass and its supertypes.
1937 ClassElement superclass = cls.superclass; 1854 ClassElement superclass = cls.superclass;
1938 if (superclass != null) { 1855 if (superclass != null) {
1939 tryEmitTest(superclass); 1856 tryEmitTest(superclass);
1940 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, 1857 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
1941 alreadyGenerated); 1858 alreadyGenerated);
1942 } 1859 }
1943 } 1860 }
1944 1861
1945 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
1984 /** 1862 /**
1985 * Return a function that returns true if its argument is a class 1863 * Return a function that returns true if its argument is a class
1986 * that needs to be emitted. 1864 * that needs to be emitted.
1987 */ 1865 */
1988 Function computeClassFilter() { 1866 Function computeClassFilter() {
1989 Set<ClassElement> unneededClasses = new Set<ClassElement>(); 1867 Set<ClassElement> unneededClasses = new Set<ClassElement>();
1990 // The [Bool] class is not marked as abstract, but has a factory 1868 // The [Bool] class is not marked as abstract, but has a factory
1991 // constructor that always throws. We never need to emit it. 1869 // constructor that always throws. We never need to emit it.
1992 unneededClasses.add(compiler.boolClass); 1870 unneededClasses.add(compiler.boolClass);
1993 1871
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
2136 ClassBuilder closureBuilder = new ClassBuilder(); 2014 ClassBuilder closureBuilder = new ClassBuilder();
2137 // If a static function is used as a closure we need to add its name 2015 // If a static function is used as a closure we need to add its name
2138 // in case it is used in spawnFunction. 2016 // in case it is used in spawnFunction.
2139 String methodName = namer.STATIC_CLOSURE_NAME_NAME; 2017 String methodName = namer.STATIC_CLOSURE_NAME_NAME;
2140 emitClosureClassHeader( 2018 emitClosureClassHeader(
2141 mangledName, superName, <String>[invocationName, methodName], 2019 mangledName, superName, <String>[invocationName, methodName],
2142 closureBuilder); 2020 closureBuilder);
2143 2021
2144 addParameterStubs(callElement, closureBuilder.addProperty); 2022 addParameterStubs(callElement, closureBuilder.addProperty);
2145 2023
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
2146 // TODO(ngeoffray): Cache common base classes for closures, bound 2030 // TODO(ngeoffray): Cache common base classes for closures, bound
2147 // closures, and static closures that have common type checks. 2031 // closures, and static closures that have common type checks.
2148 boundClosures.add( 2032 boundClosures.add(
2149 js('$classesCollector.$mangledName = #', 2033 js('$classesCollector.$mangledName = #',
2150 closureBuilder.toObjectInitializer())); 2034 closureBuilder.toObjectInitializer()));
2151 2035
2152 staticGetters[element] = closureClassElement; 2036 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);
2175 } 2037 }
2176 } 2038 }
2177 2039
2178 void emitClosureClassHeader(String mangledName, 2040 void emitClosureClassHeader(String mangledName,
2179 String superName, 2041 String superName,
2180 List<String> fieldNames, 2042 List<String> fieldNames,
2181 ClassBuilder builder) { 2043 ClassBuilder builder) {
2182 builder.addProperty('', 2044 builder.addProperty('',
2183 js.string("$superName;${fieldNames.join(',')}")); 2045 js.string("$superName;${fieldNames.join(',')}"));
2184 } 2046 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
2222 if (inInterceptor) { 2084 if (inInterceptor) {
2223 cache = interceptorClosureCache; 2085 cache = interceptorClosureCache;
2224 } else { 2086 } else {
2225 cache = boundClosureCache; 2087 cache = boundClosureCache;
2226 } 2088 }
2227 List<String> fieldNames = <String>[]; 2089 List<String> fieldNames = <String>[];
2228 compiler.boundClosureClass.forEachInstanceField((_, Element field) { 2090 compiler.boundClosureClass.forEachInstanceField((_, Element field) {
2229 fieldNames.add(namer.getName(field)); 2091 fieldNames.add(namer.getName(field));
2230 }); 2092 });
2231 2093
2232 DartType memberType = member.computeType(compiler); 2094 Iterable<Element> typedefChecks =
2233 Map<FunctionType, bool> functionTypeChecks = 2095 getTypedefChecksOn(member.computeType(compiler));
2234 getFunctionTypeChecksOn(memberType); 2096 bool hasTypedefChecks = !typedefChecks.isEmpty;
2235 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty;
2236 2097
2237 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks; 2098 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks;
2238 2099
2239 ClassElement classElement = member.getEnclosingClass();
2240 String closureClass = canBeShared ? cache[parameterCount] : null; 2100 String closureClass = canBeShared ? cache[parameterCount] : null;
2241 if (closureClass == null) { 2101 if (closureClass == null) {
2242 // Either the class was not cached yet, or there are optional parameters. 2102 // Either the class was not cached yet, or there are optional parameters.
2243 // Create a new closure class. 2103 // Create a new closure class.
2244 String name; 2104 String name;
2245 if (canBeShared) { 2105 if (canBeShared) {
2246 if (inInterceptor) { 2106 if (inInterceptor) {
2247 name = 'BoundClosure\$i${parameterCount}'; 2107 name = 'BoundClosure\$i${parameterCount}';
2248 } else { 2108 } else {
2249 name = 'BoundClosure\$${parameterCount}'; 2109 name = 'BoundClosure\$${parameterCount}';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2285 arguments.add(js(name)); 2145 arguments.add(js(name));
2286 } 2146 }
2287 2147
2288 jsAst.Expression fun = js.fun( 2148 jsAst.Expression fun = js.fun(
2289 parameters, 2149 parameters,
2290 js.return_( 2150 js.return_(
2291 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments))); 2151 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments)));
2292 boundClosureBuilder.addProperty(invocationName, fun); 2152 boundClosureBuilder.addProperty(invocationName, fun);
2293 2153
2294 addParameterStubs(callElement, boundClosureBuilder.addProperty); 2154 addParameterStubs(callElement, boundClosureBuilder.addProperty);
2295 2155 typedefChecks.forEach((Element typedef) {
2296 void emitFunctionTypeSignature(Element method, FunctionType methodType) { 2156 String operator = namer.operatorIs(typedef);
2297 String encoding = backend.rti.getSignatureEncoding( 2157 boundClosureBuilder.addProperty(operator, js('true'));
2298 methodType, () => 'this.${fieldNames[0]}'); 2158 });
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);
2312 2159
2313 boundClosures.add( 2160 boundClosures.add(
2314 js('$classesCollector.$mangledName = #', 2161 js('$classesCollector.$mangledName = #',
2315 boundClosureBuilder.toObjectInitializer())); 2162 boundClosureBuilder.toObjectInitializer()));
2316 2163
2317 closureClass = namer.isolateAccess(closureClassElement); 2164 closureClass = namer.isolateAccess(closureClassElement);
2318 2165
2319 // Cache it. 2166 // Cache it.
2320 if (canBeShared) { 2167 if (canBeShared) {
2321 cache[parameterCount] = closureClass; 2168 cache[parameterCount] = closureClass;
(...skipping 11 matching lines...) Expand all
2333 if (inInterceptor) { 2180 if (inInterceptor) {
2334 String receiverArg = fieldNames[2]; 2181 String receiverArg = fieldNames[2];
2335 parameters.add(receiverArg); 2182 parameters.add(receiverArg);
2336 arguments.add(js(receiverArg)); 2183 arguments.add(js(receiverArg));
2337 } else { 2184 } else {
2338 // Put null in the intercepted receiver field. 2185 // Put null in the intercepted receiver field.
2339 arguments.add(new jsAst.LiteralNull()); 2186 arguments.add(new jsAst.LiteralNull());
2340 } 2187 }
2341 2188
2342 jsAst.Expression getterFunction = js.fun( 2189 jsAst.Expression getterFunction = js.fun(
2343 parameters, js.return_(js(closureClass).newWith(arguments))); 2190 parameters,
2191 js.return_(js(closureClass).newWith(arguments)));
2344 2192
2345 defineStub(getterName, getterFunction); 2193 defineStub(getterName, getterFunction);
2346 } 2194 }
2347 2195
2348 /** 2196 /**
2349 * Documentation wanted -- johnniwinther 2197 * Documentation wanted -- johnniwinther
2350 * 2198 *
2351 * Invariant: [member] must be a declaration element. 2199 * Invariant: [member] must be a declaration element.
2352 */ 2200 */
2353 void emitCallStubForGetter(Element member, 2201 void emitCallStubForGetter(Element member,
(...skipping 19 matching lines...) Expand all
2373 ? member.fixedBackendName() 2221 ? member.fixedBackendName()
2374 : namer.instanceFieldName(member); 2222 : namer.instanceFieldName(member);
2375 return js('this')[fieldName]; 2223 return js('this')[fieldName];
2376 } 2224 }
2377 } 2225 }
2378 2226
2379 // Two selectors may match but differ only in type. To avoid generating 2227 // Two selectors may match but differ only in type. To avoid generating
2380 // identical stubs for each we track untyped selectors which already have 2228 // identical stubs for each we track untyped selectors which already have
2381 // stubs. 2229 // stubs.
2382 Set<Selector> generatedSelectors = new Set<Selector>(); 2230 Set<Selector> generatedSelectors = new Set<Selector>();
2231
2383 for (Selector selector in selectors) { 2232 for (Selector selector in selectors) {
2384 if (selector.applies(member, compiler)) { 2233 if (selector.applies(member, compiler)) {
2385 selector = selector.asUntyped; 2234 selector = selector.asUntyped;
2386 if (generatedSelectors.contains(selector)) continue; 2235 if (generatedSelectors.contains(selector)) continue;
2387 generatedSelectors.add(selector); 2236 generatedSelectors.add(selector);
2388 2237
2389 String invocationName = namer.invocationName(selector); 2238 String invocationName = namer.invocationName(selector);
2390 Selector callSelector = new Selector.callClosureFrom(selector); 2239 Selector callSelector = new Selector.callClosureFrom(selector);
2391 String closureCallName = namer.invocationName(callSelector); 2240 String closureCallName = namer.invocationName(callSelector);
2392 2241
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after
2977 }); 2826 });
2978 2827
2979 // 3b. Add classes that are referenced by substitutions in object checks and 2828 // 3b. Add classes that are referenced by substitutions in object checks and
2980 // their superclasses. 2829 // their superclasses.
2981 TypeChecks requiredChecks = 2830 TypeChecks requiredChecks =
2982 backend.rti.computeChecks(neededClasses, checkedClasses); 2831 backend.rti.computeChecks(neededClasses, checkedClasses);
2983 Set<ClassElement> classesUsedInSubstitutions = 2832 Set<ClassElement> classesUsedInSubstitutions =
2984 rti.getClassesUsedInSubstitutions(backend, requiredChecks); 2833 rti.getClassesUsedInSubstitutions(backend, requiredChecks);
2985 addClassesWithSuperclasses(classesUsedInSubstitutions); 2834 addClassesWithSuperclasses(classesUsedInSubstitutions);
2986 2835
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
2996 // 4. Finally, sort the classes. 2836 // 4. Finally, sort the classes.
2997 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses); 2837 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
2998 2838
2999 // If we need noSuchMethod support, we run through all needed 2839 // If we need noSuchMethod support, we run through all needed
3000 // classes to figure out if we need the support on any native 2840 // classes to figure out if we need the support on any native
3001 // class. If so, we let the native emitter deal with it. 2841 // class. If so, we let the native emitter deal with it.
3002 if (compiler.enabledNoSuchMethod) { 2842 if (compiler.enabledNoSuchMethod) {
3003 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD; 2843 SourceString noSuchMethodName = Compiler.NO_SUCH_METHOD;
3004 Selector noSuchMethodSelector = compiler.noSuchMethodSelector; 2844 Selector noSuchMethodSelector = compiler.noSuchMethodSelector;
3005 for (ClassElement element in sortedClasses) { 2845 for (ClassElement element in sortedClasses) {
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after
3640 3480
3641 const String HOOKS_API_USAGE = """ 3481 const String HOOKS_API_USAGE = """
3642 // The code supports the following hooks: 3482 // The code supports the following hooks:
3643 // dartPrint(message) - if this function is defined it is called 3483 // dartPrint(message) - if this function is defined it is called
3644 // instead of the Dart [print] method. 3484 // instead of the Dart [print] method.
3645 // dartMainRunner(main) - if this function is defined, the Dart [main] 3485 // dartMainRunner(main) - if this function is defined, the Dart [main]
3646 // method will not be invoked directly. 3486 // method will not be invoked directly.
3647 // Instead, a closure that will invoke [main] is 3487 // Instead, a closure that will invoke [main] is
3648 // passed to [dartMainRunner]. 3488 // passed to [dartMainRunner].
3649 """; 3489 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698