Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 /** | 5 /** |
| 6 * A function element that represents a closure call. The signature is copied | 6 * A function element that represents a closure call. The signature is copied |
| 7 * from the given element. | 7 * from the given element. |
| 8 */ | 8 */ |
| 9 class ClosureInvocationElement extends FunctionElement { | 9 class ClosureInvocationElement extends FunctionElement { |
| 10 ClosureInvocationElement(SourceString name, | 10 ClosureInvocationElement(SourceString name, |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 code = 'function() { return true; }'; | 528 code = 'function() { return true; }'; |
| 529 } else { | 529 } else { |
| 530 code = 'true'; | 530 code = 'true'; |
| 531 } | 531 } |
| 532 CodeBuffer buffer = new CodeBuffer(); | 532 CodeBuffer buffer = new CodeBuffer(); |
| 533 buffer.add(code); | 533 buffer.add(code); |
| 534 defineInstanceMember(namer.operatorIs(other), buffer); | 534 defineInstanceMember(namer.operatorIs(other), buffer); |
| 535 }); | 535 }); |
| 536 | 536 |
| 537 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { | 537 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
| 538 // Emit the noSuchMethods on the Object prototype now, so that | 538 // Emit the noSuchMethod handlers on the Object prototype now, |
| 539 // the code in the dynamicMethod can find them. Note that the | 539 // so that the code in the dynamicMethod can find them. Note |
| 540 // code in dynamicMethod is invoked before analyzing the full JS | 540 // that the code in dynamicMethod is invoked before analyzing |
| 541 // script. | 541 // the full JS script. |
| 542 emitNoSuchMethodCalls(defineInstanceMember); | 542 emitNoSuchMethodHandlers(defineInstanceMember); |
| 543 } | 543 } |
| 544 } | 544 } |
| 545 | 545 |
| 546 void generateClass(ClassElement classElement, CodeBuffer buffer) { | 546 void generateClass(ClassElement classElement, CodeBuffer buffer) { |
| 547 if (classElement.isNative()) { | 547 if (classElement.isNative()) { |
| 548 nativeEmitter.generateNativeClass(classElement); | 548 nativeEmitter.generateNativeClass(classElement); |
| 549 return; | 549 return; |
| 550 } else { | 550 } else { |
| 551 // TODO(ngeoffray): Instead of switching between buffer, we | 551 // TODO(ngeoffray): Instead of switching between buffer, we |
| 552 // should create code sections, and decide where to emit them at | 552 // should create code sections, and decide where to emit them at |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 858 if (selectors !== null && !selectors.isEmpty()) { | 858 if (selectors !== null && !selectors.isEmpty()) { |
| 859 emitCallStubForGetter(member, selectors, defineInstanceMember); | 859 emitCallStubForGetter(member, selectors, defineInstanceMember); |
| 860 } | 860 } |
| 861 } else if (member.kind == ElementKind.FUNCTION) { | 861 } else if (member.kind == ElementKind.FUNCTION) { |
| 862 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { | 862 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { |
| 863 emitDynamicFunctionGetter(member, defineInstanceMember); | 863 emitDynamicFunctionGetter(member, defineInstanceMember); |
| 864 } | 864 } |
| 865 } | 865 } |
| 866 } | 866 } |
| 867 | 867 |
| 868 void emitNoSuchMethodCalls(DefineMemberFunction defineInstanceMember) { | 868 void emitNoSuchMethodHandlers(DefineMemberFunction defineInstanceMember) { |
| 869 // Do not generate no such method calls if there is no class. | 869 // Do not generate no such method handlers if there is no class. |
| 870 if (compiler.codegenWorld.instantiatedClasses.isEmpty()) return; | 870 if (compiler.codegenWorld.instantiatedClasses.isEmpty()) return; |
| 871 | 871 |
| 872 ClassElement objectClass = | 872 ClassElement objectClass = |
| 873 compiler.coreLibrary.find(const SourceString('Object')); | 873 compiler.coreLibrary.find(const SourceString('Object')); |
| 874 String runtimeObjectPrototype = | 874 String runtimeObjectPrototype = |
| 875 '${namer.isolateAccess(objectClass)}.prototype'; | 875 '${namer.isolateAccess(objectClass)}.prototype'; |
| 876 String noSuchMethodName = | 876 String noSuchMethodName = |
| 877 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); | 877 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); |
| 878 Collection<LibraryElement> libraries = compiler.libraries.getValues(); | 878 |
| 879 // Keep track of the JavaScript names we've already added so we | |
| 880 // do not introduce duplicates (bad for code size). | |
| 881 Set<String> addedJsNames = new Set<String>(); | |
| 879 | 882 |
| 880 CodeBuffer generateMethod(String methodName, Selector selector) { | 883 CodeBuffer generateMethod(String methodName, Selector selector) { |
| 881 CodeBuffer buffer = new CodeBuffer(); | |
| 882 buffer.add('function'); | |
| 883 CodeBuffer args = new CodeBuffer(); | 884 CodeBuffer args = new CodeBuffer(); |
| 884 for (int i = 0; i < selector.argumentCount; i++) { | 885 for (int i = 0; i < selector.argumentCount; i++) { |
| 885 if (i != 0) args.add(', '); | 886 if (i != 0) args.add(', '); |
| 886 args.add('arg$i'); | 887 args.add('\$$i'); |
| 887 } | 888 } |
| 888 // We need to check if the object has a noSuchMethod. If not, it | 889 // We need to check if the object has a noSuchMethod. If not, it |
| 889 // means the object is a native object, and we can just call our | 890 // means the object is a native object, and we can just call our |
| 890 // generic noSuchMethod. Note that when calling this method, the | 891 // generic noSuchMethod. Note that when calling this method, the |
| 891 // 'this' object is not a Dart object. | 892 // 'this' object is not a Dart object. |
| 892 buffer.add(' ($args) {\n'); | 893 CodeBuffer buffer = new CodeBuffer(); |
| 894 buffer.add('function($args) {\n'); | |
| 893 buffer.add(' return this.$noSuchMethodName\n'); | 895 buffer.add(' return this.$noSuchMethodName\n'); |
| 894 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); | 896 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); |
| 895 buffer.add(" : $runtimeObjectPrototype.$noSuchMethodName.call("); | 897 buffer.add(" : $runtimeObjectPrototype.$noSuchMethodName.call("); |
| 896 buffer.add("this, '$methodName', [$args])\n"); | 898 buffer.add("this, '$methodName', [$args])\n"); |
| 897 buffer.add('}'); | 899 buffer.add('}'); |
| 898 return buffer; | 900 return buffer; |
| 899 } | 901 } |
| 900 | 902 |
| 901 compiler.codegenWorld.invokedNames.forEach((SourceString methodName, | 903 void addNoSuchMethodHandlers(SourceString name, Set<Selector> selectors) { |
| 902 Set<Selector> selectors) { | 904 // TODO(kasperl): It seems wrong to avoid generating no such |
| 903 if (objectClass.lookupLocalMember(methodName) === null | 905 // method handlers for methods that exist in the Object class |
| 904 && methodName != Elements.OPERATOR_EQUALS) { | 906 // without taking the selector (arity) into account. Needs more |
|
floitsch
2012/08/02 11:21:51
Investigated it. The following code works on the V
| |
| 905 for (Selector selector in selectors) { | 907 // investigation. |
| 906 if (methodName.isPrivate()) { | 908 if (objectClass.lookupLocalMember(name) !== null && |
| 907 for (LibraryElement lib in libraries) { | 909 name != Elements.OPERATOR_EQUALS) return; |
| 908 String jsName = | 910 |
| 909 namer.instanceMethodInvocationName(lib, methodName, selector); | 911 // TODO(kasperl): We should really teach private selectors about |
| 910 CodeBuffer method = | 912 // which libraries they are used from. That way, we wouldn't |
| 911 generateMethod(methodName.slowToString(), selector); | 913 // have to conservatively generate versions for all libraries. |
| 912 defineInstanceMember(jsName, method); | 914 Collection<LibraryElement> libraries = name.isPrivate() |
| 913 } | 915 ? compiler.libraries.getValues() |
| 916 : const [ null ]; | |
| 917 String nameString = name.slowToString(); | |
| 918 | |
| 919 for (Selector selector in selectors) { | |
| 920 for (LibraryElement lib in libraries) { | |
| 921 String jsName = null; | |
| 922 String methodName = null; | |
| 923 if (selector.kind === SelectorKind.GETTER) { | |
| 924 jsName = namer.getterName(lib, name); | |
| 925 methodName = 'get $nameString'; | |
| 926 } else if (selector.kind === SelectorKind.SETTER) { | |
| 927 jsName = namer.setterName(lib, name); | |
| 928 methodName = 'set $nameString'; | |
| 929 } else if (selector.kind === SelectorKind.INVOCATION) { | |
| 930 jsName = namer.instanceMethodInvocationName(lib, name, selector); | |
| 931 methodName = nameString; | |
| 914 } else { | 932 } else { |
| 915 String jsName = | 933 // We simply ignore selectors that do not need no such |
| 916 namer.instanceMethodInvocationName(null, methodName, selector); | 934 // method handlers. |
| 917 CodeBuffer method = generateMethod(methodName.slowToString(), | 935 continue; |
| 918 selector); | 936 } |
| 919 defineInstanceMember(jsName, method); | 937 if (!addedJsNames.contains(jsName)) { |
| 938 CodeBuffer jsCode = generateMethod(methodName, selector); | |
| 939 defineInstanceMember(jsName, jsCode); | |
| 940 addedJsNames.add(jsName); | |
| 920 } | 941 } |
| 921 } | 942 } |
| 922 } | 943 } |
| 923 }); | 944 } |
| 924 | 945 |
| 925 compiler.codegenWorld.invokedGetters.forEach((SourceString getterName, | 946 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); |
| 926 Set<Selector> selectors) { | 947 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); |
| 927 if (getterName.isPrivate()) { | 948 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); |
| 928 for (LibraryElement lib in libraries) { | |
| 929 String jsName = namer.getterName(lib, getterName); | |
| 930 CodeBuffer method = generateMethod('get ${getterName.slowToString()}', | |
| 931 Selector.GETTER); | |
| 932 defineInstanceMember(jsName, method); | |
| 933 } | |
| 934 } else { | |
| 935 String jsName = namer.getterName(null, getterName); | |
| 936 CodeBuffer method = generateMethod('get ${getterName.slowToString()}', | |
| 937 Selector.GETTER); | |
| 938 defineInstanceMember(jsName, method); | |
| 939 } | |
| 940 }); | |
| 941 | |
| 942 compiler.codegenWorld.invokedSetters.forEach((SourceString setterName, | |
| 943 Set<Selector> selectors) { | |
| 944 if (setterName.isPrivate()) { | |
| 945 for (LibraryElement lib in libraries) { | |
| 946 String jsName = namer.setterName(lib, setterName); | |
| 947 CodeBuffer method = generateMethod('set ${setterName.slowToString()}', | |
| 948 Selector.SETTER); | |
| 949 defineInstanceMember(jsName, method); | |
| 950 } | |
| 951 } else { | |
| 952 String jsName = namer.setterName(null, setterName); | |
| 953 CodeBuffer method = generateMethod('set ${setterName.slowToString()}', | |
| 954 Selector.SETTER); | |
| 955 defineInstanceMember(jsName, method); | |
| 956 } | |
| 957 }); | |
| 958 } | 949 } |
| 959 | 950 |
| 960 String buildIsolateSetup(CodeBuffer buffer, | 951 String buildIsolateSetup(CodeBuffer buffer, |
| 961 Element appMain, | 952 Element appMain, |
| 962 Element isolateMain) { | 953 Element isolateMain) { |
| 963 String mainAccess = "${namer.isolateAccess(appMain)}"; | 954 String mainAccess = "${namer.isolateAccess(appMain)}"; |
| 964 String currentIsolate = "${namer.CURRENT_ISOLATE}"; | 955 String currentIsolate = "${namer.CURRENT_ISOLATE}"; |
| 965 String mainEnsureGetter = ''; | 956 String mainEnsureGetter = ''; |
| 966 // Since we pass the closurized version of the main method to | 957 // Since we pass the closurized version of the main method to |
| 967 // the isolate method, we must make sure that it exists. | 958 // the isolate method, we must make sure that it exists. |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1087 sourceName = token.slowToString(); | 1078 sourceName = token.slowToString(); |
| 1088 } | 1079 } |
| 1089 int totalOffset = bufferOffset + offset; | 1080 int totalOffset = bufferOffset + offset; |
| 1090 sourceMapBuilder.addMapping( | 1081 sourceMapBuilder.addMapping( |
| 1091 sourceFile, token.charOffset, sourceName, totalOffset); | 1082 sourceFile, token.charOffset, sourceName, totalOffset); |
| 1092 }); | 1083 }); |
| 1093 } | 1084 } |
| 1094 } | 1085 } |
| 1095 | 1086 |
| 1096 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); | 1087 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); |
| OLD | NEW |