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

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

Issue 887853004: dart2js: Move parameterStub generation to parameter_stub_generator and add parameter stubs to model. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Forgot to save container_builder Created 5 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 /// This class should morph into something that makes it easy to build 7 /// This class should morph into something that makes it easy to build
8 /// JavaScript representations of libraries, class-sides, and instance-sides. 8 /// JavaScript representations of libraries, class-sides, and instance-sides.
9 /// Initially, it is just a placeholder for code that is moved from 9 /// Initially, it is just a placeholder for code that is moved from
10 /// [CodeEmitterTask]. 10 /// [CodeEmitterTask].
11 class ContainerBuilder extends CodeEmitterHelper { 11 class ContainerBuilder extends CodeEmitterHelper {
12 bool needsSuperGetter(FunctionElement element) =>
13 compiler.codegenWorld.methodsNeedingSuperGetter.contains(element);
14
15 /**
16 * Generate stubs to handle invocation of methods with optional
17 * arguments.
18 *
19 * A method like [: foo([x]) :] may be invoked by the following
20 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this
21 * function for detailed examples.
22 */
23 void addParameterStub(FunctionElement member,
24 Selector selector,
25 AddStubFunction addStub) {
26 FunctionSignature parameters = member.functionSignature;
27 int positionalArgumentCount = selector.positionalArgumentCount;
28 if (positionalArgumentCount == parameters.parameterCount) {
29 assert(selector.namedArgumentCount == 0);
30 return;
31 }
32 if (parameters.optionalParametersAreNamed
33 && selector.namedArgumentCount == parameters.optionalParameterCount) {
34 // If the selector has the same number of named arguments as the element,
35 // we don't need to add a stub. The call site will hit the method
36 // directly.
37 return;
38 }
39 JavaScriptConstantCompiler handler = backend.constants;
40 List<String> names = selector.getOrderedNamedArguments();
41
42 bool isInterceptedMethod = backend.isInterceptedMethod(member);
43
44 // If the method is intercepted, we need to also pass the actual receiver.
45 int extraArgumentCount = isInterceptedMethod ? 1 : 0;
46 // Use '$receiver' to avoid clashes with other parameter names. Using
47 // '$receiver' works because [:namer.safeName:] used for getting parameter
48 // names never returns a name beginning with a single '$'.
49 String receiverArgumentName = r'$receiver';
50
51 // The parameters that this stub takes.
52 List<jsAst.Parameter> parametersBuffer =
53 new List<jsAst.Parameter>(selector.argumentCount + extraArgumentCount);
54 // The arguments that will be passed to the real method.
55 List<jsAst.Expression> argumentsBuffer =
56 new List<jsAst.Expression>(
57 parameters.parameterCount + extraArgumentCount);
58 String invocationName = namer.invocationName(selector);
59
60 int count = 0;
61 if (isInterceptedMethod) {
62 count++;
63 parametersBuffer[0] = new jsAst.Parameter(receiverArgumentName);
64 argumentsBuffer[0] = js('#', receiverArgumentName);
65 }
66
67 int optionalParameterStart = positionalArgumentCount + extraArgumentCount;
68 // Includes extra receiver argument when using interceptor convention
69 int indexOfLastOptionalArgumentInParameters = optionalParameterStart - 1;
70
71 int parameterIndex = 0;
72 parameters.orderedForEachParameter((ParameterElement element) {
73 String jsName = backend.namer.safeName(element.name);
74 assert(jsName != receiverArgumentName);
75 if (count < optionalParameterStart) {
76 parametersBuffer[count] = new jsAst.Parameter(jsName);
77 argumentsBuffer[count] = js('#', jsName);
78 } else {
79 int index = names.indexOf(element.name);
80 if (index != -1) {
81 indexOfLastOptionalArgumentInParameters = count;
82 // The order of the named arguments is not the same as the
83 // one in the real method (which is in Dart source order).
84 argumentsBuffer[count] = js('#', jsName);
85 parametersBuffer[optionalParameterStart + index] =
86 new jsAst.Parameter(jsName);
87 } else {
88 ConstantExpression constant = handler.getConstantForVariable(element);
89 if (constant == null) {
90 argumentsBuffer[count] =
91 emitter.constantReference(new NullConstantValue());
92 } else {
93 ConstantValue value = constant.value;
94 if (!value.isNull) {
95 // If the value is the null constant, we should not pass it
96 // down to the native method.
97 indexOfLastOptionalArgumentInParameters = count;
98 }
99 argumentsBuffer[count] = emitter.constantReference(value);
100 }
101 }
102 }
103 count++;
104 });
105
106 var body; // List or jsAst.Statement.
107 if (member.hasFixedBackendName) {
108 body = emitter.nativeEmitter.generateParameterStubStatements(
109 member, isInterceptedMethod, invocationName,
110 parametersBuffer, argumentsBuffer,
111 indexOfLastOptionalArgumentInParameters);
112 } else if (member.isInstanceMember) {
113 if (needsSuperGetter(member)) {
114 ClassElement superClass = member.enclosingClass;
115 String methodName = namer.getNameOfInstanceMember(member);
116 // When redirecting, we must ensure that we don't end up in a subclass.
117 // We thus can't just invoke `this.foo$1.call(filledInArguments)`.
118 // Instead we need to call the statically resolved target.
119 // `<class>.prototype.bar$1.call(this, argument0, ...)`.
120 body = js.statement(
121 'return #.#.call(this, #);',
122 [backend.emitter.prototypeAccess(superClass,
123 hasBeenInstantiated: true),
124 methodName,
125 argumentsBuffer]);
126 } else {
127 body = js.statement(
128 'return this.#(#);',
129 [namer.getNameOfInstanceMember(member), argumentsBuffer]);
130 }
131 } else {
132 body = js.statement('return #(#)',
133 [emitter.staticFunctionAccess(member), argumentsBuffer]);
134 }
135
136 jsAst.Fun function = js('function(#) { #; }', [parametersBuffer, body]);
137
138 addStub(selector, function);
139 }
140
141 void addParameterStubs(FunctionElement member, AddStubFunction defineStub,
142 [bool canTearOff = false]) {
143 if (member.enclosingElement.isClosure) {
144 ClosureClassElement cls = member.enclosingElement;
145 if (cls.supertype.element == backend.boundClosureClass) {
146 compiler.internalError(cls.methodElement, 'Bound closure1.');
147 }
148 if (cls.methodElement.isInstanceMember) {
149 compiler.internalError(cls.methodElement, 'Bound closure2.');
150 }
151 }
152
153 // We fill the lists depending on the selector. For example,
154 // take method foo:
155 // foo(a, b, {c, d});
156 //
157 // We may have multiple ways of calling foo:
158 // (1) foo(1, 2);
159 // (2) foo(1, 2, c: 3);
160 // (3) foo(1, 2, d: 4);
161 // (4) foo(1, 2, c: 3, d: 4);
162 // (5) foo(1, 2, d: 4, c: 3);
163 //
164 // What we generate at the call sites are:
165 // (1) foo$2(1, 2);
166 // (2) foo$3$c(1, 2, 3);
167 // (3) foo$3$d(1, 2, 4);
168 // (4) foo$4$c$d(1, 2, 3, 4);
169 // (5) foo$4$c$d(1, 2, 3, 4);
170 //
171 // The stubs we generate are (expressed in Dart):
172 // (1) foo$2(a, b) => foo$4$c$d(a, b, null, null)
173 // (2) foo$3$c(a, b, c) => foo$4$c$d(a, b, c, null);
174 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d);
175 // (4) No stub generated, call is direct.
176 // (5) No stub generated, call is direct.
177 //
178 // We need to pay attention if this stub is for a function that has been
179 // invoked from a subclass. Then we cannot just redirect, since that
180 // would invoke the methods of the subclass. We have to compile to:
181 // (1) foo$2(a, b) => MyClass.foo$4$c$d.call(this, a, b, null, null)
182 // (2) foo$3$c(a, b, c) => MyClass.foo$4$c$d(this, a, b, c, null);
183 // (3) foo$3$d(a, b, d) => MyClass.foo$4$c$d(this, a, b, null, d);
184
185 Set<Selector> selectors = member.isInstanceMember
186 ? compiler.codegenWorld.invokedNames[member.name]
187 : null; // No stubs needed for static methods.
188
189 /// Returns all closure call selectors renamed to match this member.
190 Set<Selector> callSelectorsAsNamed() {
191 if (!canTearOff) return null;
192 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
193 namer.closureInvocationSelectorName];
194 if (callSelectors == null) return null;
195 return callSelectors.map((Selector callSelector) {
196 return new Selector.call(
197 member.name, member.library,
198 callSelector.argumentCount, callSelector.namedArguments);
199 }).toSet();
200 }
201 if (selectors == null) {
202 selectors = callSelectorsAsNamed();
203 if (selectors == null) return;
204 } else {
205 Set<Selector> callSelectors = callSelectorsAsNamed();
206 if (callSelectors != null) {
207 selectors = selectors.union(callSelectors);
208 }
209 }
210 Set<Selector> untypedSelectors = new Set<Selector>();
211 if (selectors != null) {
212 for (Selector selector in selectors) {
213 if (!selector.appliesUnnamed(member, compiler.world)) continue;
214 if (untypedSelectors.add(selector.asUntyped)) {
215 addParameterStub(member, selector, defineStub);
216 }
217 }
218 }
219 if (canTearOff) {
220 selectors = compiler.codegenWorld.invokedNames[
221 namer.closureInvocationSelectorName];
222 if (selectors != null) {
223 for (Selector selector in selectors) {
224 selector = new Selector.call(
225 member.name, member.library,
226 selector.argumentCount, selector.namedArguments);
227 if (!selector.appliesUnnamed(member, compiler.world)) continue;
228 if (untypedSelectors.add(selector)) {
229 addParameterStub(member, selector, defineStub);
230 }
231 }
232 }
233 }
234 }
235 12
236 void addMemberMethod(DartMethod method, ClassBuilder builder) { 13 void addMemberMethod(DartMethod method, ClassBuilder builder) {
237 final FunctionElement member = method.element; 14 final FunctionElement member = method.element;
238 String name = method.name; 15 String name = method.name;
239 final FunctionSignature parameters = member.functionSignature; 16 final FunctionSignature parameters = member.functionSignature;
240 jsAst.Expression code = method.code; 17 jsAst.Expression code = method.code;
241 final bool needsStubs = method.needsStubs; 18 final bool needsStubs = !method.parameterStubs.isEmpty;
herhut 2015/01/30 10:02:22 How about isNotEmpty?
zarah 2015/01/30 12:46:39 Of course! :-)
242 final bool canTearOff = method.needsTearOff; 19 final bool canTearOff = method.needsTearOff;
243 final String tearOffName = method.tearOffName; 20 final String tearOffName = method.tearOffName;
244 final bool canBeReflected = method.canBeReflected; 21 final bool canBeReflected = method.canBeReflected;
245 final bool canBeApplied = method.canBeApplied; 22 final bool canBeApplied = method.canBeApplied;
246 final bool isClosure = method is InstanceMethod && method.isClosure; 23 final bool isClosure = method is InstanceMethod && method.isClosure;
247 final bool hasSuperAlias = method is InstanceMethod && method.hasSuperAlias; 24 final bool hasSuperAlias = method is InstanceMethod && method.hasSuperAlias;
248 25
249 final bool needStructuredInfo = 26 final bool needStructuredInfo =
250 canTearOff || canBeReflected || canBeApplied || hasSuperAlias; 27 canTearOff || canBeReflected || canBeApplied || hasSuperAlias;
251 28
252 emitter.interceptorEmitter.recordMangledNameOfMemberMethod(member, name); 29 emitter.interceptorEmitter.recordMangledNameOfMemberMethod(member, name);
253 30
254 if (!needStructuredInfo) { 31 if (!needStructuredInfo) {
255 compiler.dumpInfoTask.registerElementAst(member, 32 compiler.dumpInfoTask.registerElementAst(member,
256 builder.addProperty(name, code)); 33 builder.addProperty(name, code));
257 if (needsStubs) { 34
258 addParameterStubs( 35 for (ParameterStubMethod method in method.parameterStubs) {
259 member, 36 jsAst.Property property = builder.addProperty(method.name, method.code);
260 (Selector selector, jsAst.Fun function) { 37 compiler.dumpInfoTask.registerElementAst(member, property);
261 String invocationName = namer.invocationName(selector); 38 emitter.interceptorEmitter
262 emitter.interceptorEmitter 39 .recordMangledNameOfMemberMethod(member, method.name);
263 .recordMangledNameOfMemberMethod(member, invocationName);
264 compiler.dumpInfoTask.registerElementAst(member,
265 builder.addProperty(invocationName, function));
266 });
267 } 40 }
268 return; 41 return;
269 } 42 }
270 emitter.needsStructuredMemberInfo = true; 43 emitter.needsStructuredMemberInfo = true;
271 44
272 // This element is needed for reflection or needs additional stubs or has a 45 // This element is needed for reflection or needs additional stubs or has a
273 // super alias. So we need to retain additional information. 46 // super alias. So we need to retain additional information.
274 47
275 // The information is stored in an array with this format: 48 // The information is stored in an array with this format:
276 // 49 //
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 int requiredParameterCount = parameters.requiredParameterCount << 1; 102 int requiredParameterCount = parameters.requiredParameterCount << 1;
330 if (member.isAccessor) requiredParameterCount++; 103 if (member.isAccessor) requiredParameterCount++;
331 104
332 int optionalParameterCount = parameters.optionalParameterCount << 1; 105 int optionalParameterCount = parameters.optionalParameterCount << 1;
333 if (parameters.optionalParametersAreNamed) optionalParameterCount++; 106 if (parameters.optionalParametersAreNamed) optionalParameterCount++;
334 107
335 // TODO(sra): Don't use LiteralString for non-strings. 108 // TODO(sra): Don't use LiteralString for non-strings.
336 List tearOffInfo = [new jsAst.LiteralString(callSelectorString)]; 109 List tearOffInfo = [new jsAst.LiteralString(callSelectorString)];
337 110
338 if (needsStubs || canTearOff) { 111 if (needsStubs || canTearOff) {
339 addParameterStubs(member, (Selector selector, jsAst.Fun function) {
340 112
341 String invocationName = namer.invocationName(selector); 113 for (ParameterStubMethod method in method.parameterStubs) {
342 emitter.interceptorEmitter. 114 String invocationName = method.name;
343 recordMangledNameOfMemberMethod(member, invocationName); 115 emitter.interceptorEmitter
344 expressions.add(function); 116 .recordMangledNameOfMemberMethod(member, invocationName);
117 expressions.add(method.code);
345 if (member.isInstanceMember) { 118 if (member.isInstanceMember) {
346 Set invokedSelectors = 119 expressions.add(js.string(invocationName));
347 compiler.codegenWorld.invokedNames[member.name];
348 expressions.add(js.string(invocationName));
349 } else { 120 } else {
350 expressions.add(js('null')); 121 expressions.add(js('null'));
351 // TOOD(ahe): Since we know when reading static data versus instance 122 // TOOD(ahe): Since we know when reading static data versus instance
352 // data, we can eliminate this element. 123 // data, we can eliminate this element.
353 } 124 }
125
354 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[ 126 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
355 namer.closureInvocationSelectorName]; 127 namer.closureInvocationSelectorName];
356 Selector callSelector = selector.toCallSelector(); 128 Selector callSelector = method.selector.toCallSelector();
357 String callSelectorString = 'null'; 129 String callSelectorString = 'null';
358 if (canTearOff && callSelectors != null && 130 if (canTearOff && callSelectors != null &&
359 callSelectors.contains(callSelector)) { 131 callSelectors.contains(callSelector)) {
360 callSelectorString = '"${namer.invocationName(callSelector)}"'; 132 callSelectorString = '"${namer.invocationName(callSelector)}"';
361 } 133 }
362 tearOffInfo.add(new jsAst.LiteralString(callSelectorString)); 134 tearOffInfo.add(new jsAst.LiteralString(callSelectorString));
363 }, canTearOff); 135 }
364 } 136 }
365 137
366 jsAst.Expression memberTypeExpression; 138 jsAst.Expression memberTypeExpression;
367 if (canTearOff || canBeReflected) { 139 if (canTearOff || canBeReflected) {
368 DartType memberType; 140 DartType memberType;
369 if (member.isGenerativeConstructorBody) { 141 if (member.isGenerativeConstructorBody) {
370 var body = member; 142 var body = member;
371 memberType = body.constructor.type; 143 memberType = body.constructor.type;
372 } else { 144 } else {
373 memberType = member.type; 145 memberType = member.type;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 jsAst.ArrayInitializer arrayInit = 206 jsAst.ArrayInitializer arrayInit =
435 new jsAst.ArrayInitializer(expressions.toList()); 207 new jsAst.ArrayInitializer(expressions.toList());
436 compiler.dumpInfoTask.registerElementAst(member, 208 compiler.dumpInfoTask.registerElementAst(member,
437 builder.addProperty(name, arrayInit)); 209 builder.addProperty(name, arrayInit));
438 } 210 }
439 211
440 void addMemberField(Field field, ClassBuilder builder) { 212 void addMemberField(Field field, ClassBuilder builder) {
441 // For now, do nothing. 213 // For now, do nothing.
442 } 214 }
443 } 215 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698