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

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: Handle function types in checked mode. 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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 * `x is Set<String>` then the ClassElement `Set` will occur once in 105 * `x is Set<String>` then the ClassElement `Set` will occur once in
106 * [checkedClasses]. 106 * [checkedClasses].
107 */ 107 */
108 Set<ClassElement> checkedClasses; 108 Set<ClassElement> checkedClasses;
109 109
110 /** 110 /**
111 * Raw Typedef symbols occuring in is-checks and type assertions. If the 111 * Raw Typedef symbols occuring in is-checks and type assertions. If the
112 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement 112 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement
113 * `F` will occur once in [checkedTypedefs]. 113 * `F` will occur once in [checkedTypedefs].
114 */ 114 */
115 Set<TypedefElement> checkedTypedefs; 115 Set<FunctionType> checkedFunctionTypes;
116
117 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes
118 = new Map<ClassElement, Set<FunctionType>>();
119
120 Set<FunctionType> checkedNonGenericFunctionTypes
121 = new Set<FunctionType>();
122
123 void registerDynamicFunctionTypeCheck(FunctionType functionType) {
124 ClassElement classElement = Types.getClassContext(functionType);
125 if (classElement != null) {
126 checkedGenericFunctionTypes.putIfAbsent(classElement,
127 () => new Set<FunctionType>()).add(functionType);
128 } else {
129 checkedNonGenericFunctionTypes.add(functionType);
130 }
131 }
116 132
117 final bool generateSourceMap; 133 final bool generateSourceMap;
118 134
119 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; 135 Iterable<ClassElement> cachedClassesUsingTypeVariableTests;
120 136
121 Iterable<ClassElement> get classesUsingTypeVariableTests { 137 Iterable<ClassElement> get classesUsingTypeVariableTests {
122 if (cachedClassesUsingTypeVariableTests == null) { 138 if (cachedClassesUsingTypeVariableTests == null) {
123 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks 139 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks
124 .where((DartType t) => t is TypeVariableType) 140 .where((DartType t) => t is TypeVariableType)
125 .map((TypeVariableType v) => v.element.getEnclosingClass()) 141 .map((TypeVariableType v) => v.element.getEnclosingClass())
(...skipping 10 matching lines...) Expand all
136 constantEmitter = new ConstantEmitter(compiler, namer), 152 constantEmitter = new ConstantEmitter(compiler, namer),
137 super(compiler) { 153 super(compiler) {
138 nativeEmitter = new NativeEmitter(this); 154 nativeEmitter = new NativeEmitter(this);
139 } 155 }
140 156
141 void addComment(String comment, CodeBuffer buffer) { 157 void addComment(String comment, CodeBuffer buffer) {
142 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); 158 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler));
143 } 159 }
144 160
145 void computeRequiredTypeChecks() { 161 void computeRequiredTypeChecks() {
146 assert(checkedClasses == null && checkedTypedefs == null); 162 assert(checkedClasses == null && checkedFunctionTypes == null);
147 163
148 backend.rti.addImplicitChecks(compiler.codegenWorld, 164 backend.rti.addImplicitChecks(compiler.codegenWorld,
149 classesUsingTypeVariableTests); 165 classesUsingTypeVariableTests);
150 166
151 checkedClasses = new Set<ClassElement>(); 167 checkedClasses = new Set<ClassElement>();
152 checkedTypedefs = new Set<TypedefElement>(); 168 checkedFunctionTypes = new Set<FunctionType>();
153 compiler.codegenWorld.isChecks.forEach((DartType t) { 169 compiler.codegenWorld.isChecks.forEach((DartType t) {
170 assert(!t.isMalformed);
154 if (t is InterfaceType) { 171 if (t is InterfaceType) {
155 checkedClasses.add(t.element); 172 checkedClasses.add(t.element);
156 } else if (t is TypedefType) { 173 } else if (t is FunctionType) {
157 checkedTypedefs.add(t.element); 174 checkedFunctionTypes.add(t);
158 } 175 }
159 }); 176 });
160 } 177 }
161 178
162 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) { 179 ClassElement computeMixinClass(MixinApplicationElement mixinApplication) {
163 ClassElement mixin = mixinApplication.mixin; 180 ClassElement mixin = mixinApplication.mixin;
164 while (mixin.isMixinApplication) { 181 while (mixin.isMixinApplication) {
165 mixinApplication = mixin; 182 mixinApplication = mixin;
166 mixin = mixinApplication.mixin; 183 mixin = mixinApplication.mixin;
167 } 184 }
(...skipping 1061 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 1246
1230 void generateIsTest(Element other) { 1247 void generateIsTest(Element other) {
1231 if (other == compiler.objectClass && other != classElement) { 1248 if (other == compiler.objectClass && other != classElement) {
1232 // Avoid emitting [:$isObject:] on all classes but [Object]. 1249 // Avoid emitting [:$isObject:] on all classes but [Object].
1233 return; 1250 return;
1234 } 1251 }
1235 other = backend.getImplementationClass(other); 1252 other = backend.getImplementationClass(other);
1236 builder.addProperty(namer.operatorIs(other), js('true')); 1253 builder.addProperty(namer.operatorIs(other), js('true'));
1237 } 1254 }
1238 1255
1256 void generateIsFunctionTypeTest(FunctionType type) {
1257 String operator = namer.operatorIsType(type);
1258 builder.addProperty(operator, new jsAst.LiteralBool(true));
1259 }
1260
1261 void generateFunctionTypeSignature(Element method, FunctionType type) {
1262 assert(method.isImplementation);
1263 String thisAccess = 'this';
1264 Node node = method.parseNode(compiler);
1265 ClosureClassMap closureData =
1266 compiler.closureToClassMapper.closureMappingCache[node];
1267 if (closureData != null) {
1268 Element thisElement =
1269 closureData.freeVariableMapping[closureData.thisElement];
1270 if (thisElement != null) {
1271 String thisName = backend.namer.getName(thisElement);
1272 thisAccess = 'this.$thisName';
1273 }
1274 }
1275 RuntimeTypes rti = backend.rti;
1276 String encoding = rti.getSignatureEncoding(type, () => '$thisAccess');
1277 String operatorSignature = namer.operatorSignature();
1278 builder.addProperty(operatorSignature,
1279 new jsAst.LiteralExpression(encoding));
1280 }
1281
1239 void generateSubstitution(Element other, {bool emitNull: false}) { 1282 void generateSubstitution(Element other, {bool emitNull: false}) {
1240 RuntimeTypes rti = backend.rti; 1283 RuntimeTypes rti = backend.rti;
1241 // TODO(karlklose): support typedefs with variables. 1284 // TODO(karlklose): support typedefs with variables.
1242 jsAst.Expression expression; 1285 jsAst.Expression expression;
1243 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1286 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1244 if (other.kind == ElementKind.CLASS) { 1287 if (other.kind == ElementKind.CLASS) {
1245 String substitution = rti.getSupertypeSubstitution(classElement, other, 1288 String substitution = rti.getSupertypeSubstitution(classElement, other,
1246 alwaysGenerateFunction: true); 1289 alwaysGenerateFunction: true);
1247 if (substitution != null) { 1290 if (substitution != null) {
1248 expression = new jsAst.LiteralExpression(substitution); 1291 expression = new jsAst.LiteralExpression(substitution);
1249 } else if (emitNull || needsNativeCheck) { 1292 } else if (emitNull || needsNativeCheck) {
1250 expression = new jsAst.LiteralNull(); 1293 expression = new jsAst.LiteralNull();
1251 } 1294 }
1252 } 1295 }
1253 if (expression != null) { 1296 if (expression != null) {
1254 builder.addProperty(namer.substitutionName(other), expression); 1297 builder.addProperty(namer.substitutionName(other), expression);
1255 } 1298 }
1256 } 1299 }
1257 1300
1258 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); 1301 generateIsTestsOn(classElement, generateIsTest,
1302 generateIsFunctionTypeTest, generateFunctionTypeSignature,
1303 generateSubstitution);
1259 } 1304 }
1260 1305
1261 void emitRuntimeTypeSupport(CodeBuffer buffer) { 1306 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1262 RuntimeTypes rti = backend.rti; 1307 RuntimeTypes rti = backend.rti;
1263 TypeChecks typeChecks = rti.requiredChecks; 1308 TypeChecks typeChecks = rti.requiredChecks;
1264 1309
1265 // Add checks to the constructors of instantiated classes. 1310 // Add checks to the constructors of instantiated classes.
1266 for (ClassElement cls in typeChecks) { 1311 for (ClassElement cls in typeChecks) {
1267 String holder = namer.isolateAccess(backend.getImplementationClass(cls)); 1312 String holder = namer.isolateAccess(backend.getImplementationClass(cls));
1268 for (TypeCheck check in typeChecks[cls]) { 1313 for (TypeCheck check in typeChecks[cls]) {
1269 ClassElement cls = check.cls; 1314 ClassElement cls = check.cls;
1270 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N'); 1315 buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
1271 Substitution substitution = check.substitution; 1316 Substitution substitution = check.substitution;
1272 if (substitution != null) { 1317 if (substitution != null) {
1273 String body = substitution.getCode(rti, false); 1318 String body = substitution.getCode(rti, false);
1274 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N'); 1319 buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N');
1275 } 1320 }
1276 }; 1321 };
1277 } 1322 }
1323
1324 checkedNonGenericFunctionTypes.forEach((FunctionType type) {
1325 String encoding = rti.getTypeEncoding(type);
1326 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N');
1327 });
1328
1329 checkedGenericFunctionTypes.forEach(
1330 (ClassElement cls, Set<FunctionType> functionTypes) {
1331 for (FunctionType type in functionTypes) {
1332 String encoding = rti.getTypeEncoding(type);
1333 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N');
1334 }
1335 });
1278 } 1336 }
1279 1337
1280 /** 1338 /**
1281 * Documentation wanted -- johnniwinther 1339 * Documentation wanted -- johnniwinther
1282 * 1340 *
1283 * Invariant: [classElement] must be a declaration element. 1341 * Invariant: [classElement] must be a declaration element.
1284 */ 1342 */
1285 void visitClassFields(ClassElement classElement, 1343 void visitClassFields(ClassElement classElement,
1286 void addField(Element member, 1344 void addField(Element member,
1287 String name, 1345 String name,
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1399 } 1457 }
1400 1458
1401 void generateCheckedSetter(Element member, 1459 void generateCheckedSetter(Element member,
1402 String fieldName, 1460 String fieldName,
1403 String accessorName, 1461 String accessorName,
1404 ClassBuilder builder) { 1462 ClassBuilder builder) {
1405 assert(canGenerateCheckedSetter(member)); 1463 assert(canGenerateCheckedSetter(member));
1406 DartType type = member.computeType(compiler); 1464 DartType type = member.computeType(compiler);
1407 // TODO(ahe): Generate a dynamic type error here. 1465 // TODO(ahe): Generate a dynamic type error here.
1408 if (type.element.isErroneous()) return; 1466 if (type.element.isErroneous()) return;
1409 FunctionElement helperElement 1467 CheckedModeHelper helper =
1410 = backend.getCheckedModeHelper(type, typeCast: false); 1468 backend.getCheckedModeHelper(type, typeCast: false);
1469 FunctionElement helperElement = helper.getElement(compiler);
1411 String helperName = namer.isolateAccess(helperElement); 1470 String helperName = namer.isolateAccess(helperElement);
1412 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')]; 1471 List<jsAst.Expression> arguments = <jsAst.Expression>[js('v')];
1413 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1472 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1414 arguments.add(js.string(namer.operatorIs(type.element))); 1473 arguments.add(js.string(namer.operatorIsType(type)));
1415 } 1474 }
1416 1475
1417 String setterName = namer.setterNameFromAccessorName(accessorName); 1476 String setterName = namer.setterNameFromAccessorName(accessorName);
1418 String receiver = backend.isInterceptorClass(member.getEnclosingClass()) 1477 String receiver = backend.isInterceptorClass(member.getEnclosingClass())
1419 ? 'receiver' : 'this'; 1478 ? 'receiver' : 'this';
1420 List<String> args = backend.isInterceptedMethod(member) 1479 List<String> args = backend.isInterceptedMethod(member)
1421 ? ['receiver', 'v'] 1480 ? ['receiver', 'v']
1422 : ['v']; 1481 : ['v'];
1423 builder.addProperty(setterName, 1482 builder.addProperty(setterName,
1424 js.fun(args, 1483 js.fun(args,
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1617 return arity; 1676 return arity;
1618 } 1677 }
1619 1678
1620 int _compareSelectorNames(Selector selector1, Selector selector2) { 1679 int _compareSelectorNames(Selector selector1, Selector selector2) {
1621 String name1 = selector1.name.toString(); 1680 String name1 = selector1.name.toString();
1622 String name2 = selector2.name.toString(); 1681 String name2 = selector2.name.toString();
1623 if (name1 != name2) return Comparable.compare(name1, name2); 1682 if (name1 != name2) return Comparable.compare(name1, name2);
1624 return _selectorRank(selector1) - _selectorRank(selector2); 1683 return _selectorRank(selector1) - _selectorRank(selector2);
1625 } 1684 }
1626 1685
1627 Iterable<Element> getTypedefChecksOn(DartType type) { 1686 /**
1628 bool isSubtype(TypedefElement typedef) { 1687 * Returns a mapping containing all checked function types for which [type]
1629 FunctionType typedefType = 1688 * can be a subtype. A function type is mapped to [:true:] if [type] is
1630 typedef.computeType(compiler).unalias(compiler); 1689 * statically known to be a subtype of it.
1631 return compiler.types.isSubtype(type, typedefType); 1690 */
1691 // TODO(johnniwinther): Change to return a mapping from function types to
1692 // a set of variable points and use this to detect statically/dynamically
1693 // known subtype relations.
1694 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) {
1695 Map<FunctionType, bool> functionTypeMap =
1696 new LinkedHashMap<FunctionType, bool>();
1697 for (FunctionType functionType in checkedFunctionTypes) {
1698 if (compiler.types.isSubtype(type, functionType)) {
1699 functionTypeMap[functionType] = true;
1700 } else if (compiler.types.isPotentialSubtype(type, functionType)) {
1701 functionTypeMap[functionType] = false;
1702 }
1632 } 1703 }
1633 return checkedTypedefs.where(isSubtype).toList() 1704 // TODO(johnniwinther): Ensure stable ordering of the keys.
1634 ..sort(Elements.compareByPosition); 1705 return functionTypeMap;
1635 } 1706 }
1636 1707
1637 /** 1708 /**
1638 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1709 * Generate "is tests" for [cls]: itself, and the "is tests" for the
1639 * classes it implements and type argument substitution functions for these 1710 * classes it implements and type argument substitution functions for these
1640 * tests. We don't need to add the "is tests" of the super class because 1711 * tests. We don't need to add the "is tests" of the super class because
1641 * they will be inherited at runtime, but we may need to generate the 1712 * they will be inherited at runtime, but we may need to generate the
1642 * substitutions, because they may have changed. 1713 * substitutions, because they may have changed.
1643 */ 1714 */
1644 void generateIsTestsOn(ClassElement cls, 1715 void generateIsTestsOn(ClassElement cls,
1645 void emitIsTest(Element element), 1716 void emitIsTest(Element element),
1717 void emitIsFunctionTypeTest(FunctionType type),
1718 void emitFunctionTypeSignature(Element method, Function Type type),
1646 void emitSubstitution(Element element, {emitNull})) { 1719 void emitSubstitution(Element element, {emitNull})) {
1647 if (checkedClasses.contains(cls)) { 1720 if (checkedClasses.contains(cls)) {
1648 emitIsTest(cls); 1721 emitIsTest(cls);
1649 emitSubstitution(cls); 1722 emitSubstitution(cls);
1650 } 1723 }
1651 1724
1652 RuntimeTypes rti = backend.rti; 1725 RuntimeTypes rti = backend.rti;
1653 ClassElement superclass = cls.superclass; 1726 ClassElement superclass = cls.superclass;
1654 1727
1655 bool haveSameTypeVariables(ClassElement a, ClassElement b) { 1728 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1687 } 1760 }
1688 } 1761 }
1689 void emitNothing(_, {emitNull}) {}; 1762 void emitNothing(_, {emitNull}) {};
1690 emitSubstitution = emitNothing; 1763 emitSubstitution = emitNothing;
1691 } 1764 }
1692 1765
1693 Set<Element> generated = new Set<Element>(); 1766 Set<Element> generated = new Set<Element>();
1694 // A class that defines a [:call:] method implicitly implements 1767 // A class that defines a [:call:] method implicitly implements
1695 // [Function] and needs checks for all typedefs that are used in is-checks. 1768 // [Function] and needs checks for all typedefs that are used in is-checks.
1696 if (checkedClasses.contains(compiler.functionClass) || 1769 if (checkedClasses.contains(compiler.functionClass) ||
1697 !checkedTypedefs.isEmpty) { 1770 !checkedFunctionTypes.isEmpty) {
1698 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1771 Element call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1699 if (call == null) { 1772 if (call == null) {
1700 // If [cls] is a closure, it has a synthetic call operator method. 1773 // If [cls] is a closure, it has a synthetic call operator method.
1701 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1774 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1702 } 1775 }
1703 if (call != null && call.isFunction()) { 1776 if (call != null && call.isFunction()) {
1704 generateInterfacesIsTests(compiler.functionClass, 1777 generateInterfacesIsTests(compiler.functionClass,
1705 emitIsTest, 1778 emitIsTest,
1706 emitSubstitution, 1779 emitSubstitution,
1707 generated); 1780 generated);
1708 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1781 FunctionType callType = call.computeType(compiler);
1709 } 1782 generateFunctionTypeTests(call, callType,
1783 emitFunctionTypeSignature, emitIsFunctionTypeTest);
1784 }
1710 } 1785 }
1711 1786
1712 for (DartType interfaceType in cls.interfaces) { 1787 for (DartType interfaceType in cls.interfaces) {
1713 generateInterfacesIsTests(interfaceType.element, emitIsTest, 1788 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1714 emitSubstitution, generated); 1789 emitSubstitution, generated);
1715 } 1790 }
1716 } 1791 }
1717 1792
1718 /** 1793 /**
1719 * Generate "is tests" where [cls] is being implemented. 1794 * Generate "is tests" where [cls] is being implemented.
(...skipping 21 matching lines...) Expand all
1741 1816
1742 // We need to also emit "is checks" for the superclass and its supertypes. 1817 // We need to also emit "is checks" for the superclass and its supertypes.
1743 ClassElement superclass = cls.superclass; 1818 ClassElement superclass = cls.superclass;
1744 if (superclass != null) { 1819 if (superclass != null) {
1745 tryEmitTest(superclass); 1820 tryEmitTest(superclass);
1746 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution, 1821 generateInterfacesIsTests(superclass, emitIsTest, emitSubstitution,
1747 alreadyGenerated); 1822 alreadyGenerated);
1748 } 1823 }
1749 } 1824 }
1750 1825
1826 void generateFunctionTypeTests(
1827 Element method,
1828 FunctionType methodType,
1829 void emitFunctionTypeSignature(Element method, FunctionType methodType),
1830 void emitIsFunctionTypeTest(FunctionType functionType)) {
1831 Map<FunctionType, bool> functionTypeChecks =
1832 getFunctionTypeChecksOn(methodType);
1833 generateFunctionTypeTestsInternal(method, methodType, functionTypeChecks,
1834 emitFunctionTypeSignature, emitIsFunctionTypeTest);
1835 }
1836
1837 const int MAX_FUNCTION_TYPE_PREDICATES = 10;
1838
1839 void generateFunctionTypeTestsInternal(
1840 Element method,
1841 FunctionType methodType,
1842 Map<FunctionType, bool> functionTypeChecks,
1843 void emitFunctionTypeSignature(Element method, FunctionType methodType),
1844 void emitIsFunctionTypeTest(FunctionType functionType)) {
1845 bool hasDynamicFunctionTypeCheck = false;
1846 int neededPredicates = 0;
1847 functionTypeChecks.forEach((FunctionType functionType, bool knownSubtype) {
1848 if (!knownSubtype) {
1849 registerDynamicFunctionTypeCheck(functionType);
1850 hasDynamicFunctionTypeCheck = true;
1851 } else {
1852 neededPredicates++;
1853 }
1854 });
1855 bool hasSignature = false;
1856 if (hasDynamicFunctionTypeCheck ||
1857 neededPredicates > MAX_FUNCTION_TYPE_PREDICATES) {
1858 emitFunctionTypeSignature(method, methodType);
1859 hasSignature = true;
1860 }
1861 functionTypeChecks.forEach((FunctionType functionType,
1862 bool knownSubtype) {
1863 if (knownSubtype || !hasDynamicFunctionTypeCheck) {
1864 if (hasSignature) {
1865 registerDynamicFunctionTypeCheck(functionType);
1866 } else {
1867 emitIsFunctionTypeTest(functionType);
1868 }
1869 }
1870 });
1871 }
1872
1751 /** 1873 /**
1752 * Return a function that returns true if its argument is a class 1874 * Return a function that returns true if its argument is a class
1753 * that needs to be emitted. 1875 * that needs to be emitted.
1754 */ 1876 */
1755 Function computeClassFilter() { 1877 Function computeClassFilter() {
1756 Set<ClassElement> unneededClasses = new Set<ClassElement>(); 1878 Set<ClassElement> unneededClasses = new Set<ClassElement>();
1757 // The [Bool] class is not marked as abstract, but has a factory 1879 // The [Bool] class is not marked as abstract, but has a factory
1758 // constructor that always throws. We never need to emit it. 1880 // constructor that always throws. We never need to emit it.
1759 unneededClasses.add(compiler.boolClass); 1881 unneededClasses.add(compiler.boolClass);
1760 1882
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1901 ClassBuilder closureBuilder = new ClassBuilder(); 2023 ClassBuilder closureBuilder = new ClassBuilder();
1902 // If a static function is used as a closure we need to add its name 2024 // If a static function is used as a closure we need to add its name
1903 // in case it is used in spawnFunction. 2025 // in case it is used in spawnFunction.
1904 String methodName = namer.STATIC_CLOSURE_NAME_NAME; 2026 String methodName = namer.STATIC_CLOSURE_NAME_NAME;
1905 emitClosureClassHeader( 2027 emitClosureClassHeader(
1906 mangledName, superName, <String>[invocationName, methodName], 2028 mangledName, superName, <String>[invocationName, methodName],
1907 closureBuilder); 2029 closureBuilder);
1908 2030
1909 addParameterStubs(callElement, closureBuilder.addProperty); 2031 addParameterStubs(callElement, closureBuilder.addProperty);
1910 2032
1911 DartType type = element.computeType(compiler);
1912 getTypedefChecksOn(type).forEach((Element typedef) {
1913 String operator = namer.operatorIs(typedef);
1914 closureBuilder.addProperty(operator, js('true'));
1915 });
1916
1917 // TODO(ngeoffray): Cache common base classes for closures, bound 2033 // TODO(ngeoffray): Cache common base classes for closures, bound
1918 // closures, and static closures that have common type checks. 2034 // closures, and static closures that have common type checks.
1919 boundClosures.add( 2035 boundClosures.add(
1920 js('$classesCollector.$mangledName = #', 2036 js('$classesCollector.$mangledName = #',
1921 closureBuilder.toObjectInitializer())); 2037 closureBuilder.toObjectInitializer()));
1922 2038
1923 staticGetters[element] = closureClassElement; 2039 staticGetters[element] = closureClassElement;
2040
2041 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
2042 RuntimeTypes rti = backend.rti;
2043 String encoding = rti.getSignatureEncoding(methodType, () => 'null');
2044 String operatorSignature = namer.operatorSignature();
2045 // TODO(johnniwinther): Make MiniJsParser support function expressions.
2046 closureBuilder.addProperty(operatorSignature,
2047 new jsAst.LiteralExpression(encoding));
2048 }
2049
2050 void emitIsFunctionTypeTest(FunctionType functionType) {
2051 String operator = namer.operatorIsType(functionType);
2052 closureBuilder.addProperty(operator, js('true'));
2053 }
2054
2055 generateFunctionTypeTests(element, element.computeType(compiler),
2056 emitFunctionTypeSignature, emitIsFunctionTypeTest);
1924 } 2057 }
1925 } 2058 }
1926 2059
1927 void emitClosureClassHeader(String mangledName, 2060 void emitClosureClassHeader(String mangledName,
1928 String superName, 2061 String superName,
1929 List<String> fieldNames, 2062 List<String> fieldNames,
1930 ClassBuilder builder) { 2063 ClassBuilder builder) {
1931 builder.addProperty('', 2064 builder.addProperty('',
1932 js.string("$superName;${fieldNames.join(',')}")); 2065 js.string("$superName;${fieldNames.join(',')}"));
1933 } 2066 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1971 if (inInterceptor) { 2104 if (inInterceptor) {
1972 cache = interceptorClosureCache; 2105 cache = interceptorClosureCache;
1973 } else { 2106 } else {
1974 cache = boundClosureCache; 2107 cache = boundClosureCache;
1975 } 2108 }
1976 List<String> fieldNames = <String>[]; 2109 List<String> fieldNames = <String>[];
1977 compiler.boundClosureClass.forEachInstanceField((_, Element field) { 2110 compiler.boundClosureClass.forEachInstanceField((_, Element field) {
1978 fieldNames.add(namer.getName(field)); 2111 fieldNames.add(namer.getName(field));
1979 }); 2112 });
1980 2113
1981 Iterable<Element> typedefChecks = 2114 DartType memberType = member.computeType(compiler);
1982 getTypedefChecksOn(member.computeType(compiler)); 2115 Map<FunctionType, bool> functionTypeChecks =
1983 bool hasTypedefChecks = !typedefChecks.isEmpty; 2116 getFunctionTypeChecksOn(memberType);
2117 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty;
1984 2118
1985 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 2119 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks;
1986 2120
2121 ClassElement classElement = member.getEnclosingClass();
1987 String closureClass = canBeShared ? cache[parameterCount] : null; 2122 String closureClass = canBeShared ? cache[parameterCount] : null;
1988 if (closureClass == null) { 2123 if (closureClass == null) {
1989 // Either the class was not cached yet, or there are optional parameters. 2124 // Either the class was not cached yet, or there are optional parameters.
1990 // Create a new closure class. 2125 // Create a new closure class.
1991 String name; 2126 String name;
1992 if (canBeShared) { 2127 if (canBeShared) {
1993 if (inInterceptor) { 2128 if (inInterceptor) {
1994 name = 'BoundClosure\$i${parameterCount}'; 2129 name = 'BoundClosure\$i${parameterCount}';
1995 } else { 2130 } else {
1996 name = 'BoundClosure\$${parameterCount}'; 2131 name = 'BoundClosure\$${parameterCount}';
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2032 arguments.add(js(name)); 2167 arguments.add(js(name));
2033 } 2168 }
2034 2169
2035 jsAst.Expression fun = js.fun( 2170 jsAst.Expression fun = js.fun(
2036 parameters, 2171 parameters,
2037 js.return_( 2172 js.return_(
2038 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments))); 2173 js('this')[fieldNames[0]][js('this')[fieldNames[1]]](arguments)));
2039 boundClosureBuilder.addProperty(invocationName, fun); 2174 boundClosureBuilder.addProperty(invocationName, fun);
2040 2175
2041 addParameterStubs(callElement, boundClosureBuilder.addProperty); 2176 addParameterStubs(callElement, boundClosureBuilder.addProperty);
2042 typedefChecks.forEach((Element typedef) { 2177
2043 String operator = namer.operatorIs(typedef); 2178 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
2044 boundClosureBuilder.addProperty(operator, js('true')); 2179 RuntimeTypes rti = backend.rti;
2045 }); 2180 String encoding = rti.getSignatureEncoding(
2181 methodType, () => 'this.${fieldNames[0]}');
2182 String operatorSignature = namer.operatorSignature();
2183 boundClosureBuilder.addProperty(operatorSignature,
2184 new jsAst.LiteralExpression(encoding));
2185 }
2186
2187 void emitIsFunctionTypeTest(FunctionType functionType) {
2188 String operator = namer.operatorIsType(functionType);
2189 boundClosureBuilder.addProperty(operator,
2190 new jsAst.LiteralBool(true));
2191 }
2192
2193 generateFunctionTypeTestsInternal(member, memberType, functionTypeChecks,
2194 emitFunctionTypeSignature, emitIsFunctionTypeTest);
2046 2195
2047 boundClosures.add( 2196 boundClosures.add(
2048 js('$classesCollector.$mangledName = #', 2197 js('$classesCollector.$mangledName = #',
2049 boundClosureBuilder.toObjectInitializer())); 2198 boundClosureBuilder.toObjectInitializer()));
2050 2199
2051 closureClass = namer.isolateAccess(closureClassElement); 2200 closureClass = namer.isolateAccess(closureClassElement);
2052 2201
2053 // Cache it. 2202 // Cache it.
2054 if (canBeShared) { 2203 if (canBeShared) {
2055 cache[parameterCount] = closureClass; 2204 cache[parameterCount] = closureClass;
(...skipping 10 matching lines...) Expand all
2066 arguments.add(js.string(targetName)); 2215 arguments.add(js.string(targetName));
2067 if (inInterceptor) { 2216 if (inInterceptor) {
2068 String receiverArg = fieldNames[2]; 2217 String receiverArg = fieldNames[2];
2069 parameters.add(receiverArg); 2218 parameters.add(receiverArg);
2070 arguments.add(js(receiverArg)); 2219 arguments.add(js(receiverArg));
2071 } else { 2220 } else {
2072 // Put null in the intercepted receiver field. 2221 // Put null in the intercepted receiver field.
2073 arguments.add(new jsAst.LiteralNull()); 2222 arguments.add(new jsAst.LiteralNull());
2074 } 2223 }
2075 2224
2225 jsAst.Expression newClosure = js(closureClass).newWith(arguments);
2076 jsAst.Expression getterFunction = js.fun( 2226 jsAst.Expression getterFunction = js.fun(
2077 parameters, 2227 parameters, js.return_(newClosure));
2078 js.return_(js(closureClass).newWith(arguments)));
2079 2228
2080 defineStub(getterName, getterFunction); 2229 defineStub(getterName, getterFunction);
2081 } 2230 }
2082 2231
2083 /** 2232 /**
2084 * Documentation wanted -- johnniwinther 2233 * Documentation wanted -- johnniwinther
2085 * 2234 *
2086 * Invariant: [member] must be a declaration element. 2235 * Invariant: [member] must be a declaration element.
2087 */ 2236 */
2088 void emitCallStubForGetter(Element member, 2237 void emitCallStubForGetter(Element member,
(...skipping 19 matching lines...) Expand all
2108 ? member.fixedBackendName() 2257 ? member.fixedBackendName()
2109 : namer.instanceFieldName(member); 2258 : namer.instanceFieldName(member);
2110 return js('this')[fieldName]; 2259 return js('this')[fieldName];
2111 } 2260 }
2112 } 2261 }
2113 2262
2114 // Two selectors may match but differ only in type. To avoid generating 2263 // Two selectors may match but differ only in type. To avoid generating
2115 // identical stubs for each we track untyped selectors which already have 2264 // identical stubs for each we track untyped selectors which already have
2116 // stubs. 2265 // stubs.
2117 Set<Selector> generatedSelectors = new Set<Selector>(); 2266 Set<Selector> generatedSelectors = new Set<Selector>();
2118 2267 DartType memberType = member.computeType(compiler);
2119 for (Selector selector in selectors) { 2268 for (Selector selector in selectors) {
2120 if (selector.applies(member, compiler)) { 2269 if (selector.applies(member, compiler)) {
2121 selector = selector.asUntyped; 2270 selector = selector.asUntyped;
2122 if (generatedSelectors.contains(selector)) continue; 2271 if (generatedSelectors.contains(selector)) continue;
2123 generatedSelectors.add(selector); 2272 generatedSelectors.add(selector);
2124 2273
2125 String invocationName = namer.invocationName(selector); 2274 String invocationName = namer.invocationName(selector);
2126 Selector callSelector = new Selector.callClosureFrom(selector); 2275 Selector callSelector = new Selector.callClosureFrom(selector);
2127 String closureCallName = namer.invocationName(callSelector); 2276 String closureCallName = namer.invocationName(callSelector);
2128 2277
(...skipping 1191 matching lines...) Expand 10 before | Expand all | Expand 10 after
3320 3469
3321 const String HOOKS_API_USAGE = """ 3470 const String HOOKS_API_USAGE = """
3322 // The code supports the following hooks: 3471 // The code supports the following hooks:
3323 // dartPrint(message) - if this function is defined it is called 3472 // dartPrint(message) - if this function is defined it is called
3324 // instead of the Dart [print] method. 3473 // instead of the Dart [print] method.
3325 // dartMainRunner(main) - if this function is defined, the Dart [main] 3474 // dartMainRunner(main) - if this function is defined, the Dart [main]
3326 // method will not be invoked directly. 3475 // method will not be invoked directly.
3327 // Instead, a closure that will invoke [main] is 3476 // Instead, a closure that will invoke [main] is
3328 // passed to [dartMainRunner]. 3477 // passed to [dartMainRunner].
3329 """; 3478 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698