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

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: 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
« no previous file with comments | « no previous file | runtime/lib/object.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
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);
OLDNEW
« no previous file with comments | « no previous file | runtime/lib/object.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698