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

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

Powered by Google App Engine
This is Rietveld 408576698