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

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

Issue 2820143004: Remove Compiler and JavaScriptBackend from class_stub_generator (Closed)
Patch Set: Created 3 years, 8 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.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) 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 library dart2js.js_emitter.class_stub_generator; 5 library dart2js.js_emitter.class_stub_generator;
6 6
7 import '../common/names.dart' show Identifiers; 7 import '../common/names.dart' show Identifiers;
8 import '../compiler.dart' show Compiler; 8 import '../common_elements.dart' show CommonElements;
9 import '../elements/entities.dart'; 9 import '../elements/entities.dart';
10 import '../js/js.dart' as jsAst; 10 import '../js/js.dart' as jsAst;
11 import '../js/js.dart' show js; 11 import '../js/js.dart' show js;
12 import '../js_backend/js_backend.dart' show JavaScriptBackend, Namer; 12 import '../js_backend/namer.dart' show Namer;
13 import '../js_backend/interceptor_data.dart' show InterceptorData;
14 import '../options.dart';
13 import '../universe/selector.dart' show Selector; 15 import '../universe/selector.dart' show Selector;
14 import '../universe/world_builder.dart' 16 import '../universe/world_builder.dart'
15 show CodegenWorldBuilder, SelectorConstraints; 17 show CodegenWorldBuilder, SelectorConstraints;
16 import '../world.dart' show ClosedWorld; 18 import '../world.dart' show ClosedWorld;
17 19
20 import 'code_emitter_task.dart';
18 import 'model.dart'; 21 import 'model.dart';
19 22
20 class ClassStubGenerator { 23 class ClassStubGenerator {
21 final Namer namer; 24 final Namer _namer;
22 final JavaScriptBackend backend; 25 final CodegenWorldBuilder _worldBuilder;
23 final CodegenWorldBuilder worldBuilder; 26 final ClosedWorld _closedWorld;
24 final ClosedWorld closedWorld; 27 final InterceptorData _interceptorData;
25 final bool enableMinification; 28 final bool enableMinification;
29 final Emitter _emitter;
30 final CommonElements _commonElements;
26 31
27 ClassStubGenerator( 32 ClassStubGenerator(this._emitter, this._commonElements, this._namer,
28 this.namer, this.backend, this.worldBuilder, this.closedWorld, 33 this._worldBuilder, this._interceptorData, this._closedWorld,
29 {this.enableMinification}); 34 {this.enableMinification});
30 35
31 jsAst.Expression generateClassConstructor( 36 jsAst.Expression generateClassConstructor(
32 ClassEntity classElement, Iterable<jsAst.Name> fields, bool hasRtiField) { 37 ClassEntity classElement, Iterable<jsAst.Name> fields, bool hasRtiField) {
33 // TODO(sra): Implement placeholders in VariableDeclaration position: 38 // TODO(sra): Implement placeholders in VariableDeclaration position:
34 // 39 //
35 // String constructorName = namer.getNameOfClass(classElement); 40 // String constructorName = namer.getNameOfClass(classElement);
36 // return js.statement('function #(#) { #; }', 41 // return js.statement('function #(#) { #; }',
37 // [ constructorName, fields, 42 // [ constructorName, fields,
38 // fields.map( 43 // fields.map(
39 // (name) => js('this.# = #', [name, name]))])); 44 // (name) => js('this.# = #', [name, name]))]));
40 var typeParameters = const <jsAst.Parameter>[]; 45 var typeParameters = const <jsAst.Parameter>[];
41 var typeInits = const <jsAst.Expression>[]; 46 var typeInits = const <jsAst.Expression>[];
42 if (hasRtiField) { 47 if (hasRtiField) {
43 var rtiName = namer.rtiFieldJsName; 48 var rtiName = _namer.rtiFieldJsName;
44 typeParameters = rtiName; 49 typeParameters = rtiName;
45 typeInits = js('this.# = #', [rtiName, rtiName]); 50 typeInits = js('this.# = #', [rtiName, rtiName]);
46 } 51 }
47 return js('function(#, #) { #; #; this.#();}', [ 52 return js('function(#, #) { #; #; this.#();}', [
48 fields, 53 fields,
49 typeParameters, 54 typeParameters,
50 fields.map((name) => js('this.# = #', [name, name])), 55 fields.map((name) => js('this.# = #', [name, name])),
51 typeInits, 56 typeInits,
52 namer.deferredAction 57 _namer.deferredAction
53 ]); 58 ]);
54 } 59 }
55 60
56 jsAst.Expression generateGetter(MemberEntity member, jsAst.Name fieldName) { 61 jsAst.Expression generateGetter(MemberEntity member, jsAst.Name fieldName) {
57 ClassEntity cls = member.enclosingClass; 62 ClassEntity cls = member.enclosingClass;
58 String receiver = 63 String receiver =
59 backend.interceptorData.isInterceptedClass(cls) ? 'receiver' : 'this'; 64 _interceptorData.isInterceptedClass(cls) ? 'receiver' : 'this';
60 List<String> args = 65 List<String> args =
61 backend.interceptorData.isInterceptedMethod(member) ? ['receiver'] : []; 66 _interceptorData.isInterceptedMethod(member) ? ['receiver'] : [];
62 return js('function(#) { return #.# }', [args, receiver, fieldName]); 67 return js('function(#) { return #.# }', [args, receiver, fieldName]);
63 } 68 }
64 69
65 jsAst.Expression generateSetter(MemberEntity member, jsAst.Name fieldName) { 70 jsAst.Expression generateSetter(MemberEntity member, jsAst.Name fieldName) {
66 ClassEntity cls = member.enclosingClass; 71 ClassEntity cls = member.enclosingClass;
67 String receiver = 72 String receiver =
68 backend.interceptorData.isInterceptedClass(cls) ? 'receiver' : 'this'; 73 _interceptorData.isInterceptedClass(cls) ? 'receiver' : 'this';
69 List<String> args = 74 List<String> args =
70 backend.interceptorData.isInterceptedMethod(member) ? ['receiver'] : []; 75 _interceptorData.isInterceptedMethod(member) ? ['receiver'] : [];
71 // TODO(floitsch): remove 'return'? 76 // TODO(floitsch): remove 'return'?
72 return js( 77 return js(
73 'function(#, v) { return #.# = v; }', [args, receiver, fieldName]); 78 'function(#, v) { return #.# = v; }', [args, receiver, fieldName]);
74 } 79 }
75 80
76 /** 81 /**
77 * Documentation wanted -- johnniwinther 82 * Documentation wanted -- johnniwinther
78 * 83 *
79 * Invariant: [member] must be a declaration element. 84 * Invariant: [member] must be a declaration element.
80 */ 85 */
81 Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter( 86 Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter(
82 MemberEntity member, Map<Selector, SelectorConstraints> selectors) { 87 MemberEntity member, Map<Selector, SelectorConstraints> selectors) {
83 // If the method is intercepted, the stub gets the 88 // If the method is intercepted, the stub gets the
84 // receiver explicitely and we need to pass it to the getter call. 89 // receiver explicitely and we need to pass it to the getter call.
85 bool isInterceptedMethod = 90 bool isInterceptedMethod = _interceptorData.isInterceptedMethod(member);
86 backend.interceptorData.isInterceptedMethod(member);
87 bool isInterceptedClass = 91 bool isInterceptedClass =
88 backend.interceptorData.isInterceptedClass(member.enclosingClass); 92 _interceptorData.isInterceptedClass(member.enclosingClass);
89 93
90 const String receiverArgumentName = r'$receiver'; 94 const String receiverArgumentName = r'$receiver';
91 95
92 jsAst.Expression buildGetter() { 96 jsAst.Expression buildGetter() {
93 jsAst.Expression receiver = 97 jsAst.Expression receiver =
94 js(isInterceptedClass ? receiverArgumentName : 'this'); 98 js(isInterceptedClass ? receiverArgumentName : 'this');
95 if (member.isGetter) { 99 if (member.isGetter) {
96 jsAst.Name getterName = namer.getterForElement(member); 100 jsAst.Name getterName = _namer.getterForElement(member);
97 if (isInterceptedMethod) { 101 if (isInterceptedMethod) {
98 return js('this.#(#)', [getterName, receiver]); 102 return js('this.#(#)', [getterName, receiver]);
99 } 103 }
100 return js('#.#()', [receiver, getterName]); 104 return js('#.#()', [receiver, getterName]);
101 } else { 105 } else {
102 jsAst.Name fieldName = namer.instanceFieldPropertyName(member); 106 jsAst.Name fieldName = _namer.instanceFieldPropertyName(member);
103 return js('#.#', [receiver, fieldName]); 107 return js('#.#', [receiver, fieldName]);
104 } 108 }
105 } 109 }
106 110
107 Map<jsAst.Name, jsAst.Expression> generatedStubs = 111 Map<jsAst.Name, jsAst.Expression> generatedStubs =
108 <jsAst.Name, jsAst.Expression>{}; 112 <jsAst.Name, jsAst.Expression>{};
109 113
110 // Two selectors may match but differ only in type. To avoid generating 114 // Two selectors may match but differ only in type. To avoid generating
111 // identical stubs for each we track untyped selectors which already have 115 // identical stubs for each we track untyped selectors which already have
112 // stubs. 116 // stubs.
113 Set<Selector> generatedSelectors = new Set<Selector>(); 117 Set<Selector> generatedSelectors = new Set<Selector>();
114 for (Selector selector in selectors.keys) { 118 for (Selector selector in selectors.keys) {
115 if (generatedSelectors.contains(selector)) continue; 119 if (generatedSelectors.contains(selector)) continue;
116 if (!selector.appliesUnnamed(member)) continue; 120 if (!selector.appliesUnnamed(member)) continue;
117 if (selectors[selector].applies(member, selector, closedWorld)) { 121 if (selectors[selector].applies(member, selector, _closedWorld)) {
118 generatedSelectors.add(selector); 122 generatedSelectors.add(selector);
119 123
120 jsAst.Name invocationName = namer.invocationName(selector); 124 jsAst.Name invocationName = _namer.invocationName(selector);
121 Selector callSelector = new Selector.callClosureFrom(selector); 125 Selector callSelector = new Selector.callClosureFrom(selector);
122 jsAst.Name closureCallName = namer.invocationName(callSelector); 126 jsAst.Name closureCallName = _namer.invocationName(callSelector);
123 127
124 List<jsAst.Parameter> parameters = <jsAst.Parameter>[]; 128 List<jsAst.Parameter> parameters = <jsAst.Parameter>[];
125 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 129 List<jsAst.Expression> arguments = <jsAst.Expression>[];
126 if (isInterceptedMethod) { 130 if (isInterceptedMethod) {
127 parameters.add(new jsAst.Parameter(receiverArgumentName)); 131 parameters.add(new jsAst.Parameter(receiverArgumentName));
128 } 132 }
129 133
130 for (int i = 0; i < selector.argumentCount; i++) { 134 for (int i = 0; i < selector.argumentCount; i++) {
131 String name = 'arg$i'; 135 String name = 'arg$i';
132 parameters.add(new jsAst.Parameter(name)); 136 parameters.add(new jsAst.Parameter(name));
133 arguments.add(js('#', name)); 137 arguments.add(js('#', name));
134 } 138 }
135 139
136 jsAst.Fun function = js('function(#) { return #.#(#); }', 140 jsAst.Fun function = js('function(#) { return #.#(#); }',
137 [parameters, buildGetter(), closureCallName, arguments]); 141 [parameters, buildGetter(), closureCallName, arguments]);
138 142
139 generatedStubs[invocationName] = function; 143 generatedStubs[invocationName] = function;
140 } 144 }
141 } 145 }
142 146
143 return generatedStubs; 147 return generatedStubs;
144 } 148 }
145 149
146 Map<jsAst.Name, Selector> computeSelectorsForNsmHandlers() { 150 Map<jsAst.Name, Selector> computeSelectorsForNsmHandlers() {
147 Map<jsAst.Name, Selector> jsNames = <jsAst.Name, Selector>{}; 151 Map<jsAst.Name, Selector> jsNames = <jsAst.Name, Selector>{};
148 152
149 // Do not generate no such method handlers if there is no class. 153 // Do not generate no such method handlers if there is no class.
150 if (worldBuilder.directlyInstantiatedClasses.isEmpty) { 154 if (_worldBuilder.directlyInstantiatedClasses.isEmpty) {
151 return jsNames; 155 return jsNames;
152 } 156 }
153 157
154 void addNoSuchMethodHandlers( 158 void addNoSuchMethodHandlers(
155 String ignore, Map<Selector, SelectorConstraints> selectors) { 159 String ignore, Map<Selector, SelectorConstraints> selectors) {
156 for (Selector selector in selectors.keys) { 160 for (Selector selector in selectors.keys) {
157 SelectorConstraints maskSet = selectors[selector]; 161 SelectorConstraints maskSet = selectors[selector];
158 if (maskSet.needsNoSuchMethodHandling(selector, closedWorld)) { 162 if (maskSet.needsNoSuchMethodHandling(selector, _closedWorld)) {
159 jsAst.Name jsName = namer.invocationMirrorInternalName(selector); 163 jsAst.Name jsName = _namer.invocationMirrorInternalName(selector);
160 jsNames[jsName] = selector; 164 jsNames[jsName] = selector;
161 } 165 }
162 } 166 }
163 } 167 }
164 168
165 worldBuilder.forEachInvokedName(addNoSuchMethodHandlers); 169 _worldBuilder.forEachInvokedName(addNoSuchMethodHandlers);
166 worldBuilder.forEachInvokedGetter(addNoSuchMethodHandlers); 170 _worldBuilder.forEachInvokedGetter(addNoSuchMethodHandlers);
167 worldBuilder.forEachInvokedSetter(addNoSuchMethodHandlers); 171 _worldBuilder.forEachInvokedSetter(addNoSuchMethodHandlers);
168 return jsNames; 172 return jsNames;
169 } 173 }
170 174
171 StubMethod generateStubForNoSuchMethod(jsAst.Name name, Selector selector) { 175 StubMethod generateStubForNoSuchMethod(jsAst.Name name, Selector selector) {
172 // Values match JSInvocationMirror in js-helper library. 176 // Values match JSInvocationMirror in js-helper library.
173 int type = selector.invocationMirrorKind; 177 int type = selector.invocationMirrorKind;
174 List<String> parameterNames = 178 List<String> parameterNames =
175 new List.generate(selector.argumentCount, (i) => '\$$i'); 179 new List.generate(selector.argumentCount, (i) => '\$$i');
176 180
177 List<jsAst.Expression> argNames = selector.callStructure 181 List<jsAst.Expression> argNames = selector.callStructure
178 .getOrderedNamedArguments() 182 .getOrderedNamedArguments()
179 .map((String name) => js.string(name)) 183 .map((String name) => js.string(name))
180 .toList(); 184 .toList();
181 185
182 jsAst.Name methodName = namer.asName(selector.invocationMirrorMemberName); 186 jsAst.Name methodName = _namer.asName(selector.invocationMirrorMemberName);
183 jsAst.Name internalName = namer.invocationMirrorInternalName(selector); 187 jsAst.Name internalName = _namer.invocationMirrorInternalName(selector);
184 188
185 assert( 189 assert(_interceptorData.isInterceptedName(Identifiers.noSuchMethod_));
186 backend.interceptorData.isInterceptedName(Identifiers.noSuchMethod_)); 190 bool isIntercepted = _interceptorData.isInterceptedName(selector.name);
187 bool isIntercepted =
188 backend.interceptorData.isInterceptedName(selector.name);
189 jsAst.Expression expression = js( 191 jsAst.Expression expression = js(
190 '''this.#noSuchMethodName(#receiver, 192 '''this.#noSuchMethodName(#receiver,
191 #createInvocationMirror(#methodName, 193 #createInvocationMirror(#methodName,
192 #internalName, 194 #internalName,
193 #type, 195 #type,
194 #arguments, 196 #arguments,
195 #namedArguments))''', 197 #namedArguments))''',
196 { 198 {
197 'receiver': isIntercepted ? r'$receiver' : 'this', 199 'receiver': isIntercepted ? r'$receiver' : 'this',
198 'noSuchMethodName': namer.noSuchMethodName, 200 'noSuchMethodName': _namer.noSuchMethodName,
199 'createInvocationMirror': backend.emitter.staticFunctionAccess( 201 'createInvocationMirror': _emitter
200 backend.commonElements.createInvocationMirror), 202 .staticFunctionAccess(_commonElements.createInvocationMirror),
201 'methodName': 203 'methodName':
202 js.quoteName(enableMinification ? internalName : methodName), 204 js.quoteName(enableMinification ? internalName : methodName),
203 'internalName': js.quoteName(internalName), 205 'internalName': js.quoteName(internalName),
204 'type': js.number(type), 206 'type': js.number(type),
205 'arguments': 207 'arguments':
206 new jsAst.ArrayInitializer(parameterNames.map(js).toList()), 208 new jsAst.ArrayInitializer(parameterNames.map(js).toList()),
207 'namedArguments': new jsAst.ArrayInitializer(argNames) 209 'namedArguments': new jsAst.ArrayInitializer(argNames)
208 }); 210 });
209 211
210 jsAst.Expression function; 212 jsAst.Expression function;
(...skipping 14 matching lines...) Expand all
225 /// `tearOff` takes the following arguments: 227 /// `tearOff` takes the following arguments:
226 /// * `funcs`: a list of functions. These are the functions representing the 228 /// * `funcs`: a list of functions. These are the functions representing the
227 /// member that is torn off. There can be more than one, since a member 229 /// member that is torn off. There can be more than one, since a member
228 /// can have several stubs. 230 /// can have several stubs.
229 /// Each function must have the `$callName` property set. 231 /// Each function must have the `$callName` property set.
230 /// * `reflectionInfo`: contains reflective information, and the function 232 /// * `reflectionInfo`: contains reflective information, and the function
231 /// type. TODO(floitsch): point to where this is specified. 233 /// type. TODO(floitsch): point to where this is specified.
232 /// * `isStatic`. 234 /// * `isStatic`.
233 /// * `name`. 235 /// * `name`.
234 /// * `isIntercepted. 236 /// * `isIntercepted.
235 List<jsAst.Statement> buildTearOffCode(JavaScriptBackend backend) { 237 List<jsAst.Statement> buildTearOffCode(CompilerOptions options, Emitter emitter,
236 Namer namer = backend.namer; 238 Namer namer, CommonElements commonElements) {
237 Compiler compiler = backend.compiler; 239 FunctionEntity closureFromTearOff = commonElements.closureFromTearOff;
238
239 FunctionEntity closureFromTearOff = backend.commonElements.closureFromTearOff;
240 jsAst.Expression tearOffAccessExpression; 240 jsAst.Expression tearOffAccessExpression;
241 jsAst.Expression tearOffGlobalObjectString; 241 jsAst.Expression tearOffGlobalObjectString;
242 jsAst.Expression tearOffGlobalObject; 242 jsAst.Expression tearOffGlobalObject;
243 if (closureFromTearOff != null) { 243 if (closureFromTearOff != null) {
244 tearOffAccessExpression = 244 tearOffAccessExpression = emitter.staticFunctionAccess(closureFromTearOff);
245 backend.emitter.staticFunctionAccess(closureFromTearOff);
246 tearOffGlobalObject = 245 tearOffGlobalObject =
247 js.stringPart(namer.globalObjectForMethod(closureFromTearOff)); 246 js.stringPart(namer.globalObjectForMethod(closureFromTearOff));
248 tearOffGlobalObjectString = 247 tearOffGlobalObjectString =
249 js.string(namer.globalObjectForMethod(closureFromTearOff)); 248 js.string(namer.globalObjectForMethod(closureFromTearOff));
250 } else { 249 } else {
251 // Default values for mocked-up test libraries. 250 // Default values for mocked-up test libraries.
252 tearOffAccessExpression = 251 tearOffAccessExpression =
253 js(r'''function() { throw "Helper 'closureFromTearOff' missing." }'''); 252 js(r'''function() { throw "Helper 'closureFromTearOff' missing." }''');
254 tearOffGlobalObjectString = js.string('MissingHelperFunction'); 253 tearOffGlobalObjectString = js.string('MissingHelperFunction');
255 tearOffGlobalObject = js( 254 tearOffGlobalObject = js(
256 r'''(function() { throw "Helper 'closureFromTearOff' missing." })()'''); 255 r'''(function() { throw "Helper 'closureFromTearOff' missing." })()''');
257 } 256 }
258 257
259 jsAst.Statement tearOffGetter; 258 jsAst.Statement tearOffGetter;
260 if (!compiler.options.useContentSecurityPolicy) { 259 if (!options.useContentSecurityPolicy) {
261 jsAst.Expression tearOffAccessText = new jsAst.UnparsedNode( 260 jsAst.Expression tearOffAccessText =
262 tearOffAccessExpression, compiler.options, false); 261 new jsAst.UnparsedNode(tearOffAccessExpression, options, false);
263 tearOffGetter = js.statement( 262 tearOffGetter = js.statement(
264 ''' 263 '''
265 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) { 264 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
266 return isIntercepted 265 return isIntercepted
267 ? new Function("funcs", "reflectionInfo", "name", 266 ? new Function("funcs", "reflectionInfo", "name",
268 #tearOffGlobalObjectString, "c", 267 #tearOffGlobalObjectString, "c",
269 "return function tearOff_" + name + (functionCounter++) + "(x) {" + 268 "return function tearOff_" + name + (functionCounter++) + "(x) {" +
270 "if (c === null) c = " + #tearOffAccessText + "(" + 269 "if (c === null) c = " + #tearOffAccessText + "(" +
271 "this, funcs, reflectionInfo, false, [x], name);" + 270 "this, funcs, reflectionInfo, false, [x], name);" +
272 "return new c(this, funcs[0], x, name);" + 271 "return new c(this, funcs[0], x, name);" +
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 if (cache === void 0) cache = #tearOff( 312 if (cache === void 0) cache = #tearOff(
314 this, funcs, reflectionInfo, true, [], name).prototype; 313 this, funcs, reflectionInfo, true, [], name).prototype;
315 return cache; 314 return cache;
316 } 315 }
317 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted); 316 : tearOffGetter(funcs, reflectionInfo, name, isIntercepted);
318 }''', 317 }''',
319 {'tearOff': tearOffAccessExpression}); 318 {'tearOff': tearOffAccessExpression});
320 319
321 return <jsAst.Statement>[tearOffGetter, tearOff]; 320 return <jsAst.Statement>[tearOffGetter, tearOff];
322 } 321 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698