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

Side by Side Diff: dart/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart

Issue 27524003: Generate tear-off closures dynamically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years 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 final Map<Element, Element> staticGetters = new Map<Element, Element>(); 12 final Map<Element, Element> staticGetters = new Map<Element, Element>();
13 13
14 /// A cache of synthesized closures for top-level, static or 14 /// A cache of synthesized closures for top-level, static or
15 /// instance methods. 15 /// instance methods.
16 final Map<String, Element> methodClosures = <String, Element>{}; 16 final Map<String, Element> methodClosures = <String, Element>{};
17 17
18 /** 18 /**
19 * Generate stubs to handle invocation of methods with optional 19 * Generate stubs to handle invocation of methods with optional
20 * arguments. 20 * arguments.
21 * 21 *
22 * A method like [: foo([x]) :] may be invoked by the following 22 * A method like [: foo([x]) :] may be invoked by the following
23 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this 23 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this
24 * function for detailed examples. 24 * function for detailed examples.
25 */ 25 */
26 void addParameterStub(FunctionElement member, 26 void addParameterStub(FunctionElement member,
27 Selector selector, 27 Selector selector,
28 DefineStubFunction defineStub, 28 AddStubFunction addStub,
29 Set<String> alreadyGenerated) { 29 Set<String> alreadyGenerated) {
30 FunctionSignature parameters = member.computeSignature(compiler); 30 FunctionSignature parameters = member.computeSignature(compiler);
31 int positionalArgumentCount = selector.positionalArgumentCount; 31 int positionalArgumentCount = selector.positionalArgumentCount;
32 if (positionalArgumentCount == parameters.parameterCount) { 32 if (positionalArgumentCount == parameters.parameterCount) {
33 assert(selector.namedArgumentCount == 0); 33 assert(selector.namedArgumentCount == 0);
34 return; 34 return;
35 } 35 }
36 if (parameters.optionalParametersAreNamed 36 if (parameters.optionalParametersAreNamed
37 && selector.namedArgumentCount == parameters.optionalParameterCount) { 37 && selector.namedArgumentCount == parameters.optionalParameterCount) {
38 // If the selector has the same number of named arguments as the element, 38 // If the selector has the same number of named arguments as the element,
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 } 114 }
115 count++; 115 count++;
116 }); 116 });
117 117
118 List body; 118 List body;
119 if (member.hasFixedBackendName()) { 119 if (member.hasFixedBackendName()) {
120 body = task.nativeEmitter.generateParameterStubStatements( 120 body = task.nativeEmitter.generateParameterStubStatements(
121 member, isInterceptedMethod, invocationName, 121 member, isInterceptedMethod, invocationName,
122 parametersBuffer, argumentsBuffer, 122 parametersBuffer, argumentsBuffer,
123 indexOfLastOptionalArgumentInParameters); 123 indexOfLastOptionalArgumentInParameters);
124 } else { 124 } else if (member.isInstanceMember()) {
125 body = [js.return_( 125 body = [js.return_(
126 js('this')[namer.getNameOfInstanceMember(member)](argumentsBuffer))]; 126 js('this')[namer.getNameOfInstanceMember(member)](argumentsBuffer))];
127 } else {
128 body = [js.return_(namer.elementAccess(member)(argumentsBuffer))];
127 } 129 }
128 130
129 jsAst.Fun function = js.fun(parametersBuffer, body); 131 jsAst.Fun function = js.fun(parametersBuffer, body);
130 132
131 defineStub(invocationName, function); 133 addStub(selector, function);
132
133 String reflectionName = task.getReflectionName(selector, invocationName);
134 if (reflectionName != null) {
135 var reflectable =
136 js(backend.isAccessibleByReflection(member) ? '1' : '0');
137 defineStub('+$reflectionName', reflectable);
138 }
139 } 134 }
140 135
141 void addParameterStubs(FunctionElement member, 136 void addParameterStubs(FunctionElement member, AddStubFunction defineStub,
142 DefineStubFunction defineStub) { 137 [bool canTearOff = false]) {
138 if (member.enclosingElement.isClosure()) {
139 ClosureClassElement cls = member.enclosingElement;
140 if (cls.supertype.element == compiler.boundClosureClass) {
141 compiler.internalErrorOnElement(cls.methodElement, 'Bound closure1.');
142 }
143 if (cls.methodElement.isInstanceMember()) {
144 compiler.internalErrorOnElement(cls.methodElement, 'Bound closure2.');
145 }
146 }
147
143 // We fill the lists depending on the selector. For example, 148 // We fill the lists depending on the selector. For example,
144 // take method foo: 149 // take method foo:
145 // foo(a, b, {c, d}); 150 // foo(a, b, {c, d});
146 // 151 //
147 // We may have multiple ways of calling foo: 152 // We may have multiple ways of calling foo:
148 // (1) foo(1, 2); 153 // (1) foo(1, 2);
149 // (2) foo(1, 2, c: 3); 154 // (2) foo(1, 2, c: 3);
150 // (3) foo(1, 2, d: 4); 155 // (3) foo(1, 2, d: 4);
151 // (4) foo(1, 2, c: 3, d: 4); 156 // (4) foo(1, 2, c: 3, d: 4);
152 // (5) foo(1, 2, d: 4, c: 3); 157 // (5) foo(1, 2, d: 4, c: 3);
153 // 158 //
154 // What we generate at the call sites are: 159 // What we generate at the call sites are:
155 // (1) foo$2(1, 2); 160 // (1) foo$2(1, 2);
156 // (2) foo$3$c(1, 2, 3); 161 // (2) foo$3$c(1, 2, 3);
157 // (3) foo$3$d(1, 2, 4); 162 // (3) foo$3$d(1, 2, 4);
158 // (4) foo$4$c$d(1, 2, 3, 4); 163 // (4) foo$4$c$d(1, 2, 3, 4);
159 // (5) foo$4$c$d(1, 2, 3, 4); 164 // (5) foo$4$c$d(1, 2, 3, 4);
160 // 165 //
161 // The stubs we generate are (expressed in Dart): 166 // The stubs we generate are (expressed in Dart):
162 // (1) foo$2(a, b) => foo$4$c$d(a, b, null, null) 167 // (1) foo$2(a, b) => foo$4$c$d(a, b, null, null)
163 // (2) foo$3$c(a, b, c) => foo$4$c$d(a, b, c, null); 168 // (2) foo$3$c(a, b, c) => foo$4$c$d(a, b, c, null);
164 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d); 169 // (3) foo$3$d(a, b, d) => foo$4$c$d(a, b, null, d);
165 // (4) No stub generated, call is direct. 170 // (4) No stub generated, call is direct.
166 // (5) No stub generated, call is direct. 171 // (5) No stub generated, call is direct.
167 172
168 // Keep a cache of which stubs have already been generated, to 173 // Keep a cache of which stubs have already been generated, to
169 // avoid duplicates. Note that even if selectors are 174 // avoid duplicates. Note that even if selectors are
170 // canonicalized, we would still need this cache: a typed selector 175 // canonicalized, we would still need this cache: a typed selector
171 // on A and a typed selector on B could yield the same stub. 176 // on A and a typed selector on B could yield the same stub.
172 Set<String> generatedStubNames = new Set<String>(); 177 Set<Selector> selectors = null;
kasperl 2013/11/29 10:10:55 Maybe use ?: so the comment about not needing stub
ahe 2013/12/06 15:57:53 Done.
173 bool isClosureInvocation = 178 if (member.isInstanceMember()) {
174 member.name == namer.closureInvocationSelectorName; 179 // No stubs needed for static methods.
175 if (backend.isNeededForReflection(member) || 180 selectors = compiler.codegenWorld.invokedNames[member.name];
176 (compiler.enabledFunctionApply && isClosureInvocation)) { 181 }
177 // If [Function.apply] is called, we pessimistically compile all 182
178 // possible stubs for this closure. 183 /// Returns all closure call selectors renamed to match this member.
179 FunctionSignature signature = member.computeSignature(compiler); 184 Set<Selector> callSelectorsAsNamed() {
180 Set<Selector> selectors = signature.optionalParametersAreNamed 185 if (!canTearOff) return null;
181 ? computeSeenNamedSelectors(member) 186 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
182 : computeOptionalSelectors(signature, member); 187 namer.closureInvocationSelectorName];
188 if (callSelectors == null) return null;
189 return callSelectors.map((Selector callSelector) {
190 return new Selector.call(
191 member.name, member.getLibrary(),
192 callSelector.argumentCount, callSelector.namedArguments);
193 }).toSet();
194 }
195 if (selectors == null) {
196 selectors = callSelectorsAsNamed();
197 if (selectors == null) return;
198 } else {
199 Set<Selector> callSelectors = callSelectorsAsNamed();
200 if (callSelectors != null) {
201 selectors = selectors.union(callSelectors);
202 }
203 }
204 Set<Selector> untypedSelectors = new Set();
205 if (selectors != null) {
183 for (Selector selector in selectors) { 206 for (Selector selector in selectors) {
184 addParameterStub(member, selector, defineStub, generatedStubNames); 207 if (!selector.appliesUnnamed(member, compiler)) continue;
208 if (untypedSelectors.add(selector.asUntyped)) {
209 // TODO(ahe): Is the last argument to [addParameterStub] needed?
210 addParameterStub(member, selector, defineStub, new Set<String>());
211 }
185 } 212 }
186 if (signature.optionalParametersAreNamed && isClosureInvocation) { 213 }
187 addCatchAllParameterStub(member, signature, defineStub); 214 if (canTearOff) {
188 } 215 selectors = compiler.codegenWorld.invokedNames[
189 } else { 216 namer.closureInvocationSelectorName];
190 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; 217 if (selectors != null) {
191 if (selectors == null) return; 218 for (Selector selector in selectors) {
192 for (Selector selector in selectors) { 219 selector = new Selector.call(
193 if (!selector.applies(member, compiler)) continue; 220 member.name, member.getLibrary(),
194 addParameterStub(member, selector, defineStub, generatedStubNames); 221 selector.argumentCount, selector.namedArguments);
222 if (!selector.appliesUnnamed(member, compiler)) continue;
223 if (untypedSelectors.add(selector)) {
224 // TODO(ahe): Is the last argument to [addParameterStub] needed?
225 addParameterStub(member, selector, defineStub, new Set<String>());
226 }
227 }
195 } 228 }
196 } 229 }
197 } 230 }
198 231
199 Set<Selector> computeSeenNamedSelectors(FunctionElement element) {
200 Set<Selector> selectors = compiler.codegenWorld.invokedNames[element.name];
201 Set<Selector> result = new Set<Selector>();
202 if (selectors == null) return result;
203 for (Selector selector in selectors) {
204 if (!selector.applies(element, compiler)) continue;
205 result.add(selector);
206 }
207 return result;
208 }
209
210 void addCatchAllParameterStub(FunctionElement member,
211 FunctionSignature signature,
212 DefineStubFunction defineStub) {
213 // See Primities.applyFunction in js_helper.dart for details.
214 List<jsAst.Property> properties = <jsAst.Property>[];
215 for (Element element in signature.orderedOptionalParameters) {
216 String jsName = backend.namer.safeName(element.name);
217 Constant value = compiler.constantHandler.initialVariableValues[element];
218 jsAst.Expression reference = null;
219 if (value == null) {
220 reference = new jsAst.LiteralNull();
221 } else {
222 reference = task.constantReference(value);
223 }
224 properties.add(new jsAst.Property(js.string(jsName), reference));
225 }
226 defineStub(
227 backend.namer.callCatchAllName,
228 js.fun([], js.return_(new jsAst.ObjectInitializer(properties))));
229 }
230
231 /**
232 * Compute the set of possible selectors in the presence of optional
233 * non-named parameters.
234 */
235 Set<Selector> computeOptionalSelectors(FunctionSignature signature,
236 FunctionElement element) {
237 Set<Selector> selectors = new Set<Selector>();
238 // Add the selector that does not have any optional argument.
239 selectors.add(new Selector(SelectorKind.CALL,
240 element.name,
241 element.getLibrary(),
242 signature.requiredParameterCount,
243 <String>[]));
244
245 // For each optional parameter, we increment the number of passed
246 // argument.
247 for (int i = 1; i <= signature.optionalParameterCount; i++) {
248 selectors.add(new Selector(SelectorKind.CALL,
249 element.name,
250 element.getLibrary(),
251 signature.requiredParameterCount + i,
252 <String>[]));
253 }
254 return selectors;
255 }
256
257 void emitStaticFunctionGetters(CodeBuffer eagerBuffer) { 232 void emitStaticFunctionGetters(CodeBuffer eagerBuffer) {
233 return;
258 task.addComment('Static function getters', task.mainBuffer); 234 task.addComment('Static function getters', task.mainBuffer);
259 for (FunctionElement element in 235 for (FunctionElement element in
260 Elements.sortedByPosition(staticGetters.keys)) { 236 Elements.sortedByPosition(staticGetters.keys)) {
261 Element closure = staticGetters[element]; 237 Element closure = staticGetters[element];
262 CodeBuffer buffer = 238 CodeBuffer buffer =
263 task.isDeferred(element) ? task.deferredConstants : eagerBuffer; 239 task.isDeferred(element) ? task.deferredConstants : eagerBuffer;
264 String closureClass = namer.isolateAccess(closure); 240 String closureClass = namer.isolateAccess(closure);
265 String name = namer.getStaticClosureName(element); 241 String name = namer.getStaticClosureName(element);
266 242
267 String closureName = namer.getStaticClosureName(element); 243 String closureName = namer.getStaticClosureName(element);
268 jsAst.Node assignment = js( 244 jsAst.Node assignment = js(
269 'init.globalFunctions["$closureName"] =' 245 'init.globalFunctions["$closureName"] ='
270 ' ${namer.globalObjectFor(element)}.$name =' 246 ' ${namer.globalObjectFor(element)}.$name ='
271 ' new $closureClass(#, "$closureName")', 247 ' new $closureClass(#, "$closureName")',
272 namer.elementAccess(element)); 248 namer.elementAccess(element));
273 buffer.write(jsAst.prettyPrint(assignment, compiler)); 249 buffer.write(jsAst.prettyPrint(assignment, compiler));
274 buffer.write('$N'); 250 buffer.write('$N');
275 } 251 }
276 } 252 }
277 253
278 void emitStaticFunctionClosures() { 254 void emitStaticFunctionClosures() {
255 return;
279 Set<FunctionElement> functionsNeedingGetter = 256 Set<FunctionElement> functionsNeedingGetter =
280 compiler.codegenWorld.staticFunctionsNeedingGetter; 257 compiler.codegenWorld.staticFunctionsNeedingGetter;
281 for (FunctionElement element in 258 for (FunctionElement element in
282 Elements.sortedByPosition(functionsNeedingGetter)) { 259 Elements.sortedByPosition(functionsNeedingGetter)) {
283 String superName = namer.getNameOfClass(compiler.closureClass); 260 String superName = namer.getNameOfClass(compiler.closureClass);
284 int parameterCount = element.functionSignature.parameterCount; 261 int parameterCount = element.functionSignature.parameterCount;
285 String name = 'Closure\$$parameterCount'; 262 String name = 'Closure\$$parameterCount';
286 assert(task.instantiatedClasses.contains(compiler.closureClass)); 263 assert(task.instantiatedClasses.contains(compiler.closureClass));
287 264
288 ClassElement closureClassElement = new ClosureClassElement( 265 ClassElement closureClassElement = new ClosureClassElement(
(...skipping 13 matching lines...) Expand all
302 // Define the constructor with a name so that Object.toString can 279 // Define the constructor with a name so that Object.toString can
303 // find the class name of the closure class. 280 // find the class name of the closure class.
304 ClassBuilder closureBuilder = new ClassBuilder(); 281 ClassBuilder closureBuilder = new ClassBuilder();
305 // If a static function is used as a closure we need to add its name 282 // If a static function is used as a closure we need to add its name
306 // in case it is used in spawnFunction. 283 // in case it is used in spawnFunction.
307 String methodName = namer.STATIC_CLOSURE_NAME_NAME; 284 String methodName = namer.STATIC_CLOSURE_NAME_NAME;
308 List<String> fieldNames = <String>[invocationName, methodName]; 285 List<String> fieldNames = <String>[invocationName, methodName];
309 closureBuilder.addProperty('', 286 closureBuilder.addProperty('',
310 js.string("$superName;${fieldNames.join(',')}")); 287 js.string("$superName;${fieldNames.join(',')}"));
311 288
312 addParameterStubs(callElement, closureBuilder.addProperty); 289 addParameterStubs(
290 callElement,
291 (Selector selector, jsAst.Fun function) {
292 closureBuilder.addProperty(
293 namer.invocationName(selector), function);
294 });
313 295
314 void emitFunctionTypeSignature(Element method, FunctionType methodType) { 296 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
315 RuntimeTypes rti = backend.rti; 297 RuntimeTypes rti = backend.rti;
316 // [:() => null:] is dummy encoding of [this] which is never needed for 298 // [:() => null:] is dummy encoding of [this] which is never needed for
317 // the encoding of the type of the static [method]. 299 // the encoding of the type of the static [method].
318 jsAst.Expression encoding = 300 jsAst.Expression encoding =
319 rti.getSignatureEncoding(methodType, js('null')); 301 rti.getSignatureEncoding(methodType, js('null'));
320 String operatorSignature = namer.operatorSignature(); 302 String operatorSignature = namer.operatorSignature();
321 // TODO(johnniwinther): Make MiniJsParser support function expressions. 303 // TODO(johnniwinther): Make MiniJsParser support function expressions.
322 closureBuilder.addProperty(operatorSignature, encoding); 304 closureBuilder.addProperty(operatorSignature, encoding);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 347
366 task.precompiledConstructorNames.add(js(constructorName)); 348 task.precompiledConstructorNames.add(js(constructorName));
367 } 349 }
368 350
369 /** 351 /**
370 * Documentation wanted -- johnniwinther 352 * Documentation wanted -- johnniwinther
371 * 353 *
372 * Invariant: [member] must be a declaration element. 354 * Invariant: [member] must be a declaration element.
373 */ 355 */
374 void emitDynamicFunctionGetter(FunctionElement member, 356 void emitDynamicFunctionGetter(FunctionElement member,
375 DefineStubFunction defineStub) { 357 AddPropertyFunction addProperty) {
376 assert(invariant(member, member.isDeclaration)); 358 assert(invariant(member, member.isDeclaration));
377 assert(task.instantiatedClasses.contains(compiler.boundClosureClass)); 359 assert(task.instantiatedClasses.contains(compiler.boundClosureClass));
378 // For every method that has the same name as a property-get we create a 360 // For every method that has the same name as a property-get we create a
379 // getter that returns a bound closure. Say we have a class 'A' with method 361 // getter that returns a bound closure. Say we have a class 'A' with method
380 // 'foo' and somewhere in the code there is a dynamic property get of 362 // 'foo' and somewhere in the code there is a dynamic property get of
381 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): 363 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript):
382 // 364 //
383 // class A { 365 // class A {
384 // foo(x, y, z) { ... } // Original function. 366 // foo(x, y, z) { ... } // Original function.
385 // get foo { return new BoundClosure499(this, "foo"); } 367 // get foo { return new BoundClosure499(this, "foo"); }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 parameters.add(name); 417 parameters.add(name);
436 arguments.add(js(name)); 418 arguments.add(js(name));
437 } 419 }
438 420
439 jsAst.Expression fun = js.fun( 421 jsAst.Expression fun = js.fun(
440 parameters, 422 parameters,
441 js.return_( 423 js.return_(
442 js('this')[fieldNames[1]]['call'](arguments))); 424 js('this')[fieldNames[1]]['call'](arguments)));
443 boundClosureBuilder.addProperty(invocationName, fun); 425 boundClosureBuilder.addProperty(invocationName, fun);
444 426
445 addParameterStubs(callElement, boundClosureBuilder.addProperty); 427 addParameterStubs(
428 callElement,
429 (Selector selector, jsAst.Fun function) {
430 boundClosureBuilder.addProperty(
431 namer.invocationName(selector), function);
432 });
446 433
447 void emitFunctionTypeSignature(Element method, FunctionType methodType) { 434 void emitFunctionTypeSignature(Element method, FunctionType methodType) {
448 jsAst.Expression encoding = backend.rti.getSignatureEncoding( 435 jsAst.Expression encoding = backend.rti.getSignatureEncoding(
449 methodType, js('this')[fieldNames[0]]); 436 methodType, js('this')[fieldNames[0]]);
450 String operatorSignature = namer.operatorSignature(); 437 String operatorSignature = namer.operatorSignature();
451 boundClosureBuilder.addProperty(operatorSignature, encoding); 438 boundClosureBuilder.addProperty(operatorSignature, encoding);
452 } 439 }
453 440
454 DartType memberType = member.computeType(compiler); 441 DartType memberType = member.computeType(compiler);
455 Map<FunctionType, bool> functionTypeChecks = 442 Map<FunctionType, bool> functionTypeChecks =
(...skipping 24 matching lines...) Expand all
480 } else { 467 } else {
481 // Put null in the intercepted receiver field. 468 // Put null in the intercepted receiver field.
482 arguments.add(new jsAst.LiteralNull()); 469 arguments.add(new jsAst.LiteralNull());
483 } 470 }
484 471
485 arguments.add(js.string(targetName)); 472 arguments.add(js.string(targetName));
486 473
487 jsAst.Expression getterFunction = js.fun( 474 jsAst.Expression getterFunction = js.fun(
488 parameters, js.return_(js(closureClass).newWith(arguments))); 475 parameters, js.return_(js(closureClass).newWith(arguments)));
489 476
490 defineStub(getterName, getterFunction); 477 addProperty(getterName, getterFunction);
491 } 478 }
492 479
493 /** 480 /**
494 * Documentation wanted -- johnniwinther 481 * Documentation wanted -- johnniwinther
495 * 482 *
496 * Invariant: [member] must be a declaration element. 483 * Invariant: [member] must be a declaration element.
497 */ 484 */
498 void emitCallStubForGetter(Element member, 485 void emitCallStubForGetter(Element member,
499 Set<Selector> selectors, 486 Set<Selector> selectors,
500 DefineStubFunction defineStub) { 487 AddPropertyFunction addProperty) {
501 assert(invariant(member, member.isDeclaration)); 488 assert(invariant(member, member.isDeclaration));
502 LibraryElement memberLibrary = member.getLibrary(); 489 LibraryElement memberLibrary = member.getLibrary();
503 // If the method is intercepted, the stub gets the 490 // If the method is intercepted, the stub gets the
504 // receiver explicitely and we need to pass it to the getter call. 491 // receiver explicitely and we need to pass it to the getter call.
505 bool isInterceptedMethod = backend.isInterceptedMethod(member); 492 bool isInterceptedMethod = backend.isInterceptedMethod(member);
506 493
507 const String receiverArgumentName = r'$receiver'; 494 const String receiverArgumentName = r'$receiver';
508 495
509 jsAst.Expression buildGetter() { 496 jsAst.Expression buildGetter() {
510 if (member.isGetter()) { 497 if (member.isGetter()) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 for (int i = 0; i < selector.argumentCount; i++) { 529 for (int i = 0; i < selector.argumentCount; i++) {
543 String name = 'arg$i'; 530 String name = 'arg$i';
544 parameters.add(new jsAst.Parameter(name)); 531 parameters.add(new jsAst.Parameter(name));
545 arguments.add(js(name)); 532 arguments.add(js(name));
546 } 533 }
547 534
548 jsAst.Fun function = js.fun( 535 jsAst.Fun function = js.fun(
549 parameters, 536 parameters,
550 js.return_(buildGetter()[closureCallName](arguments))); 537 js.return_(buildGetter()[closureCallName](arguments)));
551 538
552 defineStub(invocationName, function); 539 addProperty(invocationName, function);
553 } 540 }
554 } 541 }
555 } 542 }
556 543
557 /** 544 /**
558 * Documentation wanted -- johnniwinther 545 * Documentation wanted -- johnniwinther
559 * 546 *
560 * Invariant: [member] must be a declaration element. 547 * Invariant: [member] must be a declaration element.
561 */ 548 */
562 void emitExtraAccessors(Element member, ClassBuilder builder) { 549 void emitExtraAccessors(Element member, ClassBuilder builder) {
563 assert(invariant(member, member.isDeclaration)); 550 assert(invariant(member, member.isDeclaration));
564 if (member.isGetter() || member.isField()) { 551 if (member.isGetter() || member.isField()) {
565 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; 552 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name];
566 if (selectors != null && !selectors.isEmpty) { 553 if (selectors != null && !selectors.isEmpty) {
567 emitCallStubForGetter(member, selectors, builder.addProperty); 554 emitCallStubForGetter(member, selectors, builder.addProperty);
568 } 555 }
569 } else if (member.isFunction()) {
570 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) {
571 emitDynamicFunctionGetter(member, builder.addProperty);
572 }
573 } 556 }
574 } 557 }
575 558
576 void addMember(Element member, ClassBuilder builder) { 559 void addMember(Element member, ClassBuilder builder) {
577 assert(invariant(member, member.isDeclaration)); 560 assert(invariant(member, member.isDeclaration));
578 561
579 if (member.isField()) { 562 if (member.isField()) {
580 addMemberField(member, builder); 563 addMemberField(member, builder);
581 } else if (member.isFunction() || 564 } else if (member.isFunction() ||
582 member.isGenerativeConstructorBody() || 565 member.isGenerativeConstructorBody() ||
583 member.isGenerativeConstructor() || 566 member.isGenerativeConstructor() ||
584 member.isAccessor()) { 567 member.isAccessor()) {
585 addMemberMethod(member, builder); 568 addMemberMethod(member, builder);
586 } else { 569 } else {
587 compiler.internalErrorOnElement( 570 compiler.internalErrorOnElement(
588 member, 'unexpected kind: "${member.kind}"'); 571 member, 'unexpected kind: "${member.kind}"');
589 } 572 }
590 if (member.isInstanceMember()) emitExtraAccessors(member, builder); 573 if (member.isInstanceMember()) emitExtraAccessors(member, builder);
591 } 574 }
592 575
593 void addMemberMethod(FunctionElement member, ClassBuilder builder) { 576 void addMemberMethod(FunctionElement member, ClassBuilder builder) {
594 if (member.isAbstract(compiler)) return; 577 if (member.isAbstract(compiler)) return;
595 jsAst.Expression code = backend.generatedCode[member]; 578 jsAst.Expression code = backend.generatedCode[member];
596 if (code == null) return; 579 if (code == null) return;
597 String name = namer.getNameOfMember(member); 580 String name = namer.getNameOfMember(member);
598 if (backend.isInterceptedMethod(member)) { 581 task.interceptorEmitter.recordMangledNameOfMemberMethod(member, name);
599 task.interceptorEmitter.interceptorInvocationNames.add(name); 582 FunctionSignature parameters = member.computeSignature(compiler);
583 bool needsStubs = !parameters.optionalParameters.isEmpty;
584 bool canTearOff = false;
585 bool isClosure = false;
586 String tearOffName;
587 if (!member.isFunction() || member.isConstructor() || member.isAccessor()) {
588 canTearOff = false;
589 } else if (member.isInstanceMember()) {
590 if (member.getEnclosingClass().isClosure()) {
591 canTearOff = false;
592 isClosure = true;
593 } else {
594 // Careful with operators.
595 canTearOff = compiler.codegenWorld.hasInvokedGetter(member, compiler);
596 tearOffName = namer.getterName(member);
597 }
598 } else {
599 canTearOff =
600 compiler.codegenWorld.staticFunctionsNeedingGetter.contains(member);
601 tearOffName = namer.getStaticClosureName(member);
600 } 602 }
601 code = task.metadataEmitter.extendWithMetadata(member, code); 603
602 builder.addProperty(name, code); 604 bool canBeReflected = backend.isAccessibleByReflection(member);
603 String reflectionName = task.getReflectionName(member, name); 605 bool needStructuredInfo = canTearOff || canBeReflected || compiler.enabledFu nctionApply;
kasperl 2013/11/29 10:10:55 Long line.
ahe 2013/12/06 15:57:53 Done.
604 if (reflectionName != null) { 606 if (!needStructuredInfo) {
605 var reflectable = 607 builder.addProperty(name, code);
606 js(backend.isAccessibleByReflection(member) ? '1' : '0'); 608 if (needsStubs) {
607 builder.addProperty('+$reflectionName', reflectable); 609 addParameterStubs(
608 jsAst.Node defaultValues = 610 member,
609 task.metadataEmitter.reifyDefaultArguments(member); 611 (Selector selector, jsAst.Fun function) {
610 if (defaultValues != null) { 612 builder.addProperty(namer.invocationName(selector), function);
611 String unmangledName = member.name; 613 });
612 builder.addProperty('*$unmangledName', defaultValues);
613 } 614 }
615 return;
614 } 616 }
615 if (member.isInstanceMember()) { 617
616 // TODO(ahe): Where is this done for static/top-level methods? 618 if (canTearOff) {
617 FunctionSignature parameters = member.computeSignature(compiler); 619 assert(invariant(member, !member.isGenerativeConstructor()));
618 if (!parameters.optionalParameters.isEmpty) { 620 assert(invariant(member, !member.isGenerativeConstructorBody()));
619 addParameterStubs(member, builder.addProperty); 621 assert(invariant(member, !member.isConstructor()));
622 }
623
624 // This element is needed for reflection or needs additional stubs. So we
625 // need to retain additional information.
626
627 // The information is stored in an array with this format:
628 //
629 // 1. The JS function for this member.
630 // 2. First stub.
631 // 3. Name of first stub.
632 // ...
633 // M. Call name of this member.
634 // M+1. Call name of first stub.
635 // ...
636 // N. Getter name for tearOff.
637 // N+1. (Required parameter count << 1) + (member.isAccessor() ? 1 : 0).
638 // N+2. (Optional parameter count << 1) +
639 // (parameters.optionalParametersAreNamed ? 1 : 0).
640 // N+3. Index to function type in constant pool.
641 // N+4. First default argument.
642 // ...
643 // O. First parameter name (if needed for reflection or Function.apply).
644 // ...
645 // P. Unmangled name (if reflectable).
646 // P+1. First metadata (if reflectable).
647 // ...
648
649 List expressions = [];
650
651 Selector callSelector;
652 if (member.isFunction()) {
653 callSelector =
654 new Selector.fromElement(member, compiler).toCallSelector();
655 }
656
657 // On [requiredParameterCount], the lower bit is set if this method can be
658 // called reflectively.
659 int requiredParameterCount = parameters.requiredParameterCount << 1;
660 if (member.isAccessor()) requiredParameterCount++;
661
662 int optionalParameterCount = parameters.optionalParameterCount << 1;
663 if (parameters.optionalParametersAreNamed) optionalParameterCount++;
664
665 expressions.add(code);
666
667 String callSelectorString =
668 callSelector == null ? null : '"${namer.invocationName(callSelector)}"';
669 List tearOffInfo =
670 [new jsAst.LiteralString('$callSelectorString /* tearOffInfo */')];
671
672 if (needsStubs || canTearOff) {
673 addParameterStubs(member, (Selector selector, jsAst.Fun function) {
674 expressions.add(function);
675 if (member.isInstanceMember()) {
676 Set invokedSelectors =
677 compiler.codegenWorld.invokedNames[member.name];
678 if (invokedSelectors != null && invokedSelectors.contains(selector)) {
679 expressions.add(js.string(namer.invocationName(selector)));
680 } else {
681 // Don't add a stub for calling this as a regular instance method,
682 // we only need the "call" stub for implicit closures of this
683 // method.
684 expressions.add("null");
685 }
686 } else {
687 // Static methods don't need "named" stubs as the default arguments
688 // are inlined at call sites. But static methods might need "call"
689 // stubs for implicit closures.
690 expressions.add("null");
691 // TOOD(ahe): Since we know when reading static data versus instance
692 // data, we can eliminate this element.
693 }
694 Set<Selector> callSelectors = compiler.codegenWorld.invokedNames[
695 namer.closureInvocationSelectorName];
696 Selector callSelector = selector.toCallSelector();
697 String callSelectorString = 'null';
698 if (canTearOff && callSelectors != null && callSelectors.contains(callSe lector)) {
kasperl 2013/11/29 10:10:55 Long lines (there are a number of occurrences in t
ahe 2013/12/06 15:57:53 Done.
699 callSelectorString = '"${namer.invocationName(callSelector)}"';
700 }
701 tearOffInfo.add(new jsAst.LiteralString('$callSelectorString /* tearOffI nfo */'));
702 }, canTearOff);
703 }
704
705 jsAst.Expression memberTypeExpression;
706 if ((canTearOff || canBeReflected) && !member.isGenerativeConstructorBody()) {
707 DartType memberType = member.computeType(compiler);
708 if (memberType.containsTypeVariables) {
709 jsAst.Expression thisAccess = js(r'this.$receiver');
710 memberTypeExpression =
711 backend.rti.getSignatureEncoding(memberType, thisAccess);
712 } else {
713 memberTypeExpression =
714 js.toExpression(task.metadataEmitter.reifyType(memberType));
620 } 715 }
716 } else {
717 memberTypeExpression = js('null');
621 } 718 }
719
720 expressions
721 ..addAll(tearOffInfo)
722 ..add((tearOffName == null || member.isAccessor())
723 ? js("null") : js.string(tearOffName))
724 ..add(requiredParameterCount)
725 ..add(optionalParameterCount)
726 ..add(memberTypeExpression)
727 ..addAll(task.metadataEmitter.reifyDefaultArguments(member));
728
729 if (canBeReflected || compiler.enabledFunctionApply) {
730 parameters.orderedForEachParameter((Element parameter) {
731 expressions.add(task.metadataEmitter.reifyName(parameter.name));
732 });
733 }
734 if (canBeReflected) {
735 jsAst.LiteralString reflectionName;
736 if (member.isConstructor()) {
737 String reflectionNameString = task.getReflectionName(member, name);
738 reflectionName =
739 new jsAst.LiteralString(
740 '"new ${Elements.reconstructConstructorName(member)}" /* $reflec tionNameString */');
741 } else {
742 reflectionName = js.string(member.name);
743 }
744 expressions
745 ..add(reflectionName)
746 ..addAll(task.metadataEmitter.computeMetadata(member));
747 } else if (isClosure && compiler.enabledFunctionApply) {
748 expressions.add(js.string(member.name));
749 }
750
751 builder.addProperty(name, js.toExpression(expressions));
752
753 // if (canTearOff) {
754 // emitDynamicFunctionGetter(member, builder.addProperty);
755 // }
622 } 756 }
623 757
624 void addMemberField(VariableElement member, ClassBuilder builder) { 758 void addMemberField(VariableElement member, ClassBuilder builder) {
625 // For now, do nothing. 759 // For now, do nothing.
626 } 760 }
627 } 761 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698