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

Side by Side Diff: lib/compiler/implementation/emitter.dart

Issue 10832109: Refactor the way we emit no such method handlers so it's easier to optimize it later. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Improve NSM handling. Created 8 years, 4 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 /** 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
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 dynamicFunction helper can find
540 // code in dynamicMethod is invoked before analyzing the full JS 540 // them. Note that this helper is invoked before analyzing the
541 // script. 541 // 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
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
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 // the name is used from.
913 } 915 String nameString = name.slowToString();
916 Collection<LibraryElement> libraries = name.isPrivate()
917 ? namer.usedPrivateNames[nameString]
918 : const [ null ];
919
920 for (Selector selector in selectors) {
921 // If the selector is typed, we check to see if that type may
922 // have a user-defined noSuchMethod implementation. If not, we
923 // skip the selector altogether.
924 if (selector is TypedSelector) {
925 Type receiverType = (selector as TypedSelector).receiverType;
926 // For now, we check the entire world to see if an object of
927 // the receiver type may have a user-defined noSuchMethod
928 // implementation. We could do better by only looking at
929 // instantiated classes.
930 if (!compiler.world.mayHaveUserDefinedNoSuchMethod(receiverType)) {
931 continue;
932 }
933 }
934
935 for (LibraryElement lib in libraries) {
936 String jsName = null;
937 String methodName = null;
938 if (selector.kind === SelectorKind.GETTER) {
939 jsName = namer.getterName(lib, name);
940 methodName = 'get $nameString';
941 } else if (selector.kind === SelectorKind.SETTER) {
942 jsName = namer.setterName(lib, name);
943 methodName = 'set $nameString';
944 } else if (selector.kind === SelectorKind.INVOCATION) {
945 jsName = namer.instanceMethodInvocationName(lib, name, selector);
946 methodName = nameString;
914 } else { 947 } else {
915 String jsName = 948 // We simply ignore selectors that do not need no such
916 namer.instanceMethodInvocationName(null, methodName, selector); 949 // method handlers.
917 CodeBuffer method = generateMethod(methodName.slowToString(), 950 continue;
918 selector); 951 }
919 defineInstanceMember(jsName, method); 952 if (!addedJsNames.contains(jsName)) {
953 CodeBuffer jsCode = generateMethod(methodName, selector);
954 defineInstanceMember(jsName, jsCode);
955 addedJsNames.add(jsName);
920 } 956 }
921 } 957 }
922 } 958 }
923 }); 959 }
924 960
925 compiler.codegenWorld.invokedGetters.forEach((SourceString getterName, 961 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers);
926 Set<Selector> selectors) { 962 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers);
927 if (getterName.isPrivate()) { 963 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 } 964 }
959 965
960 String buildIsolateSetup(CodeBuffer buffer, 966 String buildIsolateSetup(CodeBuffer buffer,
961 Element appMain, 967 Element appMain,
962 Element isolateMain) { 968 Element isolateMain) {
963 String mainAccess = "${namer.isolateAccess(appMain)}"; 969 String mainAccess = "${namer.isolateAccess(appMain)}";
964 String currentIsolate = "${namer.CURRENT_ISOLATE}"; 970 String currentIsolate = "${namer.CURRENT_ISOLATE}";
965 String mainEnsureGetter = ''; 971 String mainEnsureGetter = '';
966 // Since we pass the closurized version of the main method to 972 // Since we pass the closurized version of the main method to
967 // the isolate method, we must make sure that it exists. 973 // the isolate method, we must make sure that it exists.
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1087 sourceName = token.slowToString(); 1093 sourceName = token.slowToString();
1088 } 1094 }
1089 int totalOffset = bufferOffset + offset; 1095 int totalOffset = bufferOffset + offset;
1090 sourceMapBuilder.addMapping( 1096 sourceMapBuilder.addMapping(
1091 sourceFile, token.charOffset, sourceName, totalOffset); 1097 sourceFile, token.charOffset, sourceName, totalOffset);
1092 }); 1098 });
1093 } 1099 }
1094 } 1100 }
1095 1101
1096 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); 1102 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition);
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | lib/compiler/implementation/world.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698