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

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

Issue 12330135: Make instance methods whose names collide with intercepted methods have the interceptor calling con… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: 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 635 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 // hit the method directly. 646 // hit the method directly.
647 return; 647 return;
648 } 648 }
649 ConstantHandler handler = compiler.constantHandler; 649 ConstantHandler handler = compiler.constantHandler;
650 List<SourceString> names = selector.getOrderedNamedArguments(); 650 List<SourceString> names = selector.getOrderedNamedArguments();
651 651
652 String invocationName = namer.invocationName(selector); 652 String invocationName = namer.invocationName(selector);
653 if (alreadyGenerated.contains(invocationName)) return; 653 if (alreadyGenerated.contains(invocationName)) return;
654 alreadyGenerated.add(invocationName); 654 alreadyGenerated.add(invocationName);
655 655
656 bool isInterceptorClass = 656 bool isInterceptedMethod = backend.isInterceptedMethod(member);
657 backend.isInterceptorClass(member.getEnclosingClass());
658 657
659 // If the method is in an interceptor class, we need to also pass 658 // If the method is intercepted, we need to also pass
660 // the actual receiver. 659 // the actual receiver.
661 int extraArgumentCount = isInterceptorClass ? 1 : 0; 660 int extraArgumentCount = isInterceptedMethod ? 1 : 0;
662 // Use '$receiver' to avoid clashes with other parameter names. Using 661 // Use '$receiver' to avoid clashes with other parameter names. Using
663 // '$receiver' works because [:namer.safeName:] used for getting parameter 662 // '$receiver' works because [:namer.safeName:] used for getting parameter
664 // names never returns a name beginning with a single '$'. 663 // names never returns a name beginning with a single '$'.
665 String receiverArgumentName = r'$receiver'; 664 String receiverArgumentName = r'$receiver';
666 665
667 // The parameters that this stub takes. 666 // The parameters that this stub takes.
668 List<jsAst.Parameter> parametersBuffer = 667 List<jsAst.Parameter> parametersBuffer =
669 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount); 668 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount);
670 // The arguments that will be passed to the real method. 669 // The arguments that will be passed to the real method.
671 List<jsAst.Expression> argumentsBuffer = 670 List<jsAst.Expression> argumentsBuffer =
672 new List<jsAst.Expression>( 671 new List<jsAst.Expression>(
673 parameters.parameterCount + extraArgumentCount); 672 parameters.parameterCount + extraArgumentCount);
674 673
675 int count = 0; 674 int count = 0;
676 if (isInterceptorClass) { 675 if (isInterceptedMethod) {
677 count++; 676 count++;
678 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName); 677 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
679 argumentsBuffer[0] = js[receiverArgumentName]; 678 argumentsBuffer[0] = js[receiverArgumentName];
680 } 679 }
681 680
682 int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1; 681 int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1;
683 TreeElements elements = 682 TreeElements elements =
684 compiler.enqueuer.resolution.getCachedElements(member); 683 compiler.enqueuer.resolution.getCachedElements(member);
685 684
686 parameters.orderedForEachParameter((Element element) { 685 parameters.orderedForEachParameter((Element element) {
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 } 905 }
907 906
908 /** 907 /**
909 * Documentation wanted -- johnniwinther 908 * Documentation wanted -- johnniwinther
910 * 909 *
911 * Invariant: [classElement] must be a declaration element. 910 * Invariant: [classElement] must be a declaration element.
912 */ 911 */
913 void emitInstanceMembers(ClassElement classElement, 912 void emitInstanceMembers(ClassElement classElement,
914 ClassBuilder builder) { 913 ClassBuilder builder) {
915 assert(invariant(classElement, classElement.isDeclaration)); 914 assert(invariant(classElement, classElement.isDeclaration));
916 if (classElement == backend.objectInterceptorClass) {
917 emitInterceptorMethods(builder);
918 // The ObjectInterceptor does not have any instance methods.
919 return;
920 }
921 915
922 void visitMember(ClassElement enclosing, Element member) { 916 void visitMember(ClassElement enclosing, Element member) {
923 assert(invariant(classElement, member.isDeclaration)); 917 assert(invariant(classElement, member.isDeclaration));
924 if (member.isInstanceMember()) { 918 if (member.isInstanceMember()) {
925 addInstanceMember(member, builder); 919 addInstanceMember(member, builder);
926 } 920 }
927 } 921 }
928 922
929 // TODO(kasperl): We should make sure to only emit one version of 923 // TODO(kasperl): We should make sure to only emit one version of
930 // overridden methods. Right now, we rely on the ordering so the 924 // overridden methods. Right now, we rely on the ordering so the
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 && compiler.enabledNoSuchMethod) { 982 && compiler.enabledNoSuchMethod) {
989 // Emit the noSuchMethod handlers on the Object prototype now, 983 // Emit the noSuchMethod handlers on the Object prototype now,
990 // so that the code in the dynamicFunction helper can find 984 // so that the code in the dynamicFunction helper can find
991 // them. Note that this helper is invoked before analyzing the 985 // them. Note that this helper is invoked before analyzing the
992 // full JS script. 986 // full JS script.
993 if (!nativeEmitter.handleNoSuchMethod) { 987 if (!nativeEmitter.handleNoSuchMethod) {
994 emitNoSuchMethodHandlers(builder.addProperty); 988 emitNoSuchMethodHandlers(builder.addProperty);
995 } 989 }
996 } 990 }
997 991
998 if (backend.isInterceptorClass(classElement)) { 992 if (backend.isInterceptorClass(classElement)
999 // The operator== method in [:Object:] does not take the same 993 && classElement != compiler.objectClass) {
1000 // number of arguments as an intercepted method, therefore we 994 // We optimize the operator== on interceptor classes to
1001 // explicitely add one to all interceptor classes. Note that we 995 // just do a JavaScript double or triple equals.
1002 // would not have do do that if all intercepted methods had
1003 // a calling convention where the receiver is the first
1004 // parameter.
1005 String name = backend.namer.publicInstanceMethodNameByArity( 996 String name = backend.namer.publicInstanceMethodNameByArity(
1006 const SourceString('=='), 1); 997 const SourceString('=='), 1);
1007 Function kind = (classElement == backend.jsNullClass) 998 Function kind = (classElement == backend.jsNullClass)
1008 ? js.equals 999 ? js.equals
1009 : js.strictEquals; 1000 : js.strictEquals;
1010 builder.addProperty(name, js.fun(['receiver', 'a'], 1001 builder.addProperty(name, js.fun(['receiver', 'a'],
1011 js.block(js.return_(kind(js['receiver'], js['a']))))); 1002 js.block(js.return_(kind(js['receiver'], js['a'])))));
1012 } 1003 }
1013 } 1004 }
1014 1005
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 if ((isInstantiated && !enclosingClass.isNative()) 1113 if ((isInstantiated && !enclosingClass.isNative())
1123 || needsGetter 1114 || needsGetter
1124 || needsSetter) { 1115 || needsSetter) {
1125 String accessorName = isShadowed 1116 String accessorName = isShadowed
1126 ? namer.shadowedFieldName(member) 1117 ? namer.shadowedFieldName(member)
1127 : namer.getName(member); 1118 : namer.getName(member);
1128 String fieldName = member.hasFixedBackendName() 1119 String fieldName = member.hasFixedBackendName()
1129 ? member.fixedBackendName() 1120 ? member.fixedBackendName()
1130 : (isMixinNativeField ? member.name.slowToString() : accessorName); 1121 : (isMixinNativeField ? member.name.slowToString() : accessorName);
1131 bool needsCheckedSetter = false; 1122 bool needsCheckedSetter = false;
1132 if (needsSetter && compiler.enableTypeAssertions 1123 if (needsSetter) {
1133 && canGenerateCheckedSetter(member)) { 1124 if (compiler.enableTypeAssertions
1134 needsCheckedSetter = true; 1125 && canGenerateCheckedSetter(member)) {
1135 needsSetter = false; 1126 needsCheckedSetter = true;
1127 needsSetter = false;
1128 } else if (backend.isInterceptedMethod(member)) {
1129 // The [addField] will take care of generating the setter.
1130 needsSetter = false;
1131 }
1136 } 1132 }
1137 // Getters and setters with suffixes will be generated dynamically. 1133 // Getters and setters with suffixes will be generated dynamically.
1138 addField(member, 1134 addField(member,
1139 fieldName, 1135 fieldName,
1140 accessorName, 1136 accessorName,
1141 needsGetter, 1137 needsGetter,
1142 needsSetter, 1138 needsSetter,
1143 needsCheckedSetter); 1139 needsCheckedSetter);
1144 } 1140 }
1145 } 1141 }
(...skipping 17 matching lines...) Expand all
1163 // allowed on fields that are in [classElement] we don't need to visit 1159 // allowed on fields that are in [classElement] we don't need to visit
1164 // superclasses for non-instantiated classes. 1160 // superclasses for non-instantiated classes.
1165 classElement.implementation.forEachInstanceField( 1161 classElement.implementation.forEachInstanceField(
1166 visitField, 1162 visitField,
1167 includeBackendMembers: true, 1163 includeBackendMembers: true,
1168 includeSuperMembers: isInstantiated && !classElement.isNative()); 1164 includeSuperMembers: isInstantiated && !classElement.isNative());
1169 } 1165 }
1170 1166
1171 void generateGetter(Element member, String fieldName, String accessorName, 1167 void generateGetter(Element member, String fieldName, String accessorName,
1172 ClassBuilder builder) { 1168 ClassBuilder builder) {
1169 assert(!backend.isInterceptorClass(member));
1173 String getterName = namer.getterNameFromAccessorName(accessorName); 1170 String getterName = namer.getterNameFromAccessorName(accessorName);
1174 builder.addProperty(getterName, 1171 builder.addProperty(getterName,
1175 js.fun([], js.return_(js['this'][fieldName]))); 1172 js.fun([], js.return_(js['this'][fieldName])));
1176 } 1173 }
1177 1174
1178 void generateSetter(Element member, String fieldName, String accessorName, 1175 void generateSetter(Element member, String fieldName, String accessorName,
1179 ClassBuilder builder) { 1176 ClassBuilder builder) {
1177 assert(!backend.isInterceptorClass(member));
1180 String setterName = namer.setterNameFromAccessorName(accessorName); 1178 String setterName = namer.setterNameFromAccessorName(accessorName);
1179 List<String> args = backend.isInterceptedMethod(member)
1180 ? ['receiver', 'v']
1181 : ['v'];
1181 builder.addProperty(setterName, 1182 builder.addProperty(setterName,
1182 js.fun(['v'], js['this'][fieldName].assign('v'))); 1183 js.fun(args, js['this'][fieldName].assign('v')));
1183 } 1184 }
1184 1185
1185 bool canGenerateCheckedSetter(Element member) { 1186 bool canGenerateCheckedSetter(Element member) {
1186 DartType type = member.computeType(compiler); 1187 DartType type = member.computeType(compiler);
1187 if (type.element.isTypeVariable() 1188 if (type.element.isTypeVariable()
1188 || type.element == compiler.dynamicClass 1189 || type.element == compiler.dynamicClass
1189 || type.element == compiler.objectClass) { 1190 || type.element == compiler.objectClass) {
1190 // TODO(ngeoffray): Support type checks on type parameters. 1191 // TODO(ngeoffray): Support type checks on type parameters.
1191 return false; 1192 return false;
1192 } 1193 }
(...skipping 10 matching lines...) Expand all
1203 if (type.element.isErroneous()) return; 1204 if (type.element.isErroneous()) return;
1204 FunctionElement helperElement 1205 FunctionElement helperElement
1205 = backend.getCheckedModeHelper(type, typeCast: false); 1206 = backend.getCheckedModeHelper(type, typeCast: false);
1206 String helperName = namer.isolateAccess(helperElement); 1207 String helperName = namer.isolateAccess(helperElement);
1207 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; 1208 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']];
1208 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1209 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1209 arguments.add(js.string(namer.operatorIs(type.element))); 1210 arguments.add(js.string(namer.operatorIs(type.element)));
1210 } 1211 }
1211 1212
1212 String setterName = namer.setterNameFromAccessorName(accessorName); 1213 String setterName = namer.setterNameFromAccessorName(accessorName);
1214 List<String> args = backend.isInterceptedMethod(member)
1215 ? ['receiver', 'v']
1216 : ['v'];
1213 builder.addProperty(setterName, 1217 builder.addProperty(setterName,
1214 js.fun(['v'], js['this'][fieldName].assign(js[helperName](arguments)))); 1218 js.fun(args, js['this'][fieldName].assign(js[helperName](arguments))));
1215 } 1219 }
1216 1220
1217 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { 1221 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) {
1218 /* Do nothing. */ 1222 /* Do nothing. */
1219 } 1223 }
1220 1224
1221 void emitSuper(String superName, ClassBuilder builder) { 1225 void emitSuper(String superName, ClassBuilder builder) {
1222 /* Do nothing. */ 1226 /* Do nothing. */
1223 } 1227 }
1224 1228
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1296 assert(!needsSetter); 1300 assert(!needsSetter);
1297 generateCheckedSetter(member, name, accessorName, builder); 1301 generateCheckedSetter(member, name, accessorName, builder);
1298 } 1302 }
1299 if (!getterAndSetterCanBeImplementedByFieldSpec) { 1303 if (!getterAndSetterCanBeImplementedByFieldSpec) {
1300 if (needsGetter) { 1304 if (needsGetter) {
1301 generateGetter(member, name, accessorName, builder); 1305 generateGetter(member, name, accessorName, builder);
1302 } 1306 }
1303 if (needsSetter) { 1307 if (needsSetter) {
1304 generateSetter(member, name, accessorName, builder); 1308 generateSetter(member, name, accessorName, builder);
1305 } 1309 }
1310 } else if (backend.isInterceptedMethod(member)
1311 && instanceFieldNeedsSetter(member)) {
1312 generateSetter(member, name, accessorName, builder);
1306 } 1313 }
1307 }); 1314 });
1308 }); 1315 });
1309 } 1316 }
1310 1317
1311 /** 1318 /**
1312 * Documentation wanted -- johnniwinther 1319 * Documentation wanted -- johnniwinther
1313 * 1320 *
1314 * Invariant: [classElement] must be a declaration element. 1321 * Invariant: [classElement] must be a declaration element.
1315 */ 1322 */
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1355 return arity; 1362 return arity;
1356 } 1363 }
1357 1364
1358 int _compareSelectorNames(Selector selector1, Selector selector2) { 1365 int _compareSelectorNames(Selector selector1, Selector selector2) {
1359 String name1 = selector1.name.toString(); 1366 String name1 = selector1.name.toString();
1360 String name2 = selector2.name.toString(); 1367 String name2 = selector2.name.toString();
1361 if (name1 != name2) return Comparable.compare(name1, name2); 1368 if (name1 != name2) return Comparable.compare(name1, name2);
1362 return _selectorRank(selector1) - _selectorRank(selector2); 1369 return _selectorRank(selector1) - _selectorRank(selector2);
1363 } 1370 }
1364 1371
1365 void emitInterceptorMethods(ClassBuilder builder) {
1366 // Emit forwarders for the ObjectInterceptor class. We need to
1367 // emit all possible sends on intercepted methods. Because of
1368 // typed selectors we have to avoid generating the same forwarder
1369 // multiple times.
1370 Set<String> alreadyGenerated = new Set<String>();
1371 for (Selector selector in
1372 backend.usedInterceptors.toList()..sort(_compareSelectorNames)) {
1373 String name = backend.namer.invocationName(selector);
1374 if (alreadyGenerated.contains(name)) continue;
1375 alreadyGenerated.add(name);
1376
1377 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
1378 List<jsAst.Expression> arguments = <jsAst.Expression>[];
1379 parameters.add(new jsAst.Parameter('receiver'));
1380
1381 if (selector.isSetter()) {
1382 parameters.add(new jsAst.Parameter('value'));
1383 arguments.add(js['value']);
1384 } else {
1385 for (int i = 0; i < selector.argumentCount; i++) {
1386 String argName = 'a$i';
1387 parameters.add(new jsAst.Parameter(argName));
1388 arguments.add(js[argName]);
1389 }
1390 }
1391 jsAst.Fun function =
1392 js.fun(parameters, js.return_(js['receiver'][name](arguments)));
1393 builder.addProperty(name, function);
1394 }
1395 }
1396
1397 Iterable<Element> getTypedefChecksOn(DartType type) { 1372 Iterable<Element> getTypedefChecksOn(DartType type) {
1398 bool isSubtype(TypedefElement typedef) { 1373 bool isSubtype(TypedefElement typedef) {
1399 FunctionType typedefType = 1374 FunctionType typedefType =
1400 typedef.computeType(compiler).unalias(compiler); 1375 typedef.computeType(compiler).unalias(compiler);
1401 return compiler.types.isSubtype(type, typedefType); 1376 return compiler.types.isSubtype(type, typedefType);
1402 } 1377 }
1403 return checkedTypedefs.where(isSubtype).toList() 1378 return checkedTypedefs.where(isSubtype).toList()
1404 ..sort(Elements.compareByPosition); 1379 ..sort(Elements.compareByPosition);
1405 } 1380 }
1406 1381
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
1553 for (Constant constant in constants) { 1528 for (Constant constant in constants) {
1554 if (constant is ConstructedConstant) { 1529 if (constant is ConstructedConstant) {
1555 Element element = constant.computeType(compiler).element; 1530 Element element = constant.computeType(compiler).element;
1556 if (backend.isInterceptorClass(element)) { 1531 if (backend.isInterceptorClass(element)) {
1557 needed.add(element); 1532 needed.add(element);
1558 } 1533 }
1559 } 1534 }
1560 } 1535 }
1561 1536
1562 // Add unneeded interceptors to the [unneededClasses] set. 1537 // Add unneeded interceptors to the [unneededClasses] set.
1563 for (ClassElement interceptor in backend.interceptedClasses.keys) { 1538 for (ClassElement interceptor in backend.interceptedClasses) {
1564 if (!needed.contains(interceptor)) { 1539 if (!needed.contains(interceptor)
1540 && interceptor != compiler.objectClass) {
1565 unneededClasses.add(interceptor); 1541 unneededClasses.add(interceptor);
1566 } 1542 }
1567 } 1543 }
1568 1544
1569 return (ClassElement cls) => !unneededClasses.contains(cls); 1545 return (ClassElement cls) => !unneededClasses.contains(cls);
1570 } 1546 }
1571 1547
1572 void emitClosureClassIfNeeded(CodeBuffer buffer) { 1548 void emitClosureClassIfNeeded(CodeBuffer buffer) {
1573 // The closure class could have become necessary because of the generation 1549 // The closure class could have become necessary because of the generation
1574 // of stubs. 1550 // of stubs.
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
1704 // if they share methods with the same signature. Currently we do this only 1680 // if they share methods with the same signature. Currently we do this only
1705 // if there are no optional parameters. Closures with optional parameters 1681 // if there are no optional parameters. Closures with optional parameters
1706 // are more difficult to canonicalize because they would need to have the 1682 // are more difficult to canonicalize because they would need to have the
1707 // same default values. 1683 // same default values.
1708 1684
1709 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; 1685 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
1710 int parameterCount = member.parameterCount(compiler); 1686 int parameterCount = member.parameterCount(compiler);
1711 1687
1712 Map<int, String> cache; 1688 Map<int, String> cache;
1713 String extraArg = null; 1689 String extraArg = null;
1714 // Methods on interceptor classes take an extra parameter, which is the 1690 // Intercepted methods take an extra parameter, which is the
1715 // actual receiver of the call. 1691 // receiver of the call.
1716 bool inInterceptor = backend.isInterceptorClass(member.getEnclosingClass()); 1692 bool inInterceptor = backend.isInterceptedMethod(member);
1717 if (inInterceptor) { 1693 if (inInterceptor) {
1718 cache = interceptorClosureCache; 1694 cache = interceptorClosureCache;
1719 extraArg = 'receiver'; 1695 extraArg = 'receiver';
1720 } else { 1696 } else {
1721 cache = boundClosureCache; 1697 cache = boundClosureCache;
1722 } 1698 }
1723 List<String> fieldNames = compiler.enableMinification 1699 List<String> fieldNames = compiler.enableMinification
1724 ? inInterceptor ? const ['a', 'b', 'c'] 1700 ? inInterceptor ? const ['a', 'b', 'c']
1725 : const ['a', 'b'] 1701 : const ['a', 'b']
1726 : inInterceptor ? const ['self', 'target', 'receiver'] 1702 : inInterceptor ? const ['self', 'target', 'receiver']
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1827 /** 1803 /**
1828 * Documentation wanted -- johnniwinther 1804 * Documentation wanted -- johnniwinther
1829 * 1805 *
1830 * Invariant: [member] must be a declaration element. 1806 * Invariant: [member] must be a declaration element.
1831 */ 1807 */
1832 void emitCallStubForGetter(Element member, 1808 void emitCallStubForGetter(Element member,
1833 Set<Selector> selectors, 1809 Set<Selector> selectors,
1834 DefineStubFunction defineStub) { 1810 DefineStubFunction defineStub) {
1835 assert(invariant(member, member.isDeclaration)); 1811 assert(invariant(member, member.isDeclaration));
1836 LibraryElement memberLibrary = member.getLibrary(); 1812 LibraryElement memberLibrary = member.getLibrary();
1837 // If the class is an interceptor class, the stub gets the 1813 // If the method is intercepted, the stub gets the
1838 // receiver explicitely and we need to pass it to the getter call. 1814 // receiver explicitely and we need to pass it to the getter call.
1839 bool isInterceptorClass = 1815 bool isInterceptedMethod = backend.isInterceptedMethod(member);
1840 backend.isInterceptorClass(member.getEnclosingClass());
1841 1816
1842 const String receiverArgumentName = r'$receiver'; 1817 const String receiverArgumentName = r'$receiver';
1843 1818
1844 jsAst.Expression buildGetter() { 1819 jsAst.Expression buildGetter() {
1845 if (member.isGetter()) { 1820 if (member.isGetter()) {
1846 String getterName = namer.getterName(member); 1821 String getterName = namer.getterName(member);
1847 return js['this'][getterName]( 1822 return js['this'][getterName](
1848 isInterceptorClass 1823 isInterceptedMethod
1849 ? <jsAst.Expression>[js[receiverArgumentName]] 1824 ? <jsAst.Expression>[js[receiverArgumentName]]
1850 : <jsAst.Expression>[]); 1825 : <jsAst.Expression>[]);
1851 } else { 1826 } else {
1852 String fieldName = member.hasFixedBackendName() 1827 String fieldName = member.hasFixedBackendName()
1853 ? member.fixedBackendName() 1828 ? member.fixedBackendName()
1854 : namer.instanceFieldName(member); 1829 : namer.instanceFieldName(member);
1855 return js['this'][fieldName]; 1830 return js['this'][fieldName];
1856 } 1831 }
1857 } 1832 }
1858 1833
1859 // Two selectors may match but differ only in type. To avoid generating 1834 // Two selectors may match but differ only in type. To avoid generating
1860 // identical stubs for each we track untyped selectors which already have 1835 // identical stubs for each we track untyped selectors which already have
1861 // stubs. 1836 // stubs.
1862 Set<Selector> generatedSelectors = new Set<Selector>(); 1837 Set<Selector> generatedSelectors = new Set<Selector>();
1863 1838
1864 for (Selector selector in selectors) { 1839 for (Selector selector in selectors) {
1865 if (selector.applies(member, compiler)) { 1840 if (selector.applies(member, compiler)) {
1866 selector = selector.asUntyped; 1841 selector = selector.asUntyped;
1867 if (generatedSelectors.contains(selector)) continue; 1842 if (generatedSelectors.contains(selector)) continue;
1868 generatedSelectors.add(selector); 1843 generatedSelectors.add(selector);
1869 1844
1870 String invocationName = namer.invocationName(selector); 1845 String invocationName = namer.invocationName(selector);
1871 Selector callSelector = new Selector.callClosureFrom(selector); 1846 Selector callSelector = new Selector.callClosureFrom(selector);
1872 String closureCallName = namer.invocationName(callSelector); 1847 String closureCallName = namer.invocationName(callSelector);
1873 1848
1874 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 1849 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
1875 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 1850 List<jsAst.Expression> arguments = <jsAst.Expression>[];
1876 if (isInterceptorClass) { 1851 if (isInterceptedMethod) {
1877 parameters.add(new jsAst.Parameter(receiverArgumentName)); 1852 parameters.add(new jsAst.Parameter(receiverArgumentName));
1878 } 1853 }
1879 1854
1880 for (int i = 0; i < selector.argumentCount; i++) { 1855 for (int i = 0; i < selector.argumentCount; i++) {
1881 String name = 'arg$i'; 1856 String name = 'arg$i';
1882 parameters.add(new jsAst.Parameter(name)); 1857 parameters.add(new jsAst.Parameter(name));
1883 arguments.add(js[name]); 1858 arguments.add(js[name]);
1884 } 1859 }
1885 1860
1886 jsAst.Fun function = js.fun( 1861 jsAst.Fun function = js.fun(
1887 parameters, 1862 parameters,
1888 js.return_(buildGetter()[closureCallName](arguments))); 1863 js.return_(buildGetter()[closureCallName](arguments)));
1889 1864
1890 defineStub(invocationName, function); 1865 defineStub(invocationName, function);
1891 } 1866 }
1892 } 1867 }
1893 } 1868 }
1894 1869
1895 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { 1870 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) {
1896 ConstantHandler handler = compiler.constantHandler; 1871 ConstantHandler handler = compiler.constantHandler;
1897 Iterable<VariableElement> staticNonFinalFields = 1872 Iterable<VariableElement> staticNonFinalFields =
1898 handler.getStaticNonFinalFieldsForEmission(); 1873 handler.getStaticNonFinalFieldsForEmission();
1899 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { 1874 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
1875 // [:interceptedNames:] is handled in [emitInterceptedNames].
1876 if (element == backend.interceptedNames) continue;
1900 compiler.withCurrentElement(element, () { 1877 compiler.withCurrentElement(element, () {
1901 Constant initialValue = handler.getInitialValueFor(element); 1878 Constant initialValue = handler.getInitialValueFor(element);
1902 jsAst.Expression init = 1879 jsAst.Expression init =
1903 js[isolateProperties][namer.getName(element)].assign( 1880 js[isolateProperties][namer.getName(element)].assign(
1904 constantEmitter.referenceInInitializationContext(initialValue)); 1881 constantEmitter.referenceInInitializationContext(initialValue));
1905 buffer.add(jsAst.prettyPrint(init, compiler)); 1882 buffer.add(jsAst.prettyPrint(init, compiler));
1906 buffer.add('$N'); 1883 buffer.add('$N');
1907 }); 1884 });
1908 } 1885 }
1909 } 1886 }
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
2028 2005
2029 List<jsAst.Expression> argNames = 2006 List<jsAst.Expression> argNames =
2030 selector.getOrderedNamedArguments().map((SourceString name) => 2007 selector.getOrderedNamedArguments().map((SourceString name) =>
2031 js.string(name.slowToString())).toList(); 2008 js.string(name.slowToString())).toList();
2032 2009
2033 String internalName = namer.invocationMirrorInternalName(selector); 2010 String internalName = namer.invocationMirrorInternalName(selector);
2034 2011
2035 String createInvocationMirror = namer.getName( 2012 String createInvocationMirror = namer.getName(
2036 compiler.createInvocationMirrorElement); 2013 compiler.createInvocationMirrorElement);
2037 2014
2015 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
2038 jsAst.Expression expression = js['this.$noSuchMethodName']( 2016 jsAst.Expression expression = js['this.$noSuchMethodName'](
2039 js[namer.CURRENT_ISOLATE][createInvocationMirror]([ 2017 [js['this'],
2040 js.string(methodName), 2018 js[namer.CURRENT_ISOLATE][createInvocationMirror]([
2041 js.string(internalName), 2019 js.string(methodName),
2042 type, 2020 js.string(internalName),
2043 new jsAst.ArrayInitializer.from( 2021 type,
2044 parameters.map((param) => js[param.name]).toList()), 2022 new jsAst.ArrayInitializer.from(
2045 new jsAst.ArrayInitializer.from(argNames)])); 2023 parameters.map((param) => js[param.name]).toList()),
2024 new jsAst.ArrayInitializer.from(argNames)])]);
2025 parameters = backend.isInterceptedName(selector.name)
2026 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters))
2027 : parameters;
2046 return js.fun(parameters, js.return_(expression)); 2028 return js.fun(parameters, js.return_(expression));
2047 } 2029 }
2048 2030
2049 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { 2031 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
2050 // Cache the object class and type. 2032 // Cache the object class and type.
2051 ClassElement objectClass = compiler.objectClass; 2033 ClassElement objectClass = compiler.objectClass;
2052 DartType objectType = objectClass.computeType(compiler); 2034 DartType objectType = objectClass.computeType(compiler);
2053 2035
2054 for (Selector selector in selectors) { 2036 for (Selector selector in selectors) {
2055 // Introduce a helper function that determines if the given 2037 // Introduce a helper function that determines if the given
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
2176 dartMainRunner(function() { ${mainCall}; }); 2158 dartMainRunner(function() { ${mainCall}; });
2177 } else { 2159 } else {
2178 ${mainCall}; 2160 ${mainCall};
2179 } 2161 }
2180 } 2162 }
2181 """); 2163 """);
2182 addComment('END invoke [main].', buffer); 2164 addComment('END invoke [main].', buffer);
2183 } 2165 }
2184 2166
2185 void emitGetInterceptorMethod(CodeBuffer buffer, 2167 void emitGetInterceptorMethod(CodeBuffer buffer,
2186 String objectName,
2187 String key, 2168 String key,
2188 Collection<ClassElement> classes) { 2169 Collection<ClassElement> classes) {
2189 jsAst.Statement buildReturnInterceptor(ClassElement cls) { 2170 jsAst.Statement buildReturnInterceptor(ClassElement cls) {
2190 return js.return_(js[namer.isolateAccess(cls)]['prototype']); 2171 return js.return_(js[namer.isolateAccess(cls)]['prototype']);
2191 } 2172 }
2192 2173
2193 jsAst.VariableUse receiver = js['receiver']; 2174 jsAst.VariableUse receiver = js['receiver'];
2194 /** 2175 /**
2195 * Build a JavaScrit AST node for doing a type check on 2176 * Build a JavaScrit AST node for doing a type check on
2196 * [cls]. [cls] must be an interceptor class. 2177 * [cls]. [cls] must be an interceptor class.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2228 bool hasString = false; 2209 bool hasString = false;
2229 for (ClassElement cls in classes) { 2210 for (ClassElement cls in classes) {
2230 if (cls == backend.jsArrayClass) hasArray = true; 2211 if (cls == backend.jsArrayClass) hasArray = true;
2231 else if (cls == backend.jsBoolClass) hasBool = true; 2212 else if (cls == backend.jsBoolClass) hasBool = true;
2232 else if (cls == backend.jsDoubleClass) hasDouble = true; 2213 else if (cls == backend.jsDoubleClass) hasDouble = true;
2233 else if (cls == backend.jsFunctionClass) hasFunction = true; 2214 else if (cls == backend.jsFunctionClass) hasFunction = true;
2234 else if (cls == backend.jsIntClass) hasInt = true; 2215 else if (cls == backend.jsIntClass) hasInt = true;
2235 else if (cls == backend.jsNullClass) hasNull = true; 2216 else if (cls == backend.jsNullClass) hasNull = true;
2236 else if (cls == backend.jsNumberClass) hasNumber = true; 2217 else if (cls == backend.jsNumberClass) hasNumber = true;
2237 else if (cls == backend.jsStringClass) hasString = true; 2218 else if (cls == backend.jsStringClass) hasString = true;
2238 else throw 'Internal error: $cls'; 2219 else {
2220 assert(cls == compiler.objectClass);
2221 }
2239 } 2222 }
2240 if (hasDouble) { 2223 if (hasDouble) {
2241 assert(!hasNumber);
2242 hasNumber = true; 2224 hasNumber = true;
2243 } 2225 }
2244 if (hasInt) hasNumber = true; 2226 if (hasInt) hasNumber = true;
2245 2227
2246 jsAst.Block block = new jsAst.Block.empty(); 2228 jsAst.Block block = new jsAst.Block.empty();
2247 2229
2248 if (hasNumber) { 2230 if (hasNumber) {
2249 jsAst.Statement whenNumber; 2231 jsAst.Statement whenNumber;
2250 2232
2251 /// Note: there are two number classes in play: Dart's [num], 2233 /// Note: there are two number classes in play: Dart's [num],
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2284 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass)); 2266 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass));
2285 } 2267 }
2286 if (hasBool) { 2268 if (hasBool) {
2287 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); 2269 block.statements.add(buildInterceptorCheck(backend.jsBoolClass));
2288 } 2270 }
2289 // TODO(ahe): It might be faster to check for Array before 2271 // TODO(ahe): It might be faster to check for Array before
2290 // function and bool. 2272 // function and bool.
2291 if (hasArray) { 2273 if (hasArray) {
2292 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); 2274 block.statements.add(buildInterceptorCheck(backend.jsArrayClass));
2293 } 2275 }
2294 block.statements.add(js.return_(js[objectName]['prototype'])); 2276 block.statements.add(js.return_(receiver));
2295 2277
2296 buffer.add(jsAst.prettyPrint( 2278 buffer.add(jsAst.prettyPrint(
2297 js[isolateProperties][key].assign(js.fun(['receiver'], block)), 2279 js[isolateProperties][key].assign(js.fun(['receiver'], block)),
2298 compiler)); 2280 compiler));
2299 buffer.add(N); 2281 buffer.add(N);
2300 } 2282 }
2301 2283
2302 /** 2284 /**
2303 * Emit all versions of the [:getInterceptor:] method. 2285 * Emit all versions of the [:getInterceptor:] method.
2304 */ 2286 */
2305 void emitGetInterceptorMethods(CodeBuffer buffer) { 2287 void emitGetInterceptorMethods(CodeBuffer buffer) {
2306 // If no class needs to be intercepted, just return.
2307 if (backend.objectInterceptorClass == null) return;
2308 String objectName = namer.isolateAccess(backend.objectInterceptorClass);
2309 var specializedGetInterceptors = backend.specializedGetInterceptors; 2288 var specializedGetInterceptors = backend.specializedGetInterceptors;
2310 for (String name in specializedGetInterceptors.keys.toList()..sort()) { 2289 for (String name in specializedGetInterceptors.keys.toList()..sort()) {
2311 Collection<ClassElement> classes = specializedGetInterceptors[name]; 2290 Collection<ClassElement> classes = specializedGetInterceptors[name];
2312 emitGetInterceptorMethod(buffer, objectName, name, classes); 2291 emitGetInterceptorMethod(buffer, name, classes);
2313 } 2292 }
2314 } 2293 }
2315 2294
2316 /** 2295 /**
2317 * Compute all the classes that must be emitted. 2296 * Compute all the classes that must be emitted.
2318 */ 2297 */
2319 void computeNeededClasses() { 2298 void computeNeededClasses() {
2320 instantiatedClasses = 2299 instantiatedClasses =
2321 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) 2300 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
2322 .toSet(); 2301 .toSet();
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
2528 } 2507 }
2529 return null; 2508 return null;
2530 } 2509 }
2531 2510
2532 void emitOneShotInterceptors(CodeBuffer buffer) { 2511 void emitOneShotInterceptors(CodeBuffer buffer) {
2533 List<String> names = backend.oneShotInterceptors.keys.toList(); 2512 List<String> names = backend.oneShotInterceptors.keys.toList();
2534 names.sort(); 2513 names.sort();
2535 for (String name in names) { 2514 for (String name in names) {
2536 Selector selector = backend.oneShotInterceptors[name]; 2515 Selector selector = backend.oneShotInterceptors[name];
2537 Set<ClassElement> classes = 2516 Set<ClassElement> classes =
2538 backend.getInterceptedClassesOn(selector); 2517 backend.getInterceptedClassesOn(selector.name);
2539 String getInterceptorName = 2518 String getInterceptorName =
2540 namer.getInterceptorName(backend.getInterceptorMethod, classes); 2519 namer.getInterceptorName(backend.getInterceptorMethod, classes);
2541 2520
2542 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 2521 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
2543 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2522 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2544 parameters.add(new jsAst.Parameter('receiver')); 2523 parameters.add(new jsAst.Parameter('receiver'));
2545 arguments.add(js['receiver']); 2524 arguments.add(js['receiver']);
2546 2525
2547 if (selector.isSetter()) { 2526 if (selector.isSetter()) {
2548 parameters.add(new jsAst.Parameter('value')); 2527 parameters.add(new jsAst.Parameter('value'));
(...skipping 21 matching lines...) Expand all
2570 jsAst.Fun function = js.fun(parameters, body); 2549 jsAst.Fun function = js.fun(parameters, body);
2571 2550
2572 jsAst.PropertyAccess property = 2551 jsAst.PropertyAccess property =
2573 js[isolateProperties][name]; 2552 js[isolateProperties][name];
2574 2553
2575 buffer.add(jsAst.prettyPrint(property.assign(function), compiler)); 2554 buffer.add(jsAst.prettyPrint(property.assign(function), compiler));
2576 buffer.add(N); 2555 buffer.add(N);
2577 } 2556 }
2578 } 2557 }
2579 2558
2559 /**
2560 * If [:invokeOn:] has been compiled, emit all the possible selector names
2561 * that are intercepted into the [:interceptedNames:] top-level
2562 * variable. The implementation of [:invokeOn:] will use it to
2563 * determine whether it should call the method with an extra
2564 * parameter.
2565 */
2566 void emitInterceptedNames(CodeBuffer buffer) {
2567 if (!compiler.enabledInvokeOn) return;
2568 String name = backend.namer.getName(backend.interceptedNames);
2569 jsAst.PropertyAccess property = js[isolateProperties][name];
2570
2571 int index = 0;
2572 List<jsAst.ArrayElement> elements = backend.usedInterceptors.map(
2573 (Selector selector) {
2574 jsAst.Literal str = js.string(namer.invocationName(selector));
2575 return new jsAst.ArrayElement(index++, str);
2576 }).toList();
2577 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(
2578 backend.usedInterceptors.length,
2579 elements);
2580
2581 buffer.add(jsAst.prettyPrint(property.assign(array), compiler));
2582 buffer.add(N);
2583 }
2584
2580 void emitInitFunction(CodeBuffer buffer) { 2585 void emitInitFunction(CodeBuffer buffer) {
2581 jsAst.Fun fun = js.fun([], [ 2586 jsAst.Fun fun = js.fun([], [
2582 js['$isolateProperties = {}'], 2587 js['$isolateProperties = {}'],
2583 ] 2588 ]
2584 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) 2589 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary())
2585 ..addAll(buildLazyInitializerFunctionIfNecessary()) 2590 ..addAll(buildLazyInitializerFunctionIfNecessary())
2586 ..addAll(buildFinishIsolateConstructor()) 2591 ..addAll(buildFinishIsolateConstructor())
2587 ); 2592 );
2588 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( 2593 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
2589 new jsAst.VariableDeclaration('init'), fun); 2594 new jsAst.VariableDeclaration('init'), fun);
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
2671 2676
2672 emitStaticFunctions(mainBuffer); 2677 emitStaticFunctions(mainBuffer);
2673 emitStaticFunctionGetters(mainBuffer); 2678 emitStaticFunctionGetters(mainBuffer);
2674 2679
2675 emitRuntimeTypeSupport(mainBuffer); 2680 emitRuntimeTypeSupport(mainBuffer);
2676 emitCompileTimeConstants(mainBuffer); 2681 emitCompileTimeConstants(mainBuffer);
2677 // Static field initializations require the classes and compile-time 2682 // Static field initializations require the classes and compile-time
2678 // constants to be set up. 2683 // constants to be set up.
2679 emitStaticNonFinalFieldInitializations(mainBuffer); 2684 emitStaticNonFinalFieldInitializations(mainBuffer);
2680 emitOneShotInterceptors(mainBuffer); 2685 emitOneShotInterceptors(mainBuffer);
2686 emitInterceptedNames(mainBuffer);
2681 emitGetInterceptorMethods(mainBuffer); 2687 emitGetInterceptorMethods(mainBuffer);
2682 emitLazilyInitializedStaticFields(mainBuffer); 2688 emitLazilyInitializedStaticFields(mainBuffer);
2683 2689
2684 isolateProperties = isolatePropertiesName; 2690 isolateProperties = isolatePropertiesName;
2685 // The following code should not use the short-hand for the 2691 // The following code should not use the short-hand for the
2686 // initialStatics. 2692 // initialStatics.
2687 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N'); 2693 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N');
2688 2694
2689 emitFinishIsolateConstructorInvocation(mainBuffer); 2695 emitFinishIsolateConstructorInvocation(mainBuffer);
2690 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=' 2696 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_='
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
2771 """; 2777 """;
2772 const String HOOKS_API_USAGE = """ 2778 const String HOOKS_API_USAGE = """
2773 // The code supports the following hooks: 2779 // The code supports the following hooks:
2774 // dartPrint(message) - if this function is defined it is called 2780 // dartPrint(message) - if this function is defined it is called
2775 // instead of the Dart [print] method. 2781 // instead of the Dart [print] method.
2776 // dartMainRunner(main) - if this function is defined, the Dart [main] 2782 // dartMainRunner(main) - if this function is defined, the Dart [main]
2777 // method will not be invoked directly. 2783 // method will not be invoked directly.
2778 // Instead, a closure that will invoke [main] is 2784 // Instead, a closure that will invoke [main] is
2779 // passed to [dartMainRunner]. 2785 // passed to [dartMainRunner].
2780 """; 2786 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698