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

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: Register dependency Created 7 years, 9 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 * `x is Set<String>` then the ClassElement `Set` will occur once in 101 * `x is Set<String>` then the ClassElement `Set` will occur once in
102 * [checkedClasses]. 102 * [checkedClasses].
103 */ 103 */
104 Set<ClassElement> checkedClasses; 104 Set<ClassElement> checkedClasses;
105 105
106 /** 106 /**
107 * Raw Typedef symbols occuring in is-checks and type assertions. If the 107 * Raw Typedef symbols occuring in is-checks and type assertions. If the
108 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement 108 * program contains `x is F<int>` and `x is F<bool>` then the TypedefElement
109 * `F` will occur once in [checkedTypedefs]. 109 * `F` will occur once in [checkedTypedefs].
110 */ 110 */
111 Set<TypedefElement> checkedTypedefs; 111 Set<FunctionType> checkedFunctionTypes;
112
113 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes
114 = new Map<ClassElement, Set<FunctionType>>();
115
116 Set<FunctionType> checkedNonGenericFunctionTypes
117 = new Set<FunctionType>();
118
119 void registerDynamicFunctionTypeCheck(FunctionType functionType) {
120 ClassElement classElement = Types.getClassContext(functionType);
121 if (classElement != null) {
122 checkedGenericFunctionTypes.putIfAbsent(classElement,
123 () => new Set<FunctionType>()).add(functionType);
124 } else {
125 checkedNonGenericFunctionTypes.add(functionType);
126 }
127 }
112 128
113 final bool generateSourceMap; 129 final bool generateSourceMap;
114 130
115 Iterable<ClassElement> cachedClassesUsingTypeVariableTests; 131 Iterable<ClassElement> cachedClassesUsingTypeVariableTests;
116 132
117 Iterable<ClassElement> get classesUsingTypeVariableTests { 133 Iterable<ClassElement> get classesUsingTypeVariableTests {
118 if (cachedClassesUsingTypeVariableTests == null) { 134 if (cachedClassesUsingTypeVariableTests == null) {
119 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks 135 cachedClassesUsingTypeVariableTests = compiler.codegenWorld.isChecks
120 .where((DartType t) => t is TypeVariableType) 136 .where((DartType t) => t is TypeVariableType)
121 .map((TypeVariableType v) => v.element.getEnclosingClass()) 137 .map((TypeVariableType v) => v.element.getEnclosingClass())
(...skipping 10 matching lines...) Expand all
132 constantEmitter = new ConstantEmitter(compiler, namer), 148 constantEmitter = new ConstantEmitter(compiler, namer),
133 super(compiler) { 149 super(compiler) {
134 nativeEmitter = new NativeEmitter(this); 150 nativeEmitter = new NativeEmitter(this);
135 } 151 }
136 152
137 void addComment(String comment, CodeBuffer buffer) { 153 void addComment(String comment, CodeBuffer buffer) {
138 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler)); 154 buffer.write(jsAst.prettyPrint(js.comment(comment), compiler));
139 } 155 }
140 156
141 void computeRequiredTypeChecks() { 157 void computeRequiredTypeChecks() {
142 assert(checkedClasses == null && checkedTypedefs == null); 158 assert(checkedClasses == null && checkedFunctionTypes == null);
143 159
144 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests); 160 compiler.codegenWorld.addImplicitChecks(classesUsingTypeVariableTests);
145 161
146 checkedClasses = new Set<ClassElement>(); 162 checkedClasses = new Set<ClassElement>();
147 checkedTypedefs = new Set<TypedefElement>(); 163 checkedFunctionTypes = new Set<FunctionType>();
148 compiler.codegenWorld.isChecks.forEach((DartType t) { 164 compiler.codegenWorld.isChecks.forEach((DartType t) {
149 if (t is InterfaceType) { 165 if (t is InterfaceType) {
150 checkedClasses.add(t.element); 166 checkedClasses.add(t.element);
151 } else if (t is TypedefType) { 167 } else if (t is FunctionType) {
152 checkedTypedefs.add(t.element); 168 checkedFunctionTypes.add(t);
153 } 169 }
154 }); 170 });
155 } 171 }
156 172
157 jsAst.Expression constantReference(Constant value) { 173 jsAst.Expression constantReference(Constant value) {
158 return constantEmitter.reference(value); 174 return constantEmitter.reference(value);
159 } 175 }
160 176
161 jsAst.Expression constantInitializerExpression(Constant value) { 177 jsAst.Expression constantInitializerExpression(Constant value) {
162 return constantEmitter.initializationExpression(value); 178 return constantEmitter.initializationExpression(value);
(...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after
967 return; 983 return;
968 } 984 }
969 if (nativeEmitter.requiresNativeIsCheck(other)) { 985 if (nativeEmitter.requiresNativeIsCheck(other)) {
970 code = js.fun([], [js.return_(true)]); 986 code = js.fun([], [js.return_(true)]);
971 } else { 987 } else {
972 code = new jsAst.LiteralBool(true); 988 code = new jsAst.LiteralBool(true);
973 } 989 }
974 builder.addProperty(namer.operatorIs(other), code); 990 builder.addProperty(namer.operatorIs(other), code);
975 } 991 }
976 992
993 void generateIsFunctionTypeTest(FunctionType type) {
994 builder.addProperty(namer.operatorIsFunctionType(type),
995 new jsAst.LiteralBool(true));
996 }
997
998 void generateFunctionTypeSignature(FunctionType type) {
999 RuntimeTypeInformation rti = backend.rti;
1000 String encoding = rti.getTypeEncoding(type, alwaysGenerateFunction: true);
1001 String operatorSignature = namer.operatorSignature();
1002 builder.addProperty(operatorSignature,
1003 new jsAst.LiteralExpression(encoding));
1004 }
1005
977 void generateSubstitution(Element other, {bool emitNull: false}) { 1006 void generateSubstitution(Element other, {bool emitNull: false}) {
978 RuntimeTypeInformation rti = backend.rti; 1007 RuntimeTypeInformation rti = backend.rti;
979 // TODO(karlklose): support typedefs with variables. 1008 // TODO(karlklose): support typedefs with variables.
980 jsAst.Expression expression; 1009 jsAst.Expression expression;
981 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1010 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
982 if (other.kind == ElementKind.CLASS) { 1011 if (other.kind == ElementKind.CLASS) {
983 String substitution = rti.getSupertypeSubstitution(classElement, other, 1012 String substitution = rti.getSupertypeSubstitution(classElement, other,
984 alwaysGenerateFunction: true); 1013 alwaysGenerateFunction: true);
985 if (substitution != null) { 1014 if (substitution != null) {
986 expression = new jsAst.LiteralExpression(substitution); 1015 expression = new jsAst.LiteralExpression(substitution);
987 } else if (emitNull || needsNativeCheck) { 1016 } else if (emitNull || needsNativeCheck) {
988 expression = new jsAst.LiteralNull(); 1017 expression = new jsAst.LiteralNull();
989 } 1018 }
990 } 1019 }
991 if (expression != null) { 1020 if (expression != null) {
992 if (needsNativeCheck) { 1021 if (needsNativeCheck) {
993 expression = js.fun([], js.return_(expression)); 1022 expression = js.fun([], js.return_(expression));
994 } 1023 }
995 builder.addProperty(namer.substitutionName(other), expression); 1024 builder.addProperty(namer.substitutionName(other), expression);
996 } 1025 }
997 } 1026 }
998 1027
999 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); 1028 generateIsTestsOn(classElement, generateIsTest,
1029 generateIsFunctionTypeTest, generateFunctionTypeSignature,
1030 generateSubstitution);
1000 1031
1001 if (identical(classElement, compiler.objectClass) 1032 if (identical(classElement, compiler.objectClass)
1002 && compiler.enabledNoSuchMethod) { 1033 && compiler.enabledNoSuchMethod) {
1003 // Emit the noSuchMethod handlers on the Object prototype now, 1034 // Emit the noSuchMethod handlers on the Object prototype now,
1004 // so that the code in the dynamicFunction helper can find 1035 // so that the code in the dynamicFunction helper can find
1005 // them. Note that this helper is invoked before analyzing the 1036 // them. Note that this helper is invoked before analyzing the
1006 // full JS script. 1037 // full JS script.
1007 if (!nativeEmitter.handleNoSuchMethod) { 1038 if (!nativeEmitter.handleNoSuchMethod) {
1008 emitNoSuchMethodHandlers(builder.addProperty); 1039 emitNoSuchMethodHandlers(builder.addProperty);
1009 } 1040 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1047 for (ClassElement cls in typeChecks) { 1078 for (ClassElement cls in typeChecks) {
1048 String holder = namer.isolateAccess(cls); 1079 String holder = namer.isolateAccess(cls);
1049 for (ClassElement check in typeChecks[cls]) { 1080 for (ClassElement check in typeChecks[cls]) {
1050 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 1081 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N');
1051 String body = rti.getSupertypeSubstitution(cls, check); 1082 String body = rti.getSupertypeSubstitution(cls, check);
1052 if (body != null) { 1083 if (body != null) {
1053 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ; 1084 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ;
1054 } 1085 }
1055 }; 1086 };
1056 } 1087 }
1088
1089 checkedNonGenericFunctionTypes.forEach((FunctionType type) {
1090 String encoding = rti.getTypeEncoding(type);
1091 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N');
1092 });
1093
1094 checkedGenericFunctionTypes.forEach(
1095 (ClassElement cls, Set<FunctionType> functionTypes) {
1096 for (FunctionType type in functionTypes) {
1097 String encoding = rti.getTypeEncoding(type);
1098 buffer.add('${namer.signatureName(type)}$_=${_}$encoding$N');
1099 }
1100 });
1057 } 1101 }
1058 1102
1059 void visitNativeMixins(ClassElement classElement, 1103 void visitNativeMixins(ClassElement classElement,
1060 void visit(MixinApplicationElement mixinApplication)) { 1104 void visit(MixinApplicationElement mixinApplication)) {
1061 if (!classElement.isNative()) return; 1105 if (!classElement.isNative()) return;
1062 // Use recursion to make sure to visit the superclasses before the 1106 // Use recursion to make sure to visit the superclasses before the
1063 // subclasses. Once we start keeping track of the emitted fields 1107 // subclasses. Once we start keeping track of the emitted fields
1064 // and members, we're going to want to visit these in the other 1108 // and members, we're going to want to visit these in the other
1065 // order so we get the most specialized definition first. 1109 // order so we get the most specialized definition first.
1066 void recurse(ClassElement cls) { 1110 void recurse(ClassElement cls) {
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 return arity; 1426 return arity;
1383 } 1427 }
1384 1428
1385 int _compareSelectorNames(Selector selector1, Selector selector2) { 1429 int _compareSelectorNames(Selector selector1, Selector selector2) {
1386 String name1 = selector1.name.toString(); 1430 String name1 = selector1.name.toString();
1387 String name2 = selector2.name.toString(); 1431 String name2 = selector2.name.toString();
1388 if (name1 != name2) return Comparable.compare(name1, name2); 1432 if (name1 != name2) return Comparable.compare(name1, name2);
1389 return _selectorRank(selector1) - _selectorRank(selector2); 1433 return _selectorRank(selector1) - _selectorRank(selector2);
1390 } 1434 }
1391 1435
1392 Iterable<Element> getTypedefChecksOn(DartType type) { 1436 /**
1393 bool isSubtype(TypedefElement typedef) { 1437 * Returns a mapping containing all checked function types for which [type]
1394 FunctionType typedefType = 1438 * can be a subtype. A function type is mapped to [:true:] if [type] is
1395 typedef.computeType(compiler).unalias(compiler); 1439 * statically known to be a subtype of it.
1396 return compiler.types.isSubtype(type, typedefType); 1440 */
1441 // TODO(johnniwinther): Change to return a mapping from function types to
1442 // a set of variable points and use this to detect statically/dynamically
1443 // known subtype relations.
1444 Map<FunctionType, bool> getFunctionTypeChecksOn(DartType type) {
1445 Map<FunctionType, bool> functionTypeMap =
1446 new LinkedHashMap<FunctionType, bool>();
1447 for (FunctionType functionType in checkedFunctionTypes) {
1448 if (compiler.types.isSubtype(type, functionType)) {
1449 functionTypeMap[functionType] = true;
1450 } else if (compiler.types.isPotentialSubtype(type, functionType)) {
1451 functionTypeMap[functionType] = false;
1452 }
1397 } 1453 }
1398 return checkedTypedefs.where(isSubtype).toList() 1454 // TODO(johnniwinther): Ensure stable ordering of the keys.
1399 ..sort(Elements.compareByPosition); 1455 return functionTypeMap;
1400 } 1456 }
1401 1457
1402 /** 1458 /**
1403 * Generate "is tests" for [cls]: itself, and the "is tests" for the 1459 * Generate "is tests" for [cls]: itself, and the "is tests" for the
1404 * classes it implements and type argument substitution functions for these 1460 * classes it implements and type argument substitution functions for these
1405 * tests. We don't need to add the "is tests" of the super class because 1461 * tests. We don't need to add the "is tests" of the super class because
1406 * they will be inherited at runtime, but we may need to generate the 1462 * they will be inherited at runtime, but we may need to generate the
1407 * substitutions, because they may have changed. 1463 * substitutions, because they may have changed.
1408 */ 1464 */
1409 void generateIsTestsOn(ClassElement cls, 1465 void generateIsTestsOn(ClassElement cls,
1410 void emitIsTest(Element element), 1466 void emitIsTest(Element element),
1467 void emitIsFunctionTypeTest(FunctionType type),
1468 void emitFunctionTypeSignature(FunctionType type),
1411 void emitSubstitution(Element element, {emitNull})) { 1469 void emitSubstitution(Element element, {emitNull})) {
1412 if (checkedClasses.contains(cls)) { 1470 if (checkedClasses.contains(cls)) {
1413 emitIsTest(cls); 1471 emitIsTest(cls);
1414 emitSubstitution(cls); 1472 emitSubstitution(cls);
1415 } 1473 }
1416 1474
1417 RuntimeTypeInformation rti = backend.rti; 1475 RuntimeTypeInformation rti = backend.rti;
1418 ClassElement superclass = cls.superclass; 1476 ClassElement superclass = cls.superclass;
1419 1477
1420 bool haveSameTypeVariables(ClassElement a, ClassElement b) { 1478 bool haveSameTypeVariables(ClassElement a, ClassElement b) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1452 } 1510 }
1453 } 1511 }
1454 void emitNothing(_, {emitNull}) {}; 1512 void emitNothing(_, {emitNull}) {};
1455 emitSubstitution = emitNothing; 1513 emitSubstitution = emitNothing;
1456 } 1514 }
1457 1515
1458 Set<Element> generated = new Set<Element>(); 1516 Set<Element> generated = new Set<Element>();
1459 // A class that defines a [:call:] method implicitly implements 1517 // A class that defines a [:call:] method implicitly implements
1460 // [Function] and needs checks for all typedefs that are used in is-checks. 1518 // [Function] and needs checks for all typedefs that are used in is-checks.
1461 if (checkedClasses.contains(compiler.functionClass) || 1519 if (checkedClasses.contains(compiler.functionClass) ||
1462 !checkedTypedefs.isEmpty) { 1520 !checkedFunctionTypes.isEmpty) {
1463 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); 1521 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME);
1464 if (call == null) { 1522 if (call == null) {
1465 // If [cls] is a closure, it has a synthetic call operator method. 1523 // If [cls] is a closure, it has a synthetic call operator method.
1466 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); 1524 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME);
1467 } 1525 }
1468 if (call != null) { 1526 if (call != null) {
1469 generateInterfacesIsTests(compiler.functionClass, 1527 generateInterfacesIsTests(compiler.functionClass,
1470 emitIsTest, 1528 emitIsTest,
1471 emitSubstitution, 1529 emitSubstitution,
1472 generated); 1530 generated);
1473 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); 1531 FunctionType callType = call.computeType(compiler);
1532 Map<FunctionType,bool> functionTypeChecks =
1533 getFunctionTypeChecksOn(callType);
1534 bool hasDynamicFunctionTypeCheck = false;
1535 functionTypeChecks.forEach((FunctionType functionType,
1536 bool knownSubtype) {
1537 emitIsFunctionTypeTest(functionType);
1538 if (!knownSubtype) {
1539 registerDynamicFunctionTypeCheck(functionType);
1540 hasDynamicFunctionTypeCheck = true;
1541 }
1542 });
1543 if (hasDynamicFunctionTypeCheck) {
1544 emitFunctionTypeSignature(callType);
1545 }
1474 } 1546 }
1475 } 1547 }
1476 1548
1477 for (DartType interfaceType in cls.interfaces) { 1549 for (DartType interfaceType in cls.interfaces) {
1478 generateInterfacesIsTests(interfaceType.element, emitIsTest, 1550 generateInterfacesIsTests(interfaceType.element, emitIsTest,
1479 emitSubstitution, generated); 1551 emitSubstitution, generated);
1480 } 1552 }
1481 1553
1482 // For native classes, we also have to run through their mixin 1554 // For native classes, we also have to run through their mixin
1483 // applications and make sure we deal with 'is' tests correctly 1555 // applications and make sure we deal with 'is' tests correctly
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
1646 jsAst.Expression assignment = 1718 jsAst.Expression assignment =
1647 js[isolateProperties][staticName][name].assign(value); 1719 js[isolateProperties][staticName][name].assign(value);
1648 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler)); 1720 buffer.write(jsAst.prettyPrint(assignment.toStatement(), compiler));
1649 buffer.write('$N'); 1721 buffer.write('$N');
1650 }); 1722 });
1651 1723
1652 // If a static function is used as a closure we need to add its name 1724 // If a static function is used as a closure we need to add its name
1653 // in case it is used in spawnFunction. 1725 // in case it is used in spawnFunction.
1654 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; 1726 String fieldName = namer.STATIC_CLOSURE_NAME_NAME;
1655 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N'); 1727 buffer.write('$fieldAccess.$fieldName$_=$_"$staticName"$N');
1656 getTypedefChecksOn(element.computeType(compiler)).forEach( 1728 FunctionType elementType = element.computeType(compiler);
1657 (Element typedef) { 1729 Map<FunctionType,bool> functionTypeChecks =
1658 String operator = namer.operatorIs(typedef); 1730 getFunctionTypeChecksOn(elementType);
1659 buffer.write('$fieldAccess.$operator$_=${_}true$N'); 1731 bool hasDynamicFunctionTypeCheck = false;
1732 functionTypeChecks.forEach((FunctionType functionType,
1733 bool knownSubtype) {
1734 String operator = namer.operatorIsFunctionType(functionType);
1735 buffer.write('$fieldAccess.$operator$_=${_}true$N');
1736 if (!knownSubtype) {
1737 TypeVariableType typeVariable = functionType.typeVariableOccurrence;
1738 registerDynamicFunctionTypeCheck(functionType);
1739 hasDynamicFunctionTypeCheck = true;
1660 } 1740 }
1661 ); 1741 });
1742 if (hasDynamicFunctionTypeCheck) {
1743 RuntimeTypeInformation rti = backend.rti;
1744 String encoding = rti.getTypeEncoding(elementType,
1745 alwaysGenerateFunction: true);
1746 String operatorSignature = namer.operatorSignature();
1747 buffer.add('$fieldAccess.$operatorSignature$_=${_}$encoding$N');
1748 }
1749
1662 } 1750 }
1663 } 1751 }
1664 1752
1665 void emitBoundClosureClassHeader(String mangledName, 1753 void emitBoundClosureClassHeader(String mangledName,
1666 String superName, 1754 String superName,
1667 List<String> fieldNames, 1755 List<String> fieldNames,
1668 ClassBuilder builder) { 1756 ClassBuilder builder) {
1669 builder.addProperty('', 1757 builder.addProperty('',
1670 js.string("$superName;${fieldNames.join(',')}")); 1758 js.string("$superName;${fieldNames.join(',')}"));
1671 } 1759 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1712 extraArg = 'receiver'; 1800 extraArg = 'receiver';
1713 } else { 1801 } else {
1714 cache = boundClosureCache; 1802 cache = boundClosureCache;
1715 } 1803 }
1716 List<String> fieldNames = compiler.enableMinification 1804 List<String> fieldNames = compiler.enableMinification
1717 ? inInterceptor ? const ['a', 'b', 'c'] 1805 ? inInterceptor ? const ['a', 'b', 'c']
1718 : const ['a', 'b'] 1806 : const ['a', 'b']
1719 : inInterceptor ? const ['self', 'target', 'receiver'] 1807 : inInterceptor ? const ['self', 'target', 'receiver']
1720 : const ['self', 'target']; 1808 : const ['self', 'target'];
1721 1809
1722 Iterable<Element> typedefChecks = 1810 DartType memberType = member.computeType(compiler);
1723 getTypedefChecksOn(member.computeType(compiler)); 1811 Map<FunctionType, bool> functionTypeChecks =
1724 bool hasTypedefChecks = !typedefChecks.isEmpty; 1812 getFunctionTypeChecksOn(memberType);
1813 bool hasFunctionTypeChecks = !functionTypeChecks.isEmpty;
1725 1814
1726 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; 1815 bool canBeShared = !hasOptionalParameters && !hasFunctionTypeChecks;
1727 1816
1817 ClassElement classElement = member.getEnclosingClass();
1728 String closureClass = canBeShared ? cache[parameterCount] : null; 1818 String closureClass = canBeShared ? cache[parameterCount] : null;
1729 if (closureClass == null) { 1819 if (closureClass == null) {
1730 // Either the class was not cached yet, or there are optional parameters. 1820 // Either the class was not cached yet, or there are optional parameters.
1731 // Create a new closure class. 1821 // Create a new closure class.
1732 String name; 1822 String name;
1733 if (canBeShared) { 1823 if (canBeShared) {
1734 if (inInterceptor) { 1824 if (inInterceptor) {
1735 name = 'BoundClosure\$i${parameterCount}'; 1825 name = 'BoundClosure\$i${parameterCount}';
1736 } else { 1826 } else {
1737 name = 'BoundClosure\$${parameterCount}'; 1827 name = 'BoundClosure\$${parameterCount}';
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1774 arguments.add(js[name]); 1864 arguments.add(js[name]);
1775 } 1865 }
1776 1866
1777 jsAst.Expression fun = js.fun( 1867 jsAst.Expression fun = js.fun(
1778 parameters, 1868 parameters,
1779 js.return_( 1869 js.return_(
1780 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments))); 1870 js['this'][fieldNames[0]][js['this'][fieldNames[1]]](arguments)));
1781 boundClosureBuilder.addProperty(invocationName, fun); 1871 boundClosureBuilder.addProperty(invocationName, fun);
1782 1872
1783 addParameterStubs(callElement, boundClosureBuilder.addProperty); 1873 addParameterStubs(callElement, boundClosureBuilder.addProperty);
1784 typedefChecks.forEach((Element typedef) { 1874 bool hasDynamicFunctionTypeCheck = false;
1785 String operator = namer.operatorIs(typedef); 1875 functionTypeChecks.forEach((FunctionType functionType,
1876 bool knownSubtype) {
1877 String operator = namer.operatorIsFunctionType(functionType);
1786 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true)); 1878 boundClosureBuilder.addProperty(operator, new jsAst.LiteralBool(true));
1879 if (!knownSubtype) {
1880 registerDynamicFunctionTypeCheck(functionType);
1881 hasDynamicFunctionTypeCheck = true;
1882 }
1787 }); 1883 });
1884 if (hasDynamicFunctionTypeCheck) {
1885 RuntimeTypeInformation rti = backend.rti;
1886 String encoding = rti.getTypeEncoding(memberType,
1887 alwaysGenerateFunction: true);
1888 String operatorSignature = namer.operatorSignature();
1889 boundClosureBuilder.addProperty(operatorSignature,
1890 new jsAst.LiteralExpression(encoding));
1891 }
1788 1892
1789 boundClosures.add( 1893 boundClosures.add(
1790 js[classesCollector][mangledName].assign( 1894 js[classesCollector][mangledName].assign(
1791 boundClosureBuilder.toObjectInitializer())); 1895 boundClosureBuilder.toObjectInitializer()));
1792 1896
1793 closureClass = namer.isolateAccess(closureClassElement); 1897 closureClass = namer.isolateAccess(closureClassElement);
1794 1898
1795 // Cache it. 1899 // Cache it.
1796 if (canBeShared) { 1900 if (canBeShared) {
1797 cache[parameterCount] = closureClass; 1901 cache[parameterCount] = closureClass;
1798 } 1902 }
1799 } 1903 }
1800 1904
1801 // And finally the getter. 1905 // And finally the getter.
1802 String getterName = namer.getterName(member); 1906 String getterName = namer.getterName(member);
1803 String targetName = namer.instanceMethodName(member); 1907 String targetName = namer.instanceMethodName(member);
1804 1908
1805 List<String> parameters = <String>[]; 1909 List<String> parameters = <String>[];
1806 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 1910 List<jsAst.Expression> arguments = <jsAst.Expression>[];
1807 arguments.add(js['this']); 1911 arguments.add(js['this']);
1808 arguments.add(js.string(targetName)); 1912 arguments.add(js.string(targetName));
1809 if (inInterceptor) { 1913 if (inInterceptor) {
1810 parameters.add(extraArg); 1914 parameters.add(extraArg);
1811 arguments.add(js[extraArg]); 1915 arguments.add(js[extraArg]);
1812 } 1916 }
1813 1917
1918 jsAst.Expression newClosure = js[closureClass].newWith(arguments);
1814 jsAst.Expression getterFunction = js.fun( 1919 jsAst.Expression getterFunction = js.fun(
1815 parameters, 1920 parameters,
1816 js.return_(js[closureClass].newWith(arguments))); 1921 forwardRuntimeTypeInfo(newClosure, memberType, classElement));
1817 1922
1818 defineStub(getterName, getterFunction); 1923 defineStub(getterName, getterFunction);
1819 } 1924 }
1820 1925
1821 /** 1926 /**
1927 * Wraps the [newExpression] of a closure with code for setting the runtime
1928 * type information if needed.
1929 */
1930 forwardRuntimeTypeInfo(jsAst.Expression newExpression,
1931 DartType memberType,
1932 ClassElement thisClass) {
1933 if (compiler.world.needsRti(thisClass) &&
1934 memberType.containsTypeVariables) {
1935 String forwardRuntimeTypeInfo =
1936 namer.isolateAccess(backend.getForwardRuntimeTypeInfo());
1937 String substitution = namer.substitutionName(thisClass);
1938 return js.return_(new jsAst.Call(js[forwardRuntimeTypeInfo],
1939 [newExpression, js['this.$substitution'], js['this']]));
1940 } else {
1941 return js.return_(newExpression);
1942 }
1943 }
1944
1945 /**
1822 * Documentation wanted -- johnniwinther 1946 * Documentation wanted -- johnniwinther
1823 * 1947 *
1824 * Invariant: [member] must be a declaration element. 1948 * Invariant: [member] must be a declaration element.
1825 */ 1949 */
1826 void emitCallStubForGetter(Element member, 1950 void emitCallStubForGetter(Element member,
1827 Set<Selector> selectors, 1951 Set<Selector> selectors,
1828 DefineStubFunction defineStub) { 1952 DefineStubFunction defineStub) {
1829 assert(invariant(member, member.isDeclaration)); 1953 assert(invariant(member, member.isDeclaration));
1830 LibraryElement memberLibrary = member.getLibrary(); 1954 LibraryElement memberLibrary = member.getLibrary();
1831 // If the method is intercepted, the stub gets the 1955 // If the method is intercepted, the stub gets the
(...skipping 14 matching lines...) Expand all
1846 ? member.fixedBackendName() 1970 ? member.fixedBackendName()
1847 : namer.instanceFieldName(member); 1971 : namer.instanceFieldName(member);
1848 return js['this'][fieldName]; 1972 return js['this'][fieldName];
1849 } 1973 }
1850 } 1974 }
1851 1975
1852 // Two selectors may match but differ only in type. To avoid generating 1976 // Two selectors may match but differ only in type. To avoid generating
1853 // identical stubs for each we track untyped selectors which already have 1977 // identical stubs for each we track untyped selectors which already have
1854 // stubs. 1978 // stubs.
1855 Set<Selector> generatedSelectors = new Set<Selector>(); 1979 Set<Selector> generatedSelectors = new Set<Selector>();
1856 1980 DartType memberType = member.computeType(compiler);
1857 for (Selector selector in selectors) { 1981 for (Selector selector in selectors) {
1858 if (selector.applies(member, compiler)) { 1982 if (selector.applies(member, compiler)) {
1859 selector = selector.asUntyped; 1983 selector = selector.asUntyped;
1860 if (generatedSelectors.contains(selector)) continue; 1984 if (generatedSelectors.contains(selector)) continue;
1861 generatedSelectors.add(selector); 1985 generatedSelectors.add(selector);
1862 1986
1863 String invocationName = namer.invocationName(selector); 1987 String invocationName = namer.invocationName(selector);
1864 Selector callSelector = new Selector.callClosureFrom(selector); 1988 Selector callSelector = new Selector.callClosureFrom(selector);
1865 String closureCallName = namer.invocationName(callSelector); 1989 String closureCallName = namer.invocationName(callSelector);
1866 1990
(...skipping 919 matching lines...) Expand 10 before | Expand all | Expand 10 after
2786 """; 2910 """;
2787 const String HOOKS_API_USAGE = """ 2911 const String HOOKS_API_USAGE = """
2788 // The code supports the following hooks: 2912 // The code supports the following hooks:
2789 // dartPrint(message) - if this function is defined it is called 2913 // dartPrint(message) - if this function is defined it is called
2790 // instead of the Dart [print] method. 2914 // instead of the Dart [print] method.
2791 // dartMainRunner(main) - if this function is defined, the Dart [main] 2915 // dartMainRunner(main) - if this function is defined, the Dart [main]
2792 // method will not be invoked directly. 2916 // method will not be invoked directly.
2793 // Instead, a closure that will invoke [main] is 2917 // Instead, a closure that will invoke [main] is
2794 // passed to [dartMainRunner]. 2918 // passed to [dartMainRunner].
2795 """; 2919 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698