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

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

Issue 2810223002: Remove Compiler and JavaScriptBackend from parameter_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/program_builder/program_builder.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) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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.parameter_stub_generator; 5 library dart2js.js_emitter.parameter_stub_generator;
6 6
7 import '../closure.dart' show ClosureClassElement; 7 import '../closure.dart' show ClosureClassElement;
8 import '../common.dart'; 8 import '../common.dart';
9 import '../compiler.dart' show Compiler; 9 import '../common_elements.dart';
10 import '../constants/values.dart'; 10 import '../constants/values.dart';
11 import '../elements/elements.dart' 11 import '../elements/elements.dart'
12 show 12 show
13 ClassElement, 13 ClassElement,
14 FunctionElement, 14 FunctionElement,
15 FunctionSignature, 15 FunctionSignature,
16 MethodElement, 16 MethodElement,
17 ParameterElement; 17 ParameterElement;
18 import '../js/js.dart' as jsAst; 18 import '../js/js.dart' as jsAst;
19 import '../js/js.dart' show js; 19 import '../js/js.dart' show js;
20 import '../js_backend/js_backend.dart' 20 import '../js_backend/constant_handler_javascript.dart'
21 show JavaScriptBackend, JavaScriptConstantCompiler, Namer; 21 show JavaScriptConstantCompiler;
22 import '../js_backend/namer.dart' show Namer;
23 import '../js_backend/native_data.dart';
24 import '../js_backend/interceptor_data.dart';
22 import '../universe/call_structure.dart' show CallStructure; 25 import '../universe/call_structure.dart' show CallStructure;
23 import '../universe/selector.dart' show Selector; 26 import '../universe/selector.dart' show Selector;
24 import '../universe/world_builder.dart' show SelectorConstraints; 27 import '../universe/world_builder.dart'
28 show CodegenWorldBuilder, SelectorConstraints;
25 import '../world.dart' show ClosedWorld; 29 import '../world.dart' show ClosedWorld;
26 30
27 import 'model.dart'; 31 import 'model.dart';
28 32
29 import 'code_emitter_task.dart' show CodeEmitterTask, Emitter; 33 import 'code_emitter_task.dart' show CodeEmitterTask, Emitter;
30 34
31 class ParameterStubGenerator { 35 class ParameterStubGenerator {
32 static final Set<Selector> emptySelectorSet = new Set<Selector>(); 36 static final Set<Selector> emptySelectorSet = new Set<Selector>();
33 37
34 final Namer namer; 38 final CommonElements _commonElements;
35 final Compiler compiler; 39 final CodeEmitterTask _emitterTask;
36 final JavaScriptBackend backend; 40 final JavaScriptConstantCompiler _constants;
37 final ClosedWorld closedWorld; 41 final Namer _namer;
42 final NativeData _nativeData;
43 final InterceptorData _interceptorData;
44 final CodegenWorldBuilder _codegenWorldBuilder;
45 final ClosedWorld _closedWorld;
38 46
39 ParameterStubGenerator( 47 ParameterStubGenerator(
40 this.compiler, this.namer, this.backend, this.closedWorld); 48 this._commonElements,
49 this._emitterTask,
50 this._constants,
51 this._namer,
52 this._nativeData,
53 this._interceptorData,
54 this._codegenWorldBuilder,
55 this._closedWorld);
41 56
42 Emitter get emitter => backend.emitter.emitter; 57 Emitter get _emitter => _emitterTask.emitter;
43 CodeEmitterTask get emitterTask => backend.emitter;
44 DiagnosticReporter get reporter => compiler.reporter;
45 58
46 bool needsSuperGetter(FunctionElement element) => 59 bool needsSuperGetter(FunctionElement element) =>
47 compiler.codegenWorldBuilder.methodsNeedingSuperGetter.contains(element); 60 _codegenWorldBuilder.methodsNeedingSuperGetter.contains(element);
48 61
49 /** 62 /**
50 * Generates stubs to handle invocation of methods with optional 63 * Generates stubs to handle invocation of methods with optional
51 * arguments. 64 * arguments.
52 * 65 *
53 * A method like `foo([x])` may be invoked by the following 66 * A method like `foo([x])` may be invoked by the following
54 * calls: `foo(), foo(1), foo(x: 1)`. This method generates the stub for the 67 * calls: `foo(), foo(1), foo(x: 1)`. This method generates the stub for the
55 * given [selector] and returns the generated [ParameterStubMethod]. 68 * given [selector] and returns the generated [ParameterStubMethod].
56 * 69 *
57 * Returns null if no stub is needed. 70 * Returns null if no stub is needed.
(...skipping 13 matching lines...) Expand all
71 assert(callStructure.isUnnamed); 84 assert(callStructure.isUnnamed);
72 return null; 85 return null;
73 } 86 }
74 if (parameters.optionalParametersAreNamed && 87 if (parameters.optionalParametersAreNamed &&
75 callStructure.namedArgumentCount == parameters.optionalParameterCount) { 88 callStructure.namedArgumentCount == parameters.optionalParameterCount) {
76 // If the selector has the same number of named arguments as the element, 89 // If the selector has the same number of named arguments as the element,
77 // we don't need to add a stub. The call site will hit the method 90 // we don't need to add a stub. The call site will hit the method
78 // directly. 91 // directly.
79 return null; 92 return null;
80 } 93 }
81 JavaScriptConstantCompiler handler = backend.constants;
82 List<String> names = callStructure.getOrderedNamedArguments(); 94 List<String> names = callStructure.getOrderedNamedArguments();
83 95
84 bool isInterceptedMethod = 96 bool isInterceptedMethod = _interceptorData.isInterceptedMethod(member);
85 backend.interceptorData.isInterceptedMethod(member);
86 97
87 // If the method is intercepted, we need to also pass the actual receiver. 98 // If the method is intercepted, we need to also pass the actual receiver.
88 int extraArgumentCount = isInterceptedMethod ? 1 : 0; 99 int extraArgumentCount = isInterceptedMethod ? 1 : 0;
89 // Use '$receiver' to avoid clashes with other parameter names. Using 100 // Use '$receiver' to avoid clashes with other parameter names. Using
90 // '$receiver' works because namer.safeVariableName used for getting 101 // '$receiver' works because namer.safeVariableName used for getting
91 // parameter names never returns a name beginning with a single '$'. 102 // parameter names never returns a name beginning with a single '$'.
92 String receiverArgumentName = r'$receiver'; 103 String receiverArgumentName = r'$receiver';
93 104
94 // The parameters that this stub takes. 105 // The parameters that this stub takes.
95 List<jsAst.Parameter> parametersBuffer = 106 List<jsAst.Parameter> parametersBuffer =
96 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount); 107 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount);
97 // The arguments that will be passed to the real method. 108 // The arguments that will be passed to the real method.
98 List<jsAst.Expression> argumentsBuffer = new List<jsAst.Expression>( 109 List<jsAst.Expression> argumentsBuffer = new List<jsAst.Expression>(
99 parameters.parameterCount + extraArgumentCount); 110 parameters.parameterCount + extraArgumentCount);
100 111
101 int count = 0; 112 int count = 0;
102 if (isInterceptedMethod) { 113 if (isInterceptedMethod) {
103 count++; 114 count++;
104 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName); 115 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
105 argumentsBuffer[0] = js('#', receiverArgumentName); 116 argumentsBuffer[0] = js('#', receiverArgumentName);
106 } 117 }
107 118
108 int optionalParameterStart = positionalArgumentCount + extraArgumentCount; 119 int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
109 // Includes extra receiver argument when using interceptor convention 120 // Includes extra receiver argument when using interceptor convention
110 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1; 121 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1;
111 122
112 parameters.orderedForEachParameter((ParameterElement element) { 123 parameters.orderedForEachParameter((ParameterElement element) {
113 String jsName = backend.namer.safeVariableName(element.name); 124 String jsName = _namer.safeVariableName(element.name);
114 assert(jsName != receiverArgumentName); 125 assert(jsName != receiverArgumentName);
115 if (count < optionalParameterStart) { 126 if (count < optionalParameterStart) {
116 parametersBuffer[count] = new jsAst.Parameter(jsName); 127 parametersBuffer[count] = new jsAst.Parameter(jsName);
117 argumentsBuffer[count] = js('#', jsName); 128 argumentsBuffer[count] = js('#', jsName);
118 } else { 129 } else {
119 int index = names.indexOf(element.name); 130 int index = names.indexOf(element.name);
120 if (index != -1) { 131 if (index != -1) {
121 indexOfLastOptionalArgumentInParameters = count; 132 indexOfLastOptionalArgumentInParameters = count;
122 // The order of the named arguments is not the same as the 133 // The order of the named arguments is not the same as the
123 // one in the real method (which is in Dart source order). 134 // one in the real method (which is in Dart source order).
124 argumentsBuffer[count] = js('#', jsName); 135 argumentsBuffer[count] = js('#', jsName);
125 parametersBuffer[optionalParameterStart + index] = 136 parametersBuffer[optionalParameterStart + index] =
126 new jsAst.Parameter(jsName); 137 new jsAst.Parameter(jsName);
127 } else { 138 } else {
128 ConstantValue value = handler.getConstantValue(element.constant); 139 ConstantValue value = _constants.getConstantValue(element.constant);
129 if (value == null) { 140 if (value == null) {
130 argumentsBuffer[count] = 141 argumentsBuffer[count] =
131 emitter.constantReference(new NullConstantValue()); 142 _emitter.constantReference(new NullConstantValue());
132 } else { 143 } else {
133 if (!value.isNull) { 144 if (!value.isNull) {
134 // If the value is the null constant, we should not pass it 145 // If the value is the null constant, we should not pass it
135 // down to the native method. 146 // down to the native method.
136 indexOfLastOptionalArgumentInParameters = count; 147 indexOfLastOptionalArgumentInParameters = count;
137 } 148 }
138 argumentsBuffer[count] = emitter.constantReference(value); 149 argumentsBuffer[count] = _emitter.constantReference(value);
139 } 150 }
140 } 151 }
141 } 152 }
142 count++; 153 count++;
143 }); 154 });
144 155
145 var body; // List or jsAst.Statement. 156 var body; // List or jsAst.Statement.
146 if (backend.nativeData.hasFixedBackendName(member)) { 157 if (_nativeData.hasFixedBackendName(member)) {
147 body = emitterTask.nativeEmitter.generateParameterStubStatements( 158 body = _emitterTask.nativeEmitter.generateParameterStubStatements(
148 member, 159 member,
149 isInterceptedMethod, 160 isInterceptedMethod,
150 namer.invocationName(selector), 161 _namer.invocationName(selector),
151 parametersBuffer, 162 parametersBuffer,
152 argumentsBuffer, 163 argumentsBuffer,
153 indexOfLastOptionalArgumentInParameters); 164 indexOfLastOptionalArgumentInParameters);
154 } else if (member.isInstanceMember) { 165 } else if (member.isInstanceMember) {
155 if (needsSuperGetter(member)) { 166 if (needsSuperGetter(member)) {
156 ClassElement superClass = member.enclosingClass; 167 ClassElement superClass = member.enclosingClass;
157 jsAst.Name methodName = namer.instanceMethodName(member); 168 jsAst.Name methodName = _namer.instanceMethodName(member);
158 // When redirecting, we must ensure that we don't end up in a subclass. 169 // When redirecting, we must ensure that we don't end up in a subclass.
159 // We thus can't just invoke `this.foo$1.call(filledInArguments)`. 170 // We thus can't just invoke `this.foo$1.call(filledInArguments)`.
160 // Instead we need to call the statically resolved target. 171 // Instead we need to call the statically resolved target.
161 // `<class>.prototype.bar$1.call(this, argument0, ...)`. 172 // `<class>.prototype.bar$1.call(this, argument0, ...)`.
162 body = js.statement('return #.#.call(this, #);', [ 173 body = js.statement('return #.#.call(this, #);', [
163 backend.emitter 174 _emitterTask.prototypeAccess(superClass, hasBeenInstantiated: true),
164 .prototypeAccess(superClass, hasBeenInstantiated: true),
165 methodName, 175 methodName,
166 argumentsBuffer 176 argumentsBuffer
167 ]); 177 ]);
168 } else { 178 } else {
169 body = js.statement('return this.#(#);', 179 body = js.statement('return this.#(#);',
170 [namer.instanceMethodName(member), argumentsBuffer]); 180 [_namer.instanceMethodName(member), argumentsBuffer]);
171 } 181 }
172 } else { 182 } else {
173 body = js.statement('return #(#)', 183 body = js.statement('return #(#)',
174 [emitter.staticFunctionAccess(member), argumentsBuffer]); 184 [_emitter.staticFunctionAccess(member), argumentsBuffer]);
175 } 185 }
176 186
177 jsAst.Fun function = js('function(#) { #; }', [parametersBuffer, body]); 187 jsAst.Fun function = js('function(#) { #; }', [parametersBuffer, body]);
178 188
179 jsAst.Name name = member.isStatic ? null : namer.invocationName(selector); 189 jsAst.Name name = member.isStatic ? null : _namer.invocationName(selector);
180 jsAst.Name callName = 190 jsAst.Name callName =
181 (callSelector != null) ? namer.invocationName(callSelector) : null; 191 (callSelector != null) ? _namer.invocationName(callSelector) : null;
182 return new ParameterStubMethod(name, callName, function); 192 return new ParameterStubMethod(name, callName, function);
183 } 193 }
184 194
185 // We fill the lists depending on possible/invoked selectors. For example, 195 // We fill the lists depending on possible/invoked selectors. For example,
186 // take method foo: 196 // take method foo:
187 // foo(a, b, {c, d}); 197 // foo(a, b, {c, d});
188 // 198 //
189 // We may have multiple ways of calling foo: 199 // We may have multiple ways of calling foo:
190 // (1) foo(1, 2); 200 // (1) foo(1, 2);
191 // (2) foo(1, 2, c: 3); 201 // (2) foo(1, 2, c: 3);
(...skipping 18 matching lines...) Expand all
210 // We need to pay attention if this stub is for a function that has been 220 // We need to pay attention if this stub is for a function that has been
211 // invoked from a subclass. Then we cannot just redirect, since that 221 // invoked from a subclass. Then we cannot just redirect, since that
212 // would invoke the methods of the subclass. We have to compile to: 222 // would invoke the methods of the subclass. We have to compile to:
213 // (1) foo$2(a, b) => MyClass.foo$4$c$d.call(this, a, b, null, null) 223 // (1) foo$2(a, b) => MyClass.foo$4$c$d.call(this, a, b, null, null)
214 // (2) foo$3$c(a, b, c) => MyClass.foo$4$c$d(this, a, b, c, null); 224 // (2) foo$3$c(a, b, c) => MyClass.foo$4$c$d(this, a, b, c, null);
215 // (3) foo$3$d(a, b, d) => MyClass.foo$4$c$d(this, a, b, null, d); 225 // (3) foo$3$d(a, b, d) => MyClass.foo$4$c$d(this, a, b, null, d);
216 List<ParameterStubMethod> generateParameterStubs(MethodElement member, 226 List<ParameterStubMethod> generateParameterStubs(MethodElement member,
217 {bool canTearOff: true}) { 227 {bool canTearOff: true}) {
218 if (member.enclosingElement.isClosure) { 228 if (member.enclosingElement.isClosure) {
219 ClosureClassElement cls = member.enclosingElement; 229 ClosureClassElement cls = member.enclosingElement;
220 if (cls.supertype.element == backend.commonElements.boundClosureClass) { 230 if (cls.supertype.element == _commonElements.boundClosureClass) {
221 reporter.internalError(cls.methodElement, 'Bound closure1.'); 231 throw new SpannableAssertionFailure(
232 cls.methodElement, 'Bound closure1.');
222 } 233 }
223 if (cls.methodElement.isInstanceMember) { 234 if (cls.methodElement.isInstanceMember) {
224 reporter.internalError(cls.methodElement, 'Bound closure2.'); 235 throw new SpannableAssertionFailure(
236 cls.methodElement, 'Bound closure2.');
225 } 237 }
226 } 238 }
227 239
228 // The set of selectors that apply to `member`. For example, for 240 // The set of selectors that apply to `member`. For example, for
229 // a member `foo(x, [y])` the following selectors may apply: 241 // a member `foo(x, [y])` the following selectors may apply:
230 // `foo(x)`, and `foo(x, y)`. 242 // `foo(x)`, and `foo(x, y)`.
231 Map<Selector, SelectorConstraints> selectors; 243 Map<Selector, SelectorConstraints> selectors;
232 // The set of selectors that apply to `member` if it's name was `call`. 244 // The set of selectors that apply to `member` if it's name was `call`.
233 // This happens when a member is torn off. In that case calls to the 245 // This happens when a member is torn off. In that case calls to the
234 // function use the name `call`, and we must be able to handle every 246 // function use the name `call`, and we must be able to handle every
235 // `call` invocation that matches the signature. For example, for 247 // `call` invocation that matches the signature. For example, for
236 // a member `foo(x, [y])` the following selectors would be possible 248 // a member `foo(x, [y])` the following selectors would be possible
237 // call-selectors: `call(x)`, and `call(x, y)`. 249 // call-selectors: `call(x)`, and `call(x, y)`.
238 Map<Selector, SelectorConstraints> callSelectors; 250 Map<Selector, SelectorConstraints> callSelectors;
239 251
240 // Only instance members (not static methods) need stubs. 252 // Only instance members (not static methods) need stubs.
241 if (member.isInstanceMember) { 253 if (member.isInstanceMember) {
242 selectors = compiler.codegenWorldBuilder.invocationsByName(member.name); 254 selectors = _codegenWorldBuilder.invocationsByName(member.name);
243 } 255 }
244 256
245 if (canTearOff) { 257 if (canTearOff) {
246 String call = namer.closureInvocationSelectorName; 258 String call = _namer.closureInvocationSelectorName;
247 callSelectors = compiler.codegenWorldBuilder.invocationsByName(call); 259 callSelectors = _codegenWorldBuilder.invocationsByName(call);
248 } 260 }
249 261
250 assert(emptySelectorSet.isEmpty); 262 assert(emptySelectorSet.isEmpty);
251 if (selectors == null) selectors = const <Selector, SelectorConstraints>{}; 263 if (selectors == null) selectors = const <Selector, SelectorConstraints>{};
252 if (callSelectors == null) 264 if (callSelectors == null)
253 callSelectors = const <Selector, SelectorConstraints>{}; 265 callSelectors = const <Selector, SelectorConstraints>{};
254 266
255 List<ParameterStubMethod> stubs = <ParameterStubMethod>[]; 267 List<ParameterStubMethod> stubs = <ParameterStubMethod>[];
256 268
257 if (selectors.isEmpty && callSelectors.isEmpty) { 269 if (selectors.isEmpty && callSelectors.isEmpty) {
(...skipping 29 matching lines...) Expand all
287 } 299 }
288 } 300 }
289 } 301 }
290 302
291 // Now run through the actual member selectors (eg. `foo$2(x, y)` and not 303 // Now run through the actual member selectors (eg. `foo$2(x, y)` and not
292 // `call$2(x, y)`. Some of them have already been generated because of the 304 // `call$2(x, y)`. Some of them have already been generated because of the
293 // call-selectors (and they are in the renamedCallSelectors set. 305 // call-selectors (and they are in the renamedCallSelectors set.
294 for (Selector selector in selectors.keys) { 306 for (Selector selector in selectors.keys) {
295 if (renamedCallSelectors.contains(selector)) continue; 307 if (renamedCallSelectors.contains(selector)) continue;
296 if (!selector.appliesUnnamed(member)) continue; 308 if (!selector.appliesUnnamed(member)) continue;
297 if (!selectors[selector].applies(member, selector, closedWorld)) { 309 if (!selectors[selector].applies(member, selector, _closedWorld)) {
298 continue; 310 continue;
299 } 311 }
300 312
301 if (untypedSelectors.add(selector)) { 313 if (untypedSelectors.add(selector)) {
302 ParameterStubMethod stub = 314 ParameterStubMethod stub =
303 generateParameterStub(member, selector, null); 315 generateParameterStub(member, selector, null);
304 if (stub != null) { 316 if (stub != null) {
305 stubs.add(stub); 317 stubs.add(stub);
306 } 318 }
307 } 319 }
308 } 320 }
309 321
310 return stubs; 322 return stubs;
311 } 323 }
312 } 324 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698