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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/class_stub_generator.dart

Issue 1198293002: dart2js: Use an abstract Name class for names in the generated JavaScript ast. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix new emitter. Created 5 years, 6 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 dart2js.js_emitter; 5 part of dart2js.js_emitter;
6 6
7 class ClassStubGenerator { 7 class ClassStubGenerator {
8 final Namer namer; 8 final Namer namer;
9 final Compiler compiler; 9 final Compiler compiler;
10 final JavaScriptBackend backend; 10 final JavaScriptBackend backend;
11 11
12 ClassStubGenerator(this.compiler, this.namer, this.backend); 12 ClassStubGenerator(this.compiler, this.namer, this.backend);
13 13
14 jsAst.Expression generateClassConstructor(ClassElement classElement, 14 jsAst.Expression generateClassConstructor(ClassElement classElement,
15 Iterable<String> fields) { 15 Iterable<String> fields) {
16 // TODO(sra): Implement placeholders in VariableDeclaration position: 16 // TODO(sra): Implement placeholders in VariableDeclaration position:
17 // 17 //
18 // String constructorName = namer.getNameOfClass(classElement); 18 // String constructorName = namer.getNameOfClass(classElement);
19 // return js.statement('function #(#) { #; }', 19 // return js.statement('function #(#) { #; }',
20 // [ constructorName, fields, 20 // [ constructorName, fields,
21 // fields.map( 21 // fields.map(
22 // (name) => js('this.# = #', [name, name]))])); 22 // (name) => js('this.# = #', [name, name]))]));
23 return js('function(#) { #; this.#();}', 23 return js('function(#) { #; this.#();}',
24 [fields, 24 [fields,
25 fields.map((name) => js('this.# = #', [name, name])), 25 fields.map((name) => js('this.# = #', [name, name])),
26 namer.deferredAction]); 26 namer.deferredAction]);
27 } 27 }
28 28
29 jsAst.Expression generateGetter(Element member, String fieldName) { 29 jsAst.Expression generateGetter(Element member, jsAst.Name fieldName) {
30 ClassElement cls = member.enclosingClass; 30 ClassElement cls = member.enclosingClass;
31 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; 31 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
32 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; 32 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
33 return js('function(#) { return #.# }', [args, receiver, fieldName]); 33 return js('function(#) { return #.# }', [args, receiver, fieldName]);
34 } 34 }
35 35
36 jsAst.Expression generateSetter(Element member, String fieldName) { 36 jsAst.Expression generateSetter(Element member, jsAst.Name fieldName) {
37 ClassElement cls = member.enclosingClass; 37 ClassElement cls = member.enclosingClass;
38 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this'; 38 String receiver = backend.isInterceptorClass(cls) ? 'receiver' : 'this';
39 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : []; 39 List<String> args = backend.isInterceptedMethod(member) ? ['receiver'] : [];
40 // TODO(floitsch): remove 'return'? 40 // TODO(floitsch): remove 'return'?
41 return js('function(#, v) { return #.# = v; }', 41 return js('function(#, v) { return #.# = v; }',
42 [args, receiver, fieldName]); 42 [args, receiver, fieldName]);
43 } 43 }
44 44
45 /** 45 /**
46 * Documentation wanted -- johnniwinther 46 * Documentation wanted -- johnniwinther
47 * 47 *
48 * Invariant: [member] must be a declaration element. 48 * Invariant: [member] must be a declaration element.
49 */ 49 */
50 Map<String, jsAst.Expression> generateCallStubsForGetter( 50 Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter(
51 Element member, Map<Selector, TypeMaskSet> selectors) { 51 Element member, Map<Selector, TypeMaskSet> selectors) {
52 assert(invariant(member, member.isDeclaration)); 52 assert(invariant(member, member.isDeclaration));
53 53
54 // If the method is intercepted, the stub gets the 54 // If the method is intercepted, the stub gets the
55 // receiver explicitely and we need to pass it to the getter call. 55 // receiver explicitely and we need to pass it to the getter call.
56 bool isInterceptedMethod = backend.isInterceptedMethod(member); 56 bool isInterceptedMethod = backend.isInterceptedMethod(member);
57 bool isInterceptorClass = 57 bool isInterceptorClass =
58 backend.isInterceptorClass(member.enclosingClass); 58 backend.isInterceptorClass(member.enclosingClass);
59 59
60 const String receiverArgumentName = r'$receiver'; 60 const String receiverArgumentName = r'$receiver';
61 61
62 jsAst.Expression buildGetter() { 62 jsAst.Expression buildGetter() {
63 jsAst.Expression receiver = 63 jsAst.Expression receiver =
64 js(isInterceptorClass ? receiverArgumentName : 'this'); 64 js(isInterceptorClass ? receiverArgumentName : 'this');
65 if (member.isGetter) { 65 if (member.isGetter) {
66 String getterName = namer.getterForElement(member); 66 jsAst.Name getterName = namer.getterForElement(member);
67 if (isInterceptedMethod) { 67 if (isInterceptedMethod) {
68 return js('this.#(#)', [getterName, receiver]); 68 return js('this.#(#)', [getterName, receiver]);
69 } 69 }
70 return js('#.#()', [receiver, getterName]); 70 return js('#.#()', [receiver, getterName]);
71 } else { 71 } else {
72 String fieldName = namer.instanceFieldPropertyName(member); 72 jsAst.Name fieldName = namer.instanceFieldPropertyName(member);
73 return js('#.#', [receiver, fieldName]); 73 return js('#.#', [receiver, fieldName]);
74 } 74 }
75 } 75 }
76 76
77 Map<String, jsAst.Expression> generatedStubs = <String, jsAst.Expression>{}; 77 Map<jsAst.Name, jsAst.Expression> generatedStubs =
78 <jsAst.Name, jsAst.Expression>{};
78 79
79 // Two selectors may match but differ only in type. To avoid generating 80 // Two selectors may match but differ only in type. To avoid generating
80 // identical stubs for each we track untyped selectors which already have 81 // identical stubs for each we track untyped selectors which already have
81 // stubs. 82 // stubs.
82 Set<Selector> generatedSelectors = new Set<Selector>(); 83 Set<Selector> generatedSelectors = new Set<Selector>();
83 for (Selector selector in selectors.keys) { 84 for (Selector selector in selectors.keys) {
84 if (generatedSelectors.contains(selector)) continue; 85 if (generatedSelectors.contains(selector)) continue;
85 if (!selector.appliesUnnamed(member, compiler.world)) continue; 86 if (!selector.appliesUnnamed(member, compiler.world)) continue;
86 for (TypeMask mask in selectors[selector].masks) { 87 for (TypeMask mask in selectors[selector].masks) {
87 if (mask != null && 88 if (mask != null &&
88 !mask.canHit(member, selector, compiler.world)) { 89 !mask.canHit(member, selector, compiler.world)) {
89 continue; 90 continue;
90 } 91 }
91 92
92 generatedSelectors.add(selector); 93 generatedSelectors.add(selector);
93 94
94 String invocationName = namer.invocationName(selector); 95 jsAst.Name invocationName = namer.invocationName(selector);
95 Selector callSelector = new Selector.callClosureFrom(selector); 96 Selector callSelector = new Selector.callClosureFrom(selector);
96 String closureCallName = namer.invocationName(callSelector); 97 jsAst.Name closureCallName = namer.invocationName(callSelector);
97 98
98 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 99 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
99 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 100 List<jsAst.Expression> arguments = <jsAst.Expression>[];
100 if (isInterceptedMethod) { 101 if (isInterceptedMethod) {
101 parameters.add(new jsAst.Parameter(receiverArgumentName)); 102 parameters.add(new jsAst.Parameter(receiverArgumentName));
102 } 103 }
103 104
104 for (int i = 0; i < selector.argumentCount; i++) { 105 for (int i = 0; i < selector.argumentCount; i++) {
105 String name = 'arg$i'; 106 String name = 'arg$i';
106 parameters.add(new jsAst.Parameter(name)); 107 parameters.add(new jsAst.Parameter(name));
107 arguments.add(js('#', name)); 108 arguments.add(js('#', name));
108 } 109 }
109 110
110 jsAst.Fun function = js( 111 jsAst.Fun function = js(
111 'function(#) { return #.#(#); }', 112 'function(#) { return #.#(#); }',
112 [ parameters, buildGetter(), closureCallName, arguments]); 113 [ parameters, buildGetter(), closureCallName, arguments]);
113 114
114 generatedStubs[invocationName] = function; 115 generatedStubs[invocationName] = function;
115 } 116 }
116 } 117 }
117 118
118 return generatedStubs; 119 return generatedStubs;
119 } 120 }
120 121
121 Map<String, Selector> computeSelectorsForNsmHandlers() { 122 Map<jsAst.Name, Selector> computeSelectorsForNsmHandlers() {
122 123
123 Map<String, Selector> jsNames = <String, Selector>{}; 124 Map<jsAst.Name, Selector> jsNames = <jsAst.Name, Selector>{};
124 125
125 // Do not generate no such method handlers if there is no class. 126 // Do not generate no such method handlers if there is no class.
126 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) { 127 if (compiler.codegenWorld.directlyInstantiatedClasses.isEmpty) {
127 return jsNames; 128 return jsNames;
128 } 129 }
129 130
130 void addNoSuchMethodHandlers(String ignore, 131 void addNoSuchMethodHandlers(String ignore,
131 Map<Selector, TypeMaskSet> selectors) { 132 Map<Selector, TypeMaskSet> selectors) {
132 TypeMask objectSubclassTypeMask = 133 TypeMask objectSubclassTypeMask =
133 new TypeMask.subclass(compiler.objectClass, compiler.world); 134 new TypeMask.subclass(compiler.objectClass, compiler.world);
134 135
135 for (Selector selector in selectors.keys) { 136 for (Selector selector in selectors.keys) {
136 TypeMaskSet maskSet = selectors[selector]; 137 TypeMaskSet maskSet = selectors[selector];
137 for (TypeMask mask in maskSet.masks) { 138 for (TypeMask mask in maskSet.masks) {
138 if (mask == null) mask = objectSubclassTypeMask; 139 if (mask == null) mask = objectSubclassTypeMask;
139 140
140 if (mask.needsNoSuchMethodHandling(selector, compiler.world)) { 141 if (mask.needsNoSuchMethodHandling(selector, compiler.world)) {
141 String jsName = namer.invocationMirrorInternalName(selector); 142 jsAst.Name jsName = namer.invocationMirrorInternalName(selector);
142 jsNames[jsName] = selector; 143 jsNames[jsName] = selector;
143 break; 144 break;
144 } 145 }
145 } 146 }
146 } 147 }
147 } 148 }
148 149
149 compiler.codegenWorld.forEachInvokedName(addNoSuchMethodHandlers); 150 compiler.codegenWorld.forEachInvokedName(addNoSuchMethodHandlers);
150 compiler.codegenWorld.forEachInvokedGetter(addNoSuchMethodHandlers); 151 compiler.codegenWorld.forEachInvokedGetter(addNoSuchMethodHandlers);
151 compiler.codegenWorld.forEachInvokedSetter(addNoSuchMethodHandlers); 152 compiler.codegenWorld.forEachInvokedSetter(addNoSuchMethodHandlers);
152 return jsNames; 153 return jsNames;
153 } 154 }
154 155
155 StubMethod generateStubForNoSuchMethod(String name, Selector selector) { 156 StubMethod generateStubForNoSuchMethod(jsAst.Name name,
157 Selector selector) {
156 // Values match JSInvocationMirror in js-helper library. 158 // Values match JSInvocationMirror in js-helper library.
157 int type = selector.invocationMirrorKind; 159 int type = selector.invocationMirrorKind;
158 List<String> parameterNames = 160 List<String> parameterNames =
159 new List.generate(selector.argumentCount, (i) => '\$$i'); 161 new List.generate(selector.argumentCount, (i) => '\$$i');
160 162
161 List<jsAst.Expression> argNames = 163 List<jsAst.Expression> argNames =
162 selector.callStructure.getOrderedNamedArguments().map((String name) => 164 selector.callStructure.getOrderedNamedArguments().map((String name) =>
163 js.string(name)).toList(); 165 js.string(name)).toList();
164 166
165 String methodName = selector.invocationMirrorMemberName; 167 jsAst.Name methodName = namer.asName(selector.invocationMirrorMemberName);
166 String internalName = namer.invocationMirrorInternalName(selector); 168 jsAst.Name internalName = namer.invocationMirrorInternalName(selector);
167 169
168 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD)); 170 assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
169 jsAst.Expression expression = 171 jsAst.Expression expression =
170 js('''this.#noSuchMethodName(this, 172 js('''this.#noSuchMethodName(this,
171 #createInvocationMirror(#methodName, 173 #createInvocationMirror(#methodName,
172 #internalName, 174 #internalName,
173 #type, 175 #type,
174 #arguments, 176 #arguments,
175 #namedArguments))''', 177 #namedArguments))''',
176 {'noSuchMethodName': namer.noSuchMethodName, 178 {'noSuchMethodName': namer.noSuchMethodName,
177 'createInvocationMirror': 179 'createInvocationMirror':
178 backend.emitter.staticFunctionAccess( 180 backend.emitter.staticFunctionAccess(
179 backend.getCreateInvocationMirror()), 181 backend.getCreateInvocationMirror()),
180 'methodName': 182 'methodName':
181 js.string(compiler.enableMinification 183 js.quoteName(compiler.enableMinification
182 ? internalName : methodName), 184 ? internalName : methodName),
183 'internalName': js.string(internalName), 185 'internalName': js.quoteName(internalName),
184 'type': js.number(type), 186 'type': js.number(type),
185 'arguments': 187 'arguments':
186 new jsAst.ArrayInitializer(parameterNames.map(js).toList()), 188 new jsAst.ArrayInitializer(parameterNames.map(js).toList()),
187 'namedArguments': new jsAst.ArrayInitializer(argNames)}); 189 'namedArguments': new jsAst.ArrayInitializer(argNames)});
188 190
189 jsAst.Expression function; 191 jsAst.Expression function;
190 if (backend.isInterceptedName(selector.name)) { 192 if (backend.isInterceptedName(selector.name)) {
191 function = js(r'function($receiver, #) { return # }', 193 function = js(r'function($receiver, #) { return # }',
192 [parameterNames, expression]); 194 [parameterNames, expression]);
193 } else { 195 } else {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 ? function() { 289 ? function() {
288 if (cache === void 0) cache = #tearOff( 290 if (cache === void 0) cache = #tearOff(
289 this, funcs, reflectionInfo, true, [], name).prototype; 291 this, funcs, reflectionInfo, true, [], name).prototype;
290 return cache; 292 return cache;
291 } 293 }
292 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted); 294 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
293 }''', {'tearOff': tearOffAccessExpression}); 295 }''', {'tearOff': tearOffAccessExpression});
294 296
295 return <jsAst.Statement>[tearOffGetter, tearOff]; 297 return <jsAst.Statement>[tearOffGetter, tearOff];
296 } 298 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698