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

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 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 // hit the method directly. 630 // hit the method directly.
631 return; 631 return;
632 } 632 }
633 ConstantHandler handler = compiler.constantHandler; 633 ConstantHandler handler = compiler.constantHandler;
634 List<SourceString> names = selector.getOrderedNamedArguments(); 634 List<SourceString> names = selector.getOrderedNamedArguments();
635 635
636 String invocationName = namer.invocationName(selector); 636 String invocationName = namer.invocationName(selector);
637 if (alreadyGenerated.contains(invocationName)) return; 637 if (alreadyGenerated.contains(invocationName)) return;
638 alreadyGenerated.add(invocationName); 638 alreadyGenerated.add(invocationName);
639 639
640 bool isInterceptorClass = 640 bool isInterceptedMethod = backend.isInterceptedMethod(member);
641 backend.isInterceptorClass(member.getEnclosingClass());
642 641
643 // If the method is in an interceptor class, we need to also pass 642 // If the method is intercepted, we need to also pass
644 // the actual receiver. 643 // the actual receiver.
645 int extraArgumentCount = isInterceptorClass ? 1 : 0; 644 int extraArgumentCount = isInterceptedMethod ? 1 : 0;
646 // Use '$receiver' to avoid clashes with other parameter names. Using 645 // Use '$receiver' to avoid clashes with other parameter names. Using
647 // '$receiver' works because [:namer.safeName:] used for getting parameter 646 // '$receiver' works because [:namer.safeName:] used for getting parameter
648 // names never returns a name beginning with a single '$'. 647 // names never returns a name beginning with a single '$'.
649 String receiverArgumentName = r'$receiver'; 648 String receiverArgumentName = r'$receiver';
650 649
651 // The parameters that this stub takes. 650 // The parameters that this stub takes.
652 List<jsAst.Parameter> parametersBuffer = 651 List<jsAst.Parameter> parametersBuffer =
653 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount); 652 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount);
654 // The arguments that will be passed to the real method. 653 // The arguments that will be passed to the real method.
655 List<jsAst.Expression> argumentsBuffer = 654 List<jsAst.Expression> argumentsBuffer =
656 new List<jsAst.Expression>( 655 new List<jsAst.Expression>(
657 parameters.parameterCount + extraArgumentCount); 656 parameters.parameterCount + extraArgumentCount);
658 657
659 int count = 0; 658 int count = 0;
660 if (isInterceptorClass) { 659 if (isInterceptedMethod) {
661 count++; 660 count++;
662 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName); 661 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
663 argumentsBuffer[0] = js[receiverArgumentName]; 662 argumentsBuffer[0] = js[receiverArgumentName];
664 } 663 }
665 664
666 int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1; 665 int indexOfLastOptionalArgumentInParameters = positionalArgumentCount - 1;
667 TreeElements elements = 666 TreeElements elements =
668 compiler.enqueuer.resolution.getCachedElements(member); 667 compiler.enqueuer.resolution.getCachedElements(member);
669 668
670 parameters.orderedForEachParameter((Element element) { 669 parameters.orderedForEachParameter((Element element) {
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
890 } 889 }
891 890
892 /** 891 /**
893 * Documentation wanted -- johnniwinther 892 * Documentation wanted -- johnniwinther
894 * 893 *
895 * Invariant: [classElement] must be a declaration element. 894 * Invariant: [classElement] must be a declaration element.
896 */ 895 */
897 void emitInstanceMembers(ClassElement classElement, 896 void emitInstanceMembers(ClassElement classElement,
898 ClassBuilder builder) { 897 ClassBuilder builder) {
899 assert(invariant(classElement, classElement.isDeclaration)); 898 assert(invariant(classElement, classElement.isDeclaration));
900 if (classElement == backend.objectInterceptorClass) {
901 emitInterceptorMethods(builder);
902 // The ObjectInterceptor does not have any instance methods.
903 return;
904 }
905 899
906 void visitMember(ClassElement enclosing, Element member) { 900 void visitMember(ClassElement enclosing, Element member) {
907 assert(invariant(classElement, member.isDeclaration)); 901 assert(invariant(classElement, member.isDeclaration));
908 if (member.isInstanceMember()) { 902 if (member.isInstanceMember()) {
909 addInstanceMember(member, builder); 903 addInstanceMember(member, builder);
910 } 904 }
911 } 905 }
912 906
913 // TODO(kasperl): We should make sure to only emit one version of 907 // TODO(kasperl): We should make sure to only emit one version of
914 // overridden methods. Right now, we rely on the ordering so the 908 // overridden methods. Right now, we rely on the ordering so the
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 && compiler.enabledNoSuchMethod) { 963 && compiler.enabledNoSuchMethod) {
970 // Emit the noSuchMethod handlers on the Object prototype now, 964 // Emit the noSuchMethod handlers on the Object prototype now,
971 // so that the code in the dynamicFunction helper can find 965 // so that the code in the dynamicFunction helper can find
972 // them. Note that this helper is invoked before analyzing the 966 // them. Note that this helper is invoked before analyzing the
973 // full JS script. 967 // full JS script.
974 if (!nativeEmitter.handleNoSuchMethod) { 968 if (!nativeEmitter.handleNoSuchMethod) {
975 emitNoSuchMethodHandlers(builder.addProperty); 969 emitNoSuchMethodHandlers(builder.addProperty);
976 } 970 }
977 } 971 }
978 972
979 if (backend.isInterceptorClass(classElement)) { 973 if (backend.isInterceptorClass(classElement)
980 // The operator== method in [:Object:] does not take the same 974 && classElement != compiler.objectClass) {
981 // number of arguments as an intercepted method, therefore we 975 // We optimize the operator== on interceptor classes to
982 // explicitely add one to all interceptor classes. Note that we 976 // just do a JavaScript double or triple equals.
983 // would not have do do that if all intercepted methods had
984 // a calling convention where the receiver is the first
985 // parameter.
986 String name = backend.namer.publicInstanceMethodNameByArity( 977 String name = backend.namer.publicInstanceMethodNameByArity(
987 const SourceString('=='), 1); 978 const SourceString('=='), 1);
988 Function kind = (classElement == backend.jsNullClass) 979 Function kind = (classElement == backend.jsNullClass)
989 ? js.equals 980 ? js.equals
990 : js.strictEquals; 981 : js.strictEquals;
991 builder.addProperty(name, js.fun(['receiver', 'a'], 982 builder.addProperty(name, js.fun(['receiver', 'a'],
992 js.block(js.return_(kind(js['receiver'], js['a']))))); 983 js.block(js.return_(kind(js['receiver'], js['a'])))));
993 } 984 }
994 } 985 }
995 986
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 if ((isInstantiated && !enclosingClass.isNative()) 1091 if ((isInstantiated && !enclosingClass.isNative())
1101 || needsGetter 1092 || needsGetter
1102 || needsSetter) { 1093 || needsSetter) {
1103 String accessorName = isShadowed 1094 String accessorName = isShadowed
1104 ? namer.shadowedFieldName(member) 1095 ? namer.shadowedFieldName(member)
1105 : namer.getName(member); 1096 : namer.getName(member);
1106 String fieldName = member.hasFixedBackendName() 1097 String fieldName = member.hasFixedBackendName()
1107 ? member.fixedBackendName() 1098 ? member.fixedBackendName()
1108 : (isMixinNativeField ? member.name.slowToString() : accessorName); 1099 : (isMixinNativeField ? member.name.slowToString() : accessorName);
1109 bool needsCheckedSetter = false; 1100 bool needsCheckedSetter = false;
1110 if (needsSetter && compiler.enableTypeAssertions 1101 if (needsSetter) {
1111 && canGenerateCheckedSetter(member)) { 1102 if (compiler.enableTypeAssertions
1112 needsCheckedSetter = true; 1103 && canGenerateCheckedSetter(member)) {
1113 needsSetter = false; 1104 needsCheckedSetter = true;
1105 needsSetter = false;
1106 } else if (backend.isInterceptedMethod(member)) {
1107 // The [addField] will take care of generating the setter.
1108 needsSetter = false;
1109 }
1114 } 1110 }
1115 // Getters and setters with suffixes will be generated dynamically. 1111 // Getters and setters with suffixes will be generated dynamically.
1116 addField(member, 1112 addField(member,
1117 fieldName, 1113 fieldName,
1118 accessorName, 1114 accessorName,
1119 needsGetter, 1115 needsGetter,
1120 needsSetter, 1116 needsSetter,
1121 needsCheckedSetter); 1117 needsCheckedSetter);
1122 } 1118 }
1123 } 1119 }
(...skipping 17 matching lines...) Expand all
1141 // allowed on fields that are in [classElement] we don't need to visit 1137 // allowed on fields that are in [classElement] we don't need to visit
1142 // superclasses for non-instantiated classes. 1138 // superclasses for non-instantiated classes.
1143 classElement.implementation.forEachInstanceField( 1139 classElement.implementation.forEachInstanceField(
1144 visitField, 1140 visitField,
1145 includeBackendMembers: true, 1141 includeBackendMembers: true,
1146 includeSuperMembers: isInstantiated && !classElement.isNative()); 1142 includeSuperMembers: isInstantiated && !classElement.isNative());
1147 } 1143 }
1148 1144
1149 void generateGetter(Element member, String fieldName, String accessorName, 1145 void generateGetter(Element member, String fieldName, String accessorName,
1150 ClassBuilder builder) { 1146 ClassBuilder builder) {
1147 assert(!backend.isInterceptorClass(member));
1151 String getterName = namer.getterNameFromAccessorName(accessorName); 1148 String getterName = namer.getterNameFromAccessorName(accessorName);
1152 builder.addProperty(getterName, 1149 builder.addProperty(getterName,
1153 js.fun([], js.return_(js['this'][fieldName]))); 1150 js.fun([], js.return_(js['this'][fieldName])));
1154 } 1151 }
1155 1152
1156 void generateSetter(Element member, String fieldName, String accessorName, 1153 void generateSetter(Element member, String fieldName, String accessorName,
1157 ClassBuilder builder) { 1154 ClassBuilder builder) {
1155 assert(!backend.isInterceptorClass(member));
1158 String setterName = namer.setterNameFromAccessorName(accessorName); 1156 String setterName = namer.setterNameFromAccessorName(accessorName);
1157 List<String> args = backend.isInterceptedMethod(member)
1158 ? ['receiver', 'v']
1159 : ['v'];
1159 builder.addProperty(setterName, 1160 builder.addProperty(setterName,
1160 js.fun(['v'], js['this'][fieldName].assign('v'))); 1161 js.fun(args, js['this'][fieldName].assign('v')));
1161 } 1162 }
1162 1163
1163 bool canGenerateCheckedSetter(Element member) { 1164 bool canGenerateCheckedSetter(Element member) {
1164 DartType type = member.computeType(compiler); 1165 DartType type = member.computeType(compiler);
1165 if (type.element.isTypeVariable() 1166 if (type.element.isTypeVariable()
1166 || type.element == compiler.dynamicClass 1167 || type.element == compiler.dynamicClass
1167 || type.element == compiler.objectClass) { 1168 || type.element == compiler.objectClass) {
1168 // TODO(ngeoffray): Support type checks on type parameters. 1169 // TODO(ngeoffray): Support type checks on type parameters.
1169 return false; 1170 return false;
1170 } 1171 }
(...skipping 10 matching lines...) Expand all
1181 if (type.element.isErroneous()) return; 1182 if (type.element.isErroneous()) return;
1182 FunctionElement helperElement 1183 FunctionElement helperElement
1183 = backend.getCheckedModeHelper(type, typeCast: false); 1184 = backend.getCheckedModeHelper(type, typeCast: false);
1184 String helperName = namer.isolateAccess(helperElement); 1185 String helperName = namer.isolateAccess(helperElement);
1185 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']]; 1186 List<jsAst.Expression> arguments = <jsAst.Expression>[js['v']];
1186 if (helperElement.computeSignature(compiler).parameterCount != 1) { 1187 if (helperElement.computeSignature(compiler).parameterCount != 1) {
1187 arguments.add(js.string(namer.operatorIs(type.element))); 1188 arguments.add(js.string(namer.operatorIs(type.element)));
1188 } 1189 }
1189 1190
1190 String setterName = namer.setterNameFromAccessorName(accessorName); 1191 String setterName = namer.setterNameFromAccessorName(accessorName);
1192 List<String> args = backend.isInterceptedMethod(member)
1193 ? ['receiver', 'v']
1194 : ['v'];
1191 builder.addProperty(setterName, 1195 builder.addProperty(setterName,
1192 js.fun(['v'], js['this'][fieldName].assign(js[helperName](arguments)))); 1196 js.fun(args, js['this'][fieldName].assign(js[helperName](arguments))));
1193 } 1197 }
1194 1198
1195 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { 1199 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) {
1196 /* Do nothing. */ 1200 /* Do nothing. */
1197 } 1201 }
1198 1202
1199 void emitSuper(String superName, ClassBuilder builder) { 1203 void emitSuper(String superName, ClassBuilder builder) {
1200 /* Do nothing. */ 1204 /* Do nothing. */
1201 } 1205 }
1202 1206
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
1274 assert(!needsSetter); 1278 assert(!needsSetter);
1275 generateCheckedSetter(member, name, accessorName, builder); 1279 generateCheckedSetter(member, name, accessorName, builder);
1276 } 1280 }
1277 if (!getterAndSetterCanBeImplementedByFieldSpec) { 1281 if (!getterAndSetterCanBeImplementedByFieldSpec) {
1278 if (needsGetter) { 1282 if (needsGetter) {
1279 generateGetter(member, name, accessorName, builder); 1283 generateGetter(member, name, accessorName, builder);
1280 } 1284 }
1281 if (needsSetter) { 1285 if (needsSetter) {
1282 generateSetter(member, name, accessorName, builder); 1286 generateSetter(member, name, accessorName, builder);
1283 } 1287 }
1288 } else if (backend.isInterceptedMethod(member)
1289 && instanceFieldNeedsSetter(member)) {
1290 generateSetter(member, name, accessorName, builder);
1284 } 1291 }
1285 }); 1292 });
1286 }); 1293 });
1287 } 1294 }
1288 1295
1289 /** 1296 /**
1290 * Documentation wanted -- johnniwinther 1297 * Documentation wanted -- johnniwinther
1291 * 1298 *
1292 * Invariant: [classElement] must be a declaration element. 1299 * Invariant: [classElement] must be a declaration element.
1293 */ 1300 */
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1336 return arity; 1343 return arity;
1337 } 1344 }
1338 1345
1339 int _compareSelectorNames(Selector selector1, Selector selector2) { 1346 int _compareSelectorNames(Selector selector1, Selector selector2) {
1340 String name1 = selector1.name.toString(); 1347 String name1 = selector1.name.toString();
1341 String name2 = selector2.name.toString(); 1348 String name2 = selector2.name.toString();
1342 if (name1 != name2) return Comparable.compare(name1, name2); 1349 if (name1 != name2) return Comparable.compare(name1, name2);
1343 return _selectorRank(selector1) - _selectorRank(selector2); 1350 return _selectorRank(selector1) - _selectorRank(selector2);
1344 } 1351 }
1345 1352
1346 void emitInterceptorMethods(ClassBuilder builder) {
1347 // Emit forwarders for the ObjectInterceptor class. We need to
1348 // emit all possible sends on intercepted methods. Because of
1349 // typed selectors we have to avoid generating the same forwarder
1350 // multiple times.
1351 Set<String> alreadyGenerated = new Set<String>();
1352 for (Selector selector in
1353 backend.usedInterceptors.toList()..sort(_compareSelectorNames)) {
1354 String name = backend.namer.invocationName(selector);
1355 if (alreadyGenerated.contains(name)) continue;
1356 alreadyGenerated.add(name);
1357
1358 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
1359 List<jsAst.Expression> arguments = <jsAst.Expression>[];
1360 parameters.add(new jsAst.Parameter('receiver'));
1361
1362 if (selector.isSetter()) {
1363 parameters.add(new jsAst.Parameter('value'));
1364 arguments.add(js['value']);
1365 } else {
1366 for (int i = 0; i < selector.argumentCount; i++) {
1367 String argName = 'a$i';
1368 parameters.add(new jsAst.Parameter(argName));
1369 arguments.add(js[argName]);
1370 }
1371 }
1372 jsAst.Fun function =
1373 js.fun(parameters, js.return_(js['receiver'][name](arguments)));
1374 builder.addProperty(name, function);
1375 }
1376 }
1377
1378 Iterable<Element> getTypedefChecksOn(DartType type) { 1353 Iterable<Element> getTypedefChecksOn(DartType type) {
1379 bool isSubtype(TypedefElement typedef) { 1354 bool isSubtype(TypedefElement typedef) {
1380 FunctionType typedefType = 1355 FunctionType typedefType =
1381 typedef.computeType(compiler).unalias(compiler); 1356 typedef.computeType(compiler).unalias(compiler);
1382 return compiler.types.isSubtype(type, typedefType); 1357 return compiler.types.isSubtype(type, typedefType);
1383 } 1358 }
1384 return checkedTypedefs.where(isSubtype).toList() 1359 return checkedTypedefs.where(isSubtype).toList()
1385 ..sort(Elements.compareByPosition); 1360 ..sort(Elements.compareByPosition);
1386 } 1361 }
1387 1362
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1529 for (Constant constant in constants) { 1504 for (Constant constant in constants) {
1530 if (constant is ConstructedConstant) { 1505 if (constant is ConstructedConstant) {
1531 Element element = constant.computeType(compiler).element; 1506 Element element = constant.computeType(compiler).element;
1532 if (backend.isInterceptorClass(element)) { 1507 if (backend.isInterceptorClass(element)) {
1533 needed.add(element); 1508 needed.add(element);
1534 } 1509 }
1535 } 1510 }
1536 } 1511 }
1537 1512
1538 // Add unneeded interceptors to the [unneededClasses] set. 1513 // Add unneeded interceptors to the [unneededClasses] set.
1539 for (ClassElement interceptor in backend.interceptedClasses.keys) { 1514 for (ClassElement interceptor in backend.interceptedClasses) {
1540 if (!needed.contains(interceptor)) { 1515 if (!needed.contains(interceptor)
1516 && interceptor != compiler.objectClass) {
1541 unneededClasses.add(interceptor); 1517 unneededClasses.add(interceptor);
1542 } 1518 }
1543 } 1519 }
1544 1520
1545 return (ClassElement cls) => !unneededClasses.contains(cls); 1521 return (ClassElement cls) => !unneededClasses.contains(cls);
1546 } 1522 }
1547 1523
1548 void emitClasses(CodeBuffer buffer) { 1524 void emitClasses(CodeBuffer buffer) {
1549 // Compute the required type checks to know which classes need a 1525 // Compute the required type checks to know which classes need a
1550 // 'is$' method. 1526 // 'is$' method.
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
1713 // if they share methods with the same signature. Currently we do this only 1689 // if they share methods with the same signature. Currently we do this only
1714 // if there are no optional parameters. Closures with optional parameters 1690 // if there are no optional parameters. Closures with optional parameters
1715 // are more difficult to canonicalize because they would need to have the 1691 // are more difficult to canonicalize because they would need to have the
1716 // same default values. 1692 // same default values.
1717 1693
1718 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; 1694 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
1719 int parameterCount = member.parameterCount(compiler); 1695 int parameterCount = member.parameterCount(compiler);
1720 1696
1721 Map<int, String> cache; 1697 Map<int, String> cache;
1722 String extraArg = null; 1698 String extraArg = null;
1723 // Methods on interceptor classes take an extra parameter, which is the 1699 // Intercepted methods take an extra parameter, which is the
1724 // actual receiver of the call. 1700 // receiver of the call.
1725 bool inInterceptor = backend.isInterceptorClass(member.getEnclosingClass()); 1701 bool inInterceptor = backend.isInterceptedMethod(member);
1726 if (inInterceptor) { 1702 if (inInterceptor) {
1727 cache = interceptorClosureCache; 1703 cache = interceptorClosureCache;
1728 extraArg = 'receiver'; 1704 extraArg = 'receiver';
1729 } else { 1705 } else {
1730 cache = boundClosureCache; 1706 cache = boundClosureCache;
1731 } 1707 }
1732 List<String> fieldNames = compiler.enableMinification 1708 List<String> fieldNames = compiler.enableMinification
1733 ? inInterceptor ? const ['a', 'b', 'c'] 1709 ? inInterceptor ? const ['a', 'b', 'c']
1734 : const ['a', 'b'] 1710 : const ['a', 'b']
1735 : inInterceptor ? const ['self', 'target', 'receiver'] 1711 : inInterceptor ? const ['self', 'target', 'receiver']
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1838 /** 1814 /**
1839 * Documentation wanted -- johnniwinther 1815 * Documentation wanted -- johnniwinther
1840 * 1816 *
1841 * Invariant: [member] must be a declaration element. 1817 * Invariant: [member] must be a declaration element.
1842 */ 1818 */
1843 void emitCallStubForGetter(Element member, 1819 void emitCallStubForGetter(Element member,
1844 Set<Selector> selectors, 1820 Set<Selector> selectors,
1845 DefineStubFunction defineStub) { 1821 DefineStubFunction defineStub) {
1846 assert(invariant(member, member.isDeclaration)); 1822 assert(invariant(member, member.isDeclaration));
1847 LibraryElement memberLibrary = member.getLibrary(); 1823 LibraryElement memberLibrary = member.getLibrary();
1848 // If the class is an interceptor class, the stub gets the 1824 // If the method is intercepted, the stub gets the
1849 // receiver explicitely and we need to pass it to the getter call. 1825 // receiver explicitely and we need to pass it to the getter call.
1850 bool isInterceptorClass = 1826 bool isInterceptedMethod = backend.isInterceptedMethod(member);
1851 backend.isInterceptorClass(member.getEnclosingClass());
1852 1827
1853 const String receiverArgumentName = r'$receiver'; 1828 const String receiverArgumentName = r'$receiver';
1854 1829
1855 jsAst.Expression buildGetter() { 1830 jsAst.Expression buildGetter() {
1856 if (member.isGetter()) { 1831 if (member.isGetter()) {
1857 String getterName = namer.getterName(member); 1832 String getterName = namer.getterName(member);
1858 return js['this'][getterName]( 1833 return js['this'][getterName](
1859 isInterceptorClass 1834 isInterceptedMethod
1860 ? <jsAst.Expression>[js[receiverArgumentName]] 1835 ? <jsAst.Expression>[js[receiverArgumentName]]
1861 : <jsAst.Expression>[]); 1836 : <jsAst.Expression>[]);
1862 } else { 1837 } else {
1863 String fieldName = member.hasFixedBackendName() 1838 String fieldName = member.hasFixedBackendName()
1864 ? member.fixedBackendName() 1839 ? member.fixedBackendName()
1865 : namer.instanceFieldName(member); 1840 : namer.instanceFieldName(member);
1866 return js['this'][fieldName]; 1841 return js['this'][fieldName];
1867 } 1842 }
1868 } 1843 }
1869 1844
1870 // Two selectors may match but differ only in type. To avoid generating 1845 // Two selectors may match but differ only in type. To avoid generating
1871 // identical stubs for each we track untyped selectors which already have 1846 // identical stubs for each we track untyped selectors which already have
1872 // stubs. 1847 // stubs.
1873 Set<Selector> generatedSelectors = new Set<Selector>(); 1848 Set<Selector> generatedSelectors = new Set<Selector>();
1874 1849
1875 for (Selector selector in selectors) { 1850 for (Selector selector in selectors) {
1876 if (selector.applies(member, compiler)) { 1851 if (selector.applies(member, compiler)) {
1877 selector = selector.asUntyped; 1852 selector = selector.asUntyped;
1878 if (generatedSelectors.contains(selector)) continue; 1853 if (generatedSelectors.contains(selector)) continue;
1879 generatedSelectors.add(selector); 1854 generatedSelectors.add(selector);
1880 1855
1881 String invocationName = namer.invocationName(selector); 1856 String invocationName = namer.invocationName(selector);
1882 Selector callSelector = new Selector.callClosureFrom(selector); 1857 Selector callSelector = new Selector.callClosureFrom(selector);
1883 String closureCallName = namer.invocationName(callSelector); 1858 String closureCallName = namer.invocationName(callSelector);
1884 1859
1885 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 1860 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
1886 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 1861 List<jsAst.Expression> arguments = <jsAst.Expression>[];
1887 if (isInterceptorClass) { 1862 if (isInterceptedMethod) {
1888 parameters.add(new jsAst.Parameter(receiverArgumentName)); 1863 parameters.add(new jsAst.Parameter(receiverArgumentName));
1889 } 1864 }
1890 1865
1891 for (int i = 0; i < selector.argumentCount; i++) { 1866 for (int i = 0; i < selector.argumentCount; i++) {
1892 String name = 'arg$i'; 1867 String name = 'arg$i';
1893 parameters.add(new jsAst.Parameter(name)); 1868 parameters.add(new jsAst.Parameter(name));
1894 arguments.add(js[name]); 1869 arguments.add(js[name]);
1895 } 1870 }
1896 1871
1897 jsAst.Fun function = js.fun( 1872 jsAst.Fun function = js.fun(
1898 parameters, 1873 parameters,
1899 js.return_(buildGetter()[closureCallName](arguments))); 1874 js.return_(buildGetter()[closureCallName](arguments)));
1900 1875
1901 defineStub(invocationName, function); 1876 defineStub(invocationName, function);
1902 } 1877 }
1903 } 1878 }
1904 } 1879 }
1905 1880
1906 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { 1881 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) {
1907 ConstantHandler handler = compiler.constantHandler; 1882 ConstantHandler handler = compiler.constantHandler;
1908 Iterable<VariableElement> staticNonFinalFields = 1883 Iterable<VariableElement> staticNonFinalFields =
1909 handler.getStaticNonFinalFieldsForEmission(); 1884 handler.getStaticNonFinalFieldsForEmission();
1910 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { 1885 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
1886 // [:interceptedNames:] is handled in [emitInterceptedNames].
1887 if (element == backend.interceptedNames) continue;
1911 compiler.withCurrentElement(element, () { 1888 compiler.withCurrentElement(element, () {
1912 Constant initialValue = handler.getInitialValueFor(element); 1889 Constant initialValue = handler.getInitialValueFor(element);
1913 jsAst.Expression init = 1890 jsAst.Expression init =
1914 js[isolateProperties][namer.getName(element)].assign( 1891 js[isolateProperties][namer.getName(element)].assign(
1915 constantEmitter.referenceInInitializationContext(initialValue)); 1892 constantEmitter.referenceInInitializationContext(initialValue));
1916 buffer.add(jsAst.prettyPrint(init, compiler)); 1893 buffer.add(jsAst.prettyPrint(init, compiler));
1917 buffer.add('$N'); 1894 buffer.add('$N');
1918 }); 1895 });
1919 } 1896 }
1920 } 1897 }
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
2039 2016
2040 List<jsAst.Expression> argNames = 2017 List<jsAst.Expression> argNames =
2041 selector.getOrderedNamedArguments().map((SourceString name) => 2018 selector.getOrderedNamedArguments().map((SourceString name) =>
2042 js.string(name.slowToString())).toList(); 2019 js.string(name.slowToString())).toList();
2043 2020
2044 String internalName = namer.invocationMirrorInternalName(selector); 2021 String internalName = namer.invocationMirrorInternalName(selector);
2045 2022
2046 String createInvocationMirror = namer.getName( 2023 String createInvocationMirror = namer.getName(
2047 compiler.createInvocationMirrorElement); 2024 compiler.createInvocationMirrorElement);
2048 2025
2026 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
2049 jsAst.Expression expression = js['this.$noSuchMethodName']( 2027 jsAst.Expression expression = js['this.$noSuchMethodName'](
2050 js[namer.CURRENT_ISOLATE][createInvocationMirror]([ 2028 [js['this'],
2051 js.string(methodName), 2029 js[namer.CURRENT_ISOLATE][createInvocationMirror]([
2052 js.string(internalName), 2030 js.string(methodName),
2053 type, 2031 js.string(internalName),
2054 new jsAst.ArrayInitializer.from( 2032 type,
2055 parameters.map((param) => js[param.name]).toList()), 2033 new jsAst.ArrayInitializer.from(
2056 new jsAst.ArrayInitializer.from(argNames)])); 2034 parameters.map((param) => js[param.name]).toList()),
2035 new jsAst.ArrayInitializer.from(argNames)])]);
2036 parameters = backend.isInterceptedName(selector.name)
2037 ? ([new jsAst.Parameter('\$receiver')]..addAll(parameters))
2038 : parameters;
2057 return js.fun(parameters, js.return_(expression)); 2039 return js.fun(parameters, js.return_(expression));
2058 } 2040 }
2059 2041
2060 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { 2042 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) {
2061 // Cache the object class and type. 2043 // Cache the object class and type.
2062 ClassElement objectClass = compiler.objectClass; 2044 ClassElement objectClass = compiler.objectClass;
2063 DartType objectType = objectClass.computeType(compiler); 2045 DartType objectType = objectClass.computeType(compiler);
2064 2046
2065 for (Selector selector in selectors) { 2047 for (Selector selector in selectors) {
2066 // Introduce a helper function that determines if the given 2048 // Introduce a helper function that determines if the given
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
2187 dartMainRunner(function() { ${mainCall}; }); 2169 dartMainRunner(function() { ${mainCall}; });
2188 } else { 2170 } else {
2189 ${mainCall}; 2171 ${mainCall};
2190 } 2172 }
2191 } 2173 }
2192 """); 2174 """);
2193 addComment('END invoke [main].', buffer); 2175 addComment('END invoke [main].', buffer);
2194 } 2176 }
2195 2177
2196 void emitGetInterceptorMethod(CodeBuffer buffer, 2178 void emitGetInterceptorMethod(CodeBuffer buffer,
2197 String objectName,
2198 String key, 2179 String key,
2199 Collection<ClassElement> classes) { 2180 Collection<ClassElement> classes) {
2200 jsAst.Statement buildReturnInterceptor(ClassElement cls) { 2181 jsAst.Statement buildReturnInterceptor(ClassElement cls) {
2201 return js.return_(js[namer.isolateAccess(cls)]['prototype']); 2182 return js.return_(js[namer.isolateAccess(cls)]['prototype']);
2202 } 2183 }
2203 2184
2204 jsAst.VariableUse receiver = js['receiver']; 2185 jsAst.VariableUse receiver = js['receiver'];
2205 /** 2186 /**
2206 * Build a JavaScrit AST node for doing a type check on 2187 * Build a JavaScrit AST node for doing a type check on
2207 * [cls]. [cls] must be an interceptor class. 2188 * [cls]. [cls] must be an interceptor class.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2239 bool hasString = false; 2220 bool hasString = false;
2240 for (ClassElement cls in classes) { 2221 for (ClassElement cls in classes) {
2241 if (cls == backend.jsArrayClass) hasArray = true; 2222 if (cls == backend.jsArrayClass) hasArray = true;
2242 else if (cls == backend.jsBoolClass) hasBool = true; 2223 else if (cls == backend.jsBoolClass) hasBool = true;
2243 else if (cls == backend.jsDoubleClass) hasDouble = true; 2224 else if (cls == backend.jsDoubleClass) hasDouble = true;
2244 else if (cls == backend.jsFunctionClass) hasFunction = true; 2225 else if (cls == backend.jsFunctionClass) hasFunction = true;
2245 else if (cls == backend.jsIntClass) hasInt = true; 2226 else if (cls == backend.jsIntClass) hasInt = true;
2246 else if (cls == backend.jsNullClass) hasNull = true; 2227 else if (cls == backend.jsNullClass) hasNull = true;
2247 else if (cls == backend.jsNumberClass) hasNumber = true; 2228 else if (cls == backend.jsNumberClass) hasNumber = true;
2248 else if (cls == backend.jsStringClass) hasString = true; 2229 else if (cls == backend.jsStringClass) hasString = true;
2249 else throw 'Internal error: $cls'; 2230 else {
2231 assert(cls == compiler.objectClass);
2232 }
2250 } 2233 }
2251 if (hasDouble) { 2234 if (hasDouble) {
2252 assert(!hasNumber);
2253 hasNumber = true; 2235 hasNumber = true;
2254 } 2236 }
2255 if (hasInt) hasNumber = true; 2237 if (hasInt) hasNumber = true;
2256 2238
2257 jsAst.Block block = new jsAst.Block.empty(); 2239 jsAst.Block block = new jsAst.Block.empty();
2258 2240
2259 if (hasNumber) { 2241 if (hasNumber) {
2260 jsAst.Statement whenNumber; 2242 jsAst.Statement whenNumber;
2261 2243
2262 /// Note: there are two number classes in play: Dart's [num], 2244 /// Note: there are two number classes in play: Dart's [num],
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2295 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass)); 2277 block.statements.add(buildInterceptorCheck(backend.jsFunctionClass));
2296 } 2278 }
2297 if (hasBool) { 2279 if (hasBool) {
2298 block.statements.add(buildInterceptorCheck(backend.jsBoolClass)); 2280 block.statements.add(buildInterceptorCheck(backend.jsBoolClass));
2299 } 2281 }
2300 // TODO(ahe): It might be faster to check for Array before 2282 // TODO(ahe): It might be faster to check for Array before
2301 // function and bool. 2283 // function and bool.
2302 if (hasArray) { 2284 if (hasArray) {
2303 block.statements.add(buildInterceptorCheck(backend.jsArrayClass)); 2285 block.statements.add(buildInterceptorCheck(backend.jsArrayClass));
2304 } 2286 }
2305 block.statements.add(js.return_(js[objectName]['prototype'])); 2287 block.statements.add(js.return_(receiver));
2306 2288
2307 buffer.add(jsAst.prettyPrint( 2289 buffer.add(jsAst.prettyPrint(
2308 js[isolateProperties][key].assign(js.fun(['receiver'], block)), 2290 js[isolateProperties][key].assign(js.fun(['receiver'], block)),
2309 compiler)); 2291 compiler));
2310 buffer.add(N); 2292 buffer.add(N);
2311 } 2293 }
2312 2294
2313 /** 2295 /**
2314 * Emit all versions of the [:getInterceptor:] method. 2296 * Emit all versions of the [:getInterceptor:] method.
2315 */ 2297 */
2316 void emitGetInterceptorMethods(CodeBuffer buffer) { 2298 void emitGetInterceptorMethods(CodeBuffer buffer) {
2317 // If no class needs to be intercepted, just return.
2318 if (backend.objectInterceptorClass == null) return;
2319 String objectName = namer.isolateAccess(backend.objectInterceptorClass);
2320 var specializedGetInterceptors = backend.specializedGetInterceptors; 2299 var specializedGetInterceptors = backend.specializedGetInterceptors;
2321 for (String name in specializedGetInterceptors.keys.toList()..sort()) { 2300 for (String name in specializedGetInterceptors.keys.toList()..sort()) {
2322 Collection<ClassElement> classes = specializedGetInterceptors[name]; 2301 Collection<ClassElement> classes = specializedGetInterceptors[name];
2323 emitGetInterceptorMethod(buffer, objectName, name, classes); 2302 emitGetInterceptorMethod(buffer, name, classes);
2324 } 2303 }
2325 } 2304 }
2326 2305
2327 void computeNeededClasses() { 2306 void computeNeededClasses() {
2328 instantiatedClasses = 2307 instantiatedClasses =
2329 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) 2308 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
2330 .toSet(); 2309 .toSet();
2331 neededClasses = new Set<ClassElement>.from(instantiatedClasses); 2310 neededClasses = new Set<ClassElement>.from(instantiatedClasses);
2332 for (ClassElement element in instantiatedClasses) { 2311 for (ClassElement element in instantiatedClasses) {
2333 for (ClassElement superclass = element.superclass; 2312 for (ClassElement superclass = element.superclass;
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
2494 } 2473 }
2495 return null; 2474 return null;
2496 } 2475 }
2497 2476
2498 void emitOneShotInterceptors(CodeBuffer buffer) { 2477 void emitOneShotInterceptors(CodeBuffer buffer) {
2499 List<String> names = backend.oneShotInterceptors.keys.toList(); 2478 List<String> names = backend.oneShotInterceptors.keys.toList();
2500 names.sort(); 2479 names.sort();
2501 for (String name in names) { 2480 for (String name in names) {
2502 Selector selector = backend.oneShotInterceptors[name]; 2481 Selector selector = backend.oneShotInterceptors[name];
2503 Set<ClassElement> classes = 2482 Set<ClassElement> classes =
2504 backend.getInterceptedClassesOn(selector); 2483 backend.getInterceptedClassesOn(selector.name);
2505 String getInterceptorName = 2484 String getInterceptorName =
2506 namer.getInterceptorName(backend.getInterceptorMethod, classes); 2485 namer.getInterceptorName(backend.getInterceptorMethod, classes);
2507 2486
2508 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 2487 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
2509 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 2488 List<jsAst.Expression> arguments = <jsAst.Expression>[];
2510 parameters.add(new jsAst.Parameter('receiver')); 2489 parameters.add(new jsAst.Parameter('receiver'));
2511 arguments.add(js['receiver']); 2490 arguments.add(js['receiver']);
2512 2491
2513 if (selector.isSetter()) { 2492 if (selector.isSetter()) {
2514 parameters.add(new jsAst.Parameter('value')); 2493 parameters.add(new jsAst.Parameter('value'));
(...skipping 21 matching lines...) Expand all
2536 jsAst.Fun function = js.fun(parameters, body); 2515 jsAst.Fun function = js.fun(parameters, body);
2537 2516
2538 jsAst.PropertyAccess property = 2517 jsAst.PropertyAccess property =
2539 js[isolateProperties][name]; 2518 js[isolateProperties][name];
2540 2519
2541 buffer.add(jsAst.prettyPrint(property.assign(function), compiler)); 2520 buffer.add(jsAst.prettyPrint(property.assign(function), compiler));
2542 buffer.add(N); 2521 buffer.add(N);
2543 } 2522 }
2544 } 2523 }
2545 2524
2525 /**
2526 * If [:invokeOn:] has been compiled, emit all the possible selector names
2527 * that are intercepted into the [:interceptedNames:] top-level
2528 * variable. The implementation of [:invokeOn:] will use it to
2529 * determine whether it should call the method with an extra
2530 * parameter.
2531 */
2532 void emitInterceptedNames(CodeBuffer buffer) {
2533 if (!compiler.enabledInvokeOn) return;
2534 String name = backend.namer.getName(backend.interceptedNames);
2535 jsAst.PropertyAccess property = js[isolateProperties][name];
2536
2537 int index = 0;
2538 List<jsAst.ArrayElement> elements = backend.usedInterceptors.map(
2539 (Selector selector) {
2540 jsAst.Literal str = js.string(namer.invocationName(selector));
2541 return new jsAst.ArrayElement(index++, str);
2542 }).toList();
2543 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(
2544 backend.usedInterceptors.length,
2545 elements);
2546
2547 buffer.add(jsAst.prettyPrint(property.assign(array), compiler));
2548 buffer.add(N);
2549 }
2550
2546 void emitInitFunction(CodeBuffer buffer) { 2551 void emitInitFunction(CodeBuffer buffer) {
2547 jsAst.Fun fun = js.fun([], [ 2552 jsAst.Fun fun = js.fun([], [
2548 js['$isolateProperties = {}'], 2553 js['$isolateProperties = {}'],
2549 ] 2554 ]
2550 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary()) 2555 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary())
2551 ..addAll(buildLazyInitializerFunctionIfNecessary()) 2556 ..addAll(buildLazyInitializerFunctionIfNecessary())
2552 ..addAll(buildFinishIsolateConstructor()) 2557 ..addAll(buildFinishIsolateConstructor())
2553 ); 2558 );
2554 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( 2559 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
2555 new jsAst.VariableDeclaration('init'), fun); 2560 new jsAst.VariableDeclaration('init'), fun);
(...skipping 23 matching lines...) Expand all
2579 emitStaticFunctionGetters(mainBuffer); 2584 emitStaticFunctionGetters(mainBuffer);
2580 // We need to finish the classes before we construct compile time 2585 // We need to finish the classes before we construct compile time
2581 // constants. 2586 // constants.
2582 emitFinishClassesInvocationIfNecessary(mainBuffer); 2587 emitFinishClassesInvocationIfNecessary(mainBuffer);
2583 emitRuntimeClassesAndTests(mainBuffer); 2588 emitRuntimeClassesAndTests(mainBuffer);
2584 emitCompileTimeConstants(mainBuffer); 2589 emitCompileTimeConstants(mainBuffer);
2585 // Static field initializations require the classes and compile-time 2590 // Static field initializations require the classes and compile-time
2586 // constants to be set up. 2591 // constants to be set up.
2587 emitStaticNonFinalFieldInitializations(mainBuffer); 2592 emitStaticNonFinalFieldInitializations(mainBuffer);
2588 emitOneShotInterceptors(mainBuffer); 2593 emitOneShotInterceptors(mainBuffer);
2594 emitInterceptedNames(mainBuffer);
2589 emitGetInterceptorMethods(mainBuffer); 2595 emitGetInterceptorMethods(mainBuffer);
2590 emitLazilyInitializedStaticFields(mainBuffer); 2596 emitLazilyInitializedStaticFields(mainBuffer);
2591 2597
2592 isolateProperties = isolatePropertiesName; 2598 isolateProperties = isolatePropertiesName;
2593 // The following code should not use the short-hand for the 2599 // The following code should not use the short-hand for the
2594 // initialStatics. 2600 // initialStatics.
2595 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N'); 2601 mainBuffer.add('var ${namer.CURRENT_ISOLATE}$_=${_}null$N');
2596 if (!boundClosureBuffer.isEmpty) { 2602 if (!boundClosureBuffer.isEmpty) {
2597 mainBuffer.add(boundClosureBuffer); 2603 mainBuffer.add(boundClosureBuffer);
2598 emitFinishClassesInvocationIfNecessary(mainBuffer); 2604 emitFinishClassesInvocationIfNecessary(mainBuffer);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
2691 """; 2697 """;
2692 const String HOOKS_API_USAGE = """ 2698 const String HOOKS_API_USAGE = """
2693 // The code supports the following hooks: 2699 // The code supports the following hooks:
2694 // dartPrint(message) - if this function is defined it is called 2700 // dartPrint(message) - if this function is defined it is called
2695 // instead of the Dart [print] method. 2701 // instead of the Dart [print] method.
2696 // dartMainRunner(main) - if this function is defined, the Dart [main] 2702 // dartMainRunner(main) - if this function is defined, the Dart [main]
2697 // method will not be invoked directly. 2703 // method will not be invoked directly.
2698 // Instead, a closure that will invoke [main] is 2704 // Instead, a closure that will invoke [main] is
2699 // passed to [dartMainRunner]. 2705 // passed to [dartMainRunner].
2700 """; 2706 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698