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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 11365170: Start new design for interceptors and implement String.charCodeAt with it. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 1 month 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 26 matching lines...) Expand all
37 bool needsLazyInitializer = false; 37 bool needsLazyInitializer = false;
38 final Namer namer; 38 final Namer namer;
39 ConstantEmitter constantEmitter; 39 ConstantEmitter constantEmitter;
40 NativeEmitter nativeEmitter; 40 NativeEmitter nativeEmitter;
41 CodeBuffer boundClosureBuffer; 41 CodeBuffer boundClosureBuffer;
42 CodeBuffer mainBuffer; 42 CodeBuffer mainBuffer;
43 /** Shorter access to [isolatePropertiesName]. Both here in the code, as 43 /** Shorter access to [isolatePropertiesName]. Both here in the code, as
44 well as in the generated code. */ 44 well as in the generated code. */
45 String isolateProperties; 45 String isolateProperties;
46 String classesCollector; 46 String classesCollector;
47
48 /**
49 * A cache of closures that are used to closurize instance methods.
50 * A closure is dynamically bound to the instance used when closurization.
karlklose 2012/11/13 12:25:30 closurization -> closurized.
ngeoffray 2012/11/13 12:51:50 Done.
51 */
47 final Map<int, String> boundClosureCache; 52 final Map<int, String> boundClosureCache;
53
54 /**
55 * A cache of closures that are used to closurize instance methods
56 * of interceptors. Such closure is dynmically bound to the
karlklose 2012/11/13 12:25:30 'Such' -> 'Such a', or change to use 'These'.
ngeoffray 2012/11/13 12:51:50 Done.
57 * interceptor instance, and the actuall receiver of the method.
58 */
59 final Map<int, String> interceptorClosureCache;
48 Set<ClassElement> checkedClasses; 60 Set<ClassElement> checkedClasses;
49 61
50 final bool generateSourceMap; 62 final bool generateSourceMap;
51 63
52 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) 64 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap)
53 : boundClosureBuffer = new CodeBuffer(), 65 : boundClosureBuffer = new CodeBuffer(),
54 mainBuffer = new CodeBuffer(), 66 mainBuffer = new CodeBuffer(),
55 this.namer = namer, 67 this.namer = namer,
56 boundClosureCache = new Map<int, String>(), 68 boundClosureCache = new Map<int, String>(),
69 interceptorClosureCache = new Map<int, String>(),
57 constantEmitter = new ConstantEmitter(compiler, namer), 70 constantEmitter = new ConstantEmitter(compiler, namer),
58 super(compiler) { 71 super(compiler) {
59 nativeEmitter = new NativeEmitter(this); 72 nativeEmitter = new NativeEmitter(this);
60 } 73 }
61 74
62 void computeRequiredTypeChecks() { 75 void computeRequiredTypeChecks() {
63 assert(checkedClasses == null); 76 assert(checkedClasses == null);
64 checkedClasses = new Set<ClassElement>(); 77 checkedClasses = new Set<ClassElement>();
65 compiler.codegenWorld.isChecks.forEach((DartType t) { 78 compiler.codegenWorld.isChecks.forEach((DartType t) {
66 if (t is InterfaceType) checkedClasses.add(t.element); 79 if (t is InterfaceType) checkedClasses.add(t.element);
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 /** 623 /**
611 * Documentation wanted -- johnniwinther 624 * Documentation wanted -- johnniwinther
612 * 625 *
613 * Invariant: [classElement] must be a declaration element. 626 * Invariant: [classElement] must be a declaration element.
614 */ 627 */
615 void emitInstanceMembers(ClassElement classElement, 628 void emitInstanceMembers(ClassElement classElement,
616 CodeBuffer buffer, 629 CodeBuffer buffer,
617 bool needsLeadingComma) { 630 bool needsLeadingComma) {
618 assert(invariant(classElement, classElement.isDeclaration)); 631 assert(invariant(classElement, classElement.isDeclaration));
619 bool needsComma = needsLeadingComma; 632 bool needsComma = needsLeadingComma;
620 void defineInstanceMember(String name, CodeBuffer memberBuffer) { 633 void defineInstanceMember(String name, StringBuffer memberBuffer) {
621 if (needsComma) buffer.add(','); 634 if (needsComma) buffer.add(',');
622 needsComma = true; 635 needsComma = true;
623 buffer.add('\n'); 636 buffer.add('\n');
624 buffer.add(' $name: '); 637 buffer.add(' $name: ');
625 buffer.add(memberBuffer); 638 buffer.add(memberBuffer);
626 } 639 }
627 640
641 JavaScriptBackend backend = compiler.backend;
642 if (classElement == backend.objectInterceptorClass) {
643 emitInterceptorMethods(defineInstanceMember);
644 // The ObjectInterceptor does not have any instance methods.
645 return;
646 }
647
628 classElement.implementation.forEachMember( 648 classElement.implementation.forEachMember(
629 (ClassElement enclosing, Element member) { 649 (ClassElement enclosing, Element member) {
630 assert(invariant(classElement, member.isDeclaration)); 650 assert(invariant(classElement, member.isDeclaration));
631 if (member.isInstanceMember()) { 651 if (member.isInstanceMember()) {
632 addInstanceMember(member, defineInstanceMember); 652 addInstanceMember(member, defineInstanceMember);
633 } 653 }
634 }, 654 },
635 includeBackendMembers: true); 655 includeBackendMembers: true);
636 656
637 generateIsTestsOn(classElement, (ClassElement other) { 657 generateIsTestsOn(classElement, (ClassElement other) {
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 emitClassFields(classElement, buffer); 868 emitClassFields(classElement, buffer);
849 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. 869 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'.
850 // That does currently not work because the native classes have a different 870 // That does currently not work because the native classes have a different
851 // syntax. 871 // syntax.
852 buffer.add(',\n "super": "$superName"'); 872 buffer.add(',\n "super": "$superName"');
853 emitClassGettersSetters(classElement, buffer); 873 emitClassGettersSetters(classElement, buffer);
854 emitInstanceMembers(classElement, buffer, true); 874 emitInstanceMembers(classElement, buffer, true);
855 buffer.add('\n};\n\n'); 875 buffer.add('\n};\n\n');
856 } 876 }
857 877
878 void emitInterceptorMethods(
879 void defineInstanceMember(String name, StringBuffer memberBuffer)) {
880 JavaScriptBackend backend = compiler.backend;
881 // Emit forwarders for the ObjectInterceptor class. We need to
882 // emit all possible sends on intercepted methods.
883 for (Selector selector in backend.usedInterceptors) {
884 String name;
885 String comma = '';
886 String parameters = '';
887 if (selector.isGetter()) {
888 name = backend.namer.getterName(selector.library, selector.name);
889 } else if (selector.isSetter()) {
890 name = backend.namer.setterName(selector.library, selector.name);
891 } else {
892 assert(selector.isCall());
893 name = backend.namer.instanceMethodInvocationName(
894 selector.library, selector.name, selector);
895 if (selector.argumentCount > 0) {
896 comma = ', ';
897 int i = 0;
898 for (; i < selector.argumentCount - 1; i++) {
899 parameters = '${parameters}a$i, ';
900 }
901 parameters = '${parameters}a$i';
902 }
903 }
904 StringBuffer body = new StringBuffer(
905 "function(receiver$comma$parameters) {"
906 " return receiver.$name($parameters); }");
karlklose 2012/11/13 12:25:30 Use two spaces for indentation?
ngeoffray 2012/11/13 12:51:50 No, the string is just one line.
907 defineInstanceMember(name, body);
908 }
909 }
910
858 /** 911 /**
859 * Generate "is tests" for [cls]: itself, and the "is tests" for the 912 * Generate "is tests" for [cls]: itself, and the "is tests" for the
860 * classes it implements. We don't need to add the "is tests" of the 913 * classes it implements. We don't need to add the "is tests" of the
861 * super class because they will be inherited at runtime. 914 * super class because they will be inherited at runtime.
862 */ 915 */
863 void generateIsTestsOn(ClassElement cls, 916 void generateIsTestsOn(ClassElement cls,
864 void emitIsTest(ClassElement element)) { 917 void emitIsTest(ClassElement element)) {
865 if (checkedClasses.contains(cls)) { 918 if (checkedClasses.contains(cls)) {
866 emitIsTest(cls); 919 emitIsTest(cls);
867 } 920 }
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1009 buffer.add('$fieldAccess.$name = $value;\n'); 1062 buffer.add('$fieldAccess.$name = $value;\n');
1010 }); 1063 });
1011 // If a static function is used as a closure we need to add its name 1064 // If a static function is used as a closure we need to add its name
1012 // in case it is used in spawnFunction. 1065 // in case it is used in spawnFunction.
1013 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; 1066 String fieldName = namer.STATIC_CLOSURE_NAME_NAME;
1014 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); 1067 buffer.add('$fieldAccess.$fieldName = "$staticName";\n');
1015 } 1068 }
1016 } 1069 }
1017 1070
1018 void emitBoundClosureClassHeader(String mangledName, 1071 void emitBoundClosureClassHeader(String mangledName,
1019 String superName, 1072 String superName,
1020 CodeBuffer buffer) { 1073 String extraArgument,
1074 CodeBuffer buffer) {
1075 extraArgument = extraArgument.isEmpty ? '' : ", '$extraArgument'";
1021 buffer.add(""" 1076 buffer.add("""
1022 $classesCollector.$mangledName = {'': 1077 $classesCollector.$mangledName = {'':
1023 ['self', 'target'], 1078 ['self'$extraArgument, 'target'],
1024 'super': '$superName', 1079 'super': '$superName',
1025 """); 1080 """);
1026 } 1081 }
1027 1082
1028 /** 1083 /**
1029 * Documentation wanted -- johnniwinther 1084 * Documentation wanted -- johnniwinther
1030 * 1085 *
1031 * Invariant: [member] must be a declaration element. 1086 * Invariant: [member] must be a declaration element.
1032 */ 1087 */
1033 void emitDynamicFunctionGetter(FunctionElement member, 1088 void emitDynamicFunctionGetter(FunctionElement member,
(...skipping 16 matching lines...) Expand all
1050 1105
1051 // TODO(floitsch): share the closure classes with other classes 1106 // TODO(floitsch): share the closure classes with other classes
1052 // if they share methods with the same signature. Currently we do this only 1107 // if they share methods with the same signature. Currently we do this only
1053 // if there are no optional parameters. Closures with optional parameters 1108 // if there are no optional parameters. Closures with optional parameters
1054 // are more difficult to canonicalize because they would need to have the 1109 // are more difficult to canonicalize because they would need to have the
1055 // same default values. 1110 // same default values.
1056 1111
1057 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0; 1112 bool hasOptionalParameters = member.optionalParameterCount(compiler) != 0;
1058 int parameterCount = member.parameterCount(compiler); 1113 int parameterCount = member.parameterCount(compiler);
1059 1114
1115 Map<int, String> cache;
1116 String extraArg;
1117 String extraArgWithThis;
1118 String extraArgWithoutComma;
1119 // Methods on foreign classes take an extra parameter, which is
1120 // the actual receiver of the call.
1121 JavaScriptBackend backend = compiler.backend;
1122 if (backend.isInterceptorClass(member.getEnclosingClass())) {
1123 cache = interceptorClosureCache;
1124 extraArg = 'receiver, ';
1125 extraArgWithThis = 'this.receiver, ';
1126 extraArgWithoutComma = 'receiver';
1127 } else {
1128 cache = boundClosureCache;
1129 extraArg = '';
1130 extraArgWithoutComma = '';
1131 extraArgWithThis = '';
1132 }
1133
1060 String closureClass = 1134 String closureClass =
1061 hasOptionalParameters ? null : boundClosureCache[parameterCount]; 1135 hasOptionalParameters ? null : cache[parameterCount];
1062 if (closureClass == null) { 1136 if (closureClass == null) {
1063 // Either the class was not cached yet, or there are optional parameters. 1137 // Either the class was not cached yet, or there are optional parameters.
1064 // Create a new closure class. 1138 // Create a new closure class.
1065 SourceString name = const SourceString("BoundClosure"); 1139 SourceString name = const SourceString("BoundClosure");
1066 ClassElement closureClassElement = new ClosureClassElement( 1140 ClassElement closureClassElement = new ClosureClassElement(
1067 name, compiler, member, member.getCompilationUnit()); 1141 name, compiler, member, member.getCompilationUnit());
1068 String mangledName = namer.getName(closureClassElement); 1142 String mangledName = namer.getName(closureClassElement);
1069 String superName = namer.getName(closureClassElement.superclass); 1143 String superName = namer.getName(closureClassElement.superclass);
1070 needsClosureClass = true; 1144 needsClosureClass = true;
1071 1145
1072 // Define the constructor with a name so that Object.toString can 1146 // Define the constructor with a name so that Object.toString can
1073 // find the class name of the closure class. 1147 // find the class name of the closure class.
1074 emitBoundClosureClassHeader(mangledName, superName, boundClosureBuffer); 1148 emitBoundClosureClassHeader(
1149 mangledName, superName, extraArgWithoutComma, boundClosureBuffer);
1075 // Now add the methods on the closure class. The instance method does not 1150 // Now add the methods on the closure class. The instance method does not
1076 // have the correct name. Since [addParameterStubs] use the name to create 1151 // have the correct name. Since [addParameterStubs] use the name to create
1077 // its stubs we simply create a fake element with the correct name. 1152 // its stubs we simply create a fake element with the correct name.
1078 // Note: the callElement will not have any enclosingElement. 1153 // Note: the callElement will not have any enclosingElement.
1079 FunctionElement callElement = 1154 FunctionElement callElement =
1080 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); 1155 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member);
1081 1156
1082 String invocationName = namer.instanceMethodName(callElement); 1157 String invocationName = namer.instanceMethodName(callElement);
1083 List<String> arguments = new List<String>(parameterCount); 1158 List<String> arguments = new List<String>(parameterCount);
1084 for (int i = 0; i < parameterCount; i++) { 1159 for (int i = 0; i < parameterCount; i++) {
1085 arguments[i] = "p$i"; 1160 arguments[i] = "p$i";
1086 } 1161 }
1087 String joinedArgs = Strings.join(arguments, ", "); 1162 String joinedArgs = Strings.join(arguments, ", ");
1088 boundClosureBuffer.add( 1163 boundClosureBuffer.add(
1089 "$invocationName: function($joinedArgs) {"); 1164 "$invocationName: function($joinedArgs) {");
1090 boundClosureBuffer.add(" return this.self[this.target]($joinedArgs);"); 1165 boundClosureBuffer.add(
1166 " return this.self[this.target]($extraArgWithThis$joinedArgs);");
1091 boundClosureBuffer.add(" }"); 1167 boundClosureBuffer.add(" }");
1092 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { 1168 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) {
1093 boundClosureBuffer.add(',\n $stubName: $memberValue'); 1169 boundClosureBuffer.add(',\n $stubName: $memberValue');
1094 }); 1170 });
1095 boundClosureBuffer.add("\n};\n"); 1171 boundClosureBuffer.add("\n};\n");
1096 1172
1097 closureClass = namer.isolateAccess(closureClassElement); 1173 closureClass = namer.isolateAccess(closureClassElement);
1098 1174
1099 // Cache it. 1175 // Cache it.
1100 if (!hasOptionalParameters) { 1176 if (!hasOptionalParameters) {
1101 boundClosureCache[parameterCount] = closureClass; 1177 cache[parameterCount] = closureClass;
1102 } 1178 }
1103 } 1179 }
1104 1180
1105 // And finally the getter. 1181 // And finally the getter.
1106 String getterName = namer.getterName(member.getLibrary(), member.name); 1182 String getterName = namer.getterName(member.getLibrary(), member.name);
1107 String targetName = namer.instanceMethodName(member); 1183 String targetName = namer.instanceMethodName(member);
1108 CodeBuffer getterBuffer = new CodeBuffer(); 1184 CodeBuffer getterBuffer = new CodeBuffer();
1109 getterBuffer.add( 1185 getterBuffer.add("function($extraArgWithoutComma) "
1110 "function() { return new $closureClass(this, '$targetName'); }"); 1186 "{ return new $closureClass(this, $extraArg'$targetName'); }");
1111 defineInstanceMember(getterName, getterBuffer); 1187 defineInstanceMember(getterName, getterBuffer);
1112 } 1188 }
1113 1189
1114 /** 1190 /**
1115 * Documentation wanted -- johnniwinther 1191 * Documentation wanted -- johnniwinther
1116 * 1192 *
1117 * Invariant: [member] must be a declaration element. 1193 * Invariant: [member] must be a declaration element.
1118 */ 1194 */
1119 void emitCallStubForGetter(Element member, 1195 void emitCallStubForGetter(Element member,
1120 Set<Selector> selectors, 1196 Set<Selector> selectors,
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
1584 const String HOOKS_API_USAGE = """ 1660 const String HOOKS_API_USAGE = """
1585 // Generated by dart2js, the Dart to JavaScript compiler. 1661 // Generated by dart2js, the Dart to JavaScript compiler.
1586 // The code supports the following hooks: 1662 // The code supports the following hooks:
1587 // dartPrint(message) - if this function is defined it is called 1663 // dartPrint(message) - if this function is defined it is called
1588 // instead of the Dart [print] method. 1664 // instead of the Dart [print] method.
1589 // dartMainRunner(main) - if this function is defined, the Dart [main] 1665 // dartMainRunner(main) - if this function is defined, the Dart [main]
1590 // method will not be invoked directly. 1666 // method will not be invoked directly.
1591 // Instead, a closure that will invoke [main] is 1667 // Instead, a closure that will invoke [main] is
1592 // passed to [dartMainRunner]. 1668 // passed to [dartMainRunner].
1593 """; 1669 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698