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

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

Powered by Google App Engine
This is Rietveld 408576698