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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart

Issue 917663003: Put IR builder visitors in a different library than IrBuilder. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart2js.ir_builder;
6
7 /**
8 * This task iterates through all resolved elements and builds [ir.Node]s. The
9 * nodes are stored in the [nodes] map and accessible through [hasIr] and
10 * [getIr].
11 *
12 * The functionality of the IrNodes is added gradually, therefore elements might
13 * have an IR or not, depending on the language features that are used. For
14 * elements that do have an IR, the tree [ast.Node]s and the [Token]s are not
15 * used in the rest of the compilation. This is ensured by setting the element's
16 * cached tree to `null` and also breaking the token stream to crash future
17 * attempts to parse.
18 *
19 * The type inferrer works on either IR nodes or tree nodes. The IR nodes are
20 * then translated into the SSA form for optimizations and code generation.
21 * Long-term, once the IR supports the full language, the backend can be
22 * re-implemented to work directly on the IR.
23 */
24 class IrBuilderTask extends CompilerTask {
25 final Map<Element, ir.ExecutableDefinition> nodes =
26 <Element, ir.ExecutableDefinition>{};
27
28 IrBuilderTask(Compiler compiler) : super(compiler);
29
30 String get name => 'IR builder';
31
32 bool hasIr(Element element) => nodes.containsKey(element.implementation);
33
34 ir.ExecutableDefinition getIr(ExecutableElement element) {
35 return nodes[element.implementation];
36 }
37
38 ir.ExecutableDefinition buildNode(AstElement element) {
39 if (!canBuild(element)) return null;
40 TreeElements elementsMapping = element.resolvedAst.elements;
41 element = element.implementation;
42 return compiler.withCurrentElement(element, () {
43 SourceFile sourceFile = elementSourceFile(element);
44 IrBuilderVisitor builder =
45 compiler.backend is JavaScriptBackend
46 ? new JsIrBuilderVisitor(elementsMapping, compiler, sourceFile)
47 : new DartIrBuilderVisitor(elementsMapping, compiler, sourceFile);
48 return builder.buildExecutable(element);
49 });
50 }
51
52 void buildNodes() {
53 measure(() {
54 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements;
55 resolved.forEach((AstElement element) {
56 ir.ExecutableDefinition definition = buildNode(element);
57 if (definition != null) {
58 nodes[element] = definition;
59 }
60 });
61 });
62 }
63
64 bool canBuild(Element element) {
65 if (element is TypedefElement) return false;
66 if (element is FunctionElement) {
67 // TODO(sigurdm): Support native functions for dart2js.
68 assert(invariant(element, !element.isNative));
69
70 if (element is ConstructorElement) {
71 if (!element.isGenerativeConstructor) {
72 // TODO(kmillikin,sigurdm): Support constructors.
73 return false;
74 }
75 if (element.isSynthesized) {
76 // Do generate CPS for synthetic constructors.
77 return true;
78 }
79 }
80 } else if (element is! FieldElement) {
81 compiler.internalError(element, "Unexpected element type $element");
82 }
83 return compiler.backend.shouldOutput(element);
84 }
85
86 bool get inCheckedMode {
87 bool result = false;
88 assert((result = true));
89 return result;
90 }
91
92 }
93
94 SourceFile elementSourceFile(Element element) {
95 if (element is FunctionElement) {
96 FunctionElement functionElement = element;
97 if (functionElement.patch != null) element = functionElement.patch;
98 }
99 return element.compilationUnit.script.file;
100 }
101
102 class _GetterElements {
103 ir.Primitive result;
104 ir.Primitive index;
105 ir.Primitive receiver;
106
107 _GetterElements({this.result, this.index, this.receiver}) ;
108 }
109
110 /**
111 * A tree visitor that builds [IrNodes]. The visit methods add statements using
112 * to the [builder] and return the last added statement for trees that represent
113 * an expression.
114 */
115 abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
116 with IrBuilderMixin<ast.Node> {
117 final Compiler compiler;
118 final SourceFile sourceFile;
119
120 // In SSA terms, join-point continuation parameters are the phis and the
121 // continuation invocation arguments are the corresponding phi inputs. To
122 // support name introduction and renaming for source level variables, we use
123 // nested (delimited) visitors for constructing subparts of the IR that will
124 // need renaming. Each source variable is assigned an index.
125 //
126 // Each nested visitor maintains a list of free variable uses in the body.
127 // These are implemented as a list of parameters, each with their own use
128 // list of references. When the delimited subexpression is plugged into the
129 // surrounding context, the free occurrences can be captured or become free
130 // occurrences in the next outer delimited subexpression.
131 //
132 // Each nested visitor maintains a list that maps indexes of variables
133 // assigned in the delimited subexpression to their reaching definition ---
134 // that is, the definition in effect at the hole in 'current'. These are
135 // used to determine if a join-point continuation needs to be passed
136 // arguments, and what the arguments are.
137
138 /// Construct a top-level visitor.
139 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
140 : super(elements);
141
142 /**
143 * Builds the [ir.ExecutableDefinition] for an executable element. In case the
144 * function uses features that cannot be expressed in the IR, this element
145 * returns `null`.
146 */
147 ir.ExecutableDefinition buildExecutable(ExecutableElement element);
148
149 ClosureScope getClosureScopeForNode(ast.Node node);
150 ClosureEnvironment getClosureEnvironment();
151
152 /// Normalizes the argument list to a static invocation (i.e. where the target
153 /// element is known).
154 ///
155 /// For the JS backend, inserts default arguments and normalizes order of
156 /// named arguments.
157 ///
158 /// For the Dart backend, returns [arguments].
159 List<ir.Primitive> normalizeStaticArguments(
160 Selector selector,
161 FunctionElement target,
162 List<ir.Primitive> arguments);
163
164 /// Normalizes the argument list of a dynamic invocation (i.e. where the
165 /// target element is unknown).
166 ///
167 /// For the JS backend, normalizes order of named arguments.
168 ///
169 /// For the Dart backend, returns [arguments].
170 List<ir.Primitive> normalizeDynamicArguments(
171 Selector selector,
172 List<ir.Primitive> arguments);
173
174 ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
175 ast.FunctionExpression node) {
176 FunctionSignature signature = element.functionSignature;
177 List<ParameterElement> parameters = [];
178 signature.orderedForEachParameter(parameters.add);
179
180 irBuilder.buildFunctionHeader(parameters,
181 closureScope: getClosureScopeForNode(node),
182 env: getClosureEnvironment());
183
184 List<ConstantExpression> defaults = new List<ConstantExpression>();
185 signature.orderedOptionalParameters.forEach((ParameterElement element) {
186 defaults.add(getConstantForVariable(element));
187 });
188
189 List<ir.Initializer> initializers;
190 if (element.isSynthesized) {
191 assert(element is ConstructorElement);
192 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[],
193 const <ir.Initializer>[]);
194 } else if (element.isGenerativeConstructor) {
195 initializers = buildConstructorInitializers(node, element);
196 visit(node.body);
197 return irBuilder.makeConstructorDefinition(defaults, initializers);
198 } else {
199 visit(node.body);
200 return irBuilder.makeFunctionDefinition(defaults);
201 }
202 }
203
204 List<ir.Initializer> buildConstructorInitializers(
205 ast.FunctionExpression function, ConstructorElement element) {
206 List<ir.Initializer> result = <ir.Initializer>[];
207 FunctionSignature signature = element.functionSignature;
208
209 void tryAddInitializingFormal(ParameterElement parameterElement) {
210 if (parameterElement.isInitializingFormal) {
211 InitializingFormalElement initializingFormal = parameterElement;
212 withBuilder(irBuilder.makeDelimitedBuilder(), () {
213 ir.Primitive value = irBuilder.buildLocalGet(parameterElement);
214 result.add(irBuilder.makeFieldInitializer(
215 initializingFormal.fieldElement,
216 irBuilder.makeRunnableBody(value)));
217 });
218 }
219 }
220
221 // TODO(sigurdm): Preserve initializing formals as initializing formals.
222 signature.orderedForEachParameter(tryAddInitializingFormal);
223
224 if (function.initializers == null) return result;
225 bool explicitSuperInitializer = false;
226 for(ast.Node initializer in function.initializers) {
227 if (initializer is ast.SendSet) {
228 // Field initializer.
229 FieldElement field = elements[initializer];
230 withBuilder(irBuilder.makeDelimitedBuilder(), () {
231 ir.Primitive value = visit(initializer.arguments.head);
232 ir.RunnableBody body = irBuilder.makeRunnableBody(value);
233 result.add(irBuilder.makeFieldInitializer(field, body));
234 });
235 } else if (initializer is ast.Send) {
236 // Super or this initializer.
237 if (ast.Initializers.isConstructorRedirect(initializer)) {
238 giveup(initializer, "constructor redirect (this) initializer");
239 }
240 ConstructorElement constructor = elements[initializer].implementation;
241 Selector selector = elements.getSelector(initializer);
242 List<ir.RunnableBody> arguments =
243 initializer.arguments.mapToList((ast.Node argument) {
244 return withBuilder(irBuilder.makeDelimitedBuilder(), () {
245 ir.Primitive value = visit(argument);
246 return irBuilder.makeRunnableBody(value);
247 });
248 });
249 result.add(irBuilder.makeSuperInitializer(constructor,
250 arguments,
251 selector));
252 explicitSuperInitializer = true;
253 } else {
254 compiler.internalError(initializer,
255 "Unexpected initializer type $initializer");
256 }
257
258 }
259 if (!explicitSuperInitializer) {
260 // No super initializer found. Try to find the default constructor if
261 // the class is not Object.
262 ClassElement enclosingClass = element.enclosingClass;
263 if (!enclosingClass.isObject) {
264 ClassElement superClass = enclosingClass.superclass;
265 FunctionElement target = superClass.lookupDefaultConstructor();
266 if (target == null) {
267 compiler.internalError(superClass,
268 "No default constructor available.");
269 }
270 Selector selector = new Selector.callDefaultConstructor();
271 result.add(irBuilder.makeSuperInitializer(target,
272 <ir.RunnableBody>[],
273 selector));
274 }
275 }
276 return result;
277 }
278
279 ir.Primitive visit(ast.Node node) => node.accept(this);
280
281 // ==== Statements ====
282 visitBlock(ast.Block node) {
283 irBuilder.buildBlock(node.statements.nodes, build);
284 }
285
286 ir.Primitive visitBreakStatement(ast.BreakStatement node) {
287 if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
288 compiler.internalError(node, "'break' target not found");
289 }
290 return null;
291 }
292
293 ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
294 if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
295 compiler.internalError(node, "'continue' target not found");
296 }
297 return null;
298 }
299
300 // Build(EmptyStatement, C) = C
301 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
302 assert(irBuilder.isOpen);
303 return null;
304 }
305
306 // Build(ExpressionStatement(e), C) = C'
307 // where (C', _) = Build(e, C)
308 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) {
309 assert(irBuilder.isOpen);
310 visit(node.expression);
311 return null;
312 }
313
314 visitFor(ast.For node) {
315 List<LocalElement> loopVariables = <LocalElement>[];
316 if (node.initializer is ast.VariableDefinitions) {
317 ast.VariableDefinitions definitions = node.initializer;
318 for (ast.Node node in definitions.definitions.nodes) {
319 LocalElement loopVariable = elements[node];
320 loopVariables.add(loopVariable);
321 }
322 }
323
324 JumpTarget target = elements.getTargetDefinition(node);
325 irBuilder.buildFor(
326 buildInitializer: subbuild(node.initializer),
327 buildCondition: subbuild(node.condition),
328 buildBody: subbuild(node.body),
329 buildUpdate: subbuildSequence(node.update),
330 closureScope: getClosureScopeForNode(node),
331 loopVariables: loopVariables,
332 target: target);
333 }
334
335 visitIf(ast.If node) {
336 irBuilder.buildIf(
337 build(node.condition),
338 subbuild(node.thenPart),
339 subbuild(node.elsePart));
340 }
341
342 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) {
343 ast.Statement body = node.statement;
344 if (body is ast.Loop) return visit(body);
345 JumpTarget target = elements.getTargetDefinition(body);
346 JumpCollector jumps = new JumpCollector(target);
347 irBuilder.state.breakCollectors.add(jumps);
348 IrBuilder innerBuilder = irBuilder.makeDelimitedBuilder();
349 withBuilder(innerBuilder, () {
350 visit(body);
351 });
352 irBuilder.state.breakCollectors.removeLast();
353 bool hasBreaks = !jumps.isEmpty;
354 ir.Continuation joinContinuation;
355 if (hasBreaks) {
356 if (innerBuilder.isOpen) {
357 jumps.addJump(innerBuilder);
358 }
359
360 // All jumps to the break continuation must be in the scope of the
361 // continuation's binding. The continuation is bound just outside the
362 // body to satisfy this property without extra analysis.
363 // As a consequence, the break continuation needs parameters for all
364 // local variables in scope at the exit from the body.
365 List<ir.Parameter> parameters =
366 new List<ir.Parameter>.generate(irBuilder.environment.length, (i) {
367 return new ir.Parameter(irBuilder.environment.index2variable[i]);
368 });
369 joinContinuation = new ir.Continuation(parameters);
370 irBuilder.invokeFullJoin(joinContinuation, jumps, recursive: false);
371 irBuilder.add(new ir.LetCont(joinContinuation,
372 innerBuilder._root));
373 for (int i = 0; i < irBuilder.environment.length; ++i) {
374 irBuilder.environment.index2value[i] = parameters[i];
375 }
376 } else {
377 if (innerBuilder._root != null) {
378 irBuilder.add(innerBuilder._root);
379 irBuilder._current = innerBuilder._current;
380 irBuilder.environment = innerBuilder.environment;
381 }
382 }
383 return null;
384 }
385
386 visitWhile(ast.While node) {
387 irBuilder.buildWhile(
388 buildCondition: subbuild(node.condition),
389 buildBody: subbuild(node.body),
390 target: elements.getTargetDefinition(node),
391 closureScope: getClosureScopeForNode(node));
392 }
393
394 visitForIn(ast.ForIn node) {
395 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions]
396 // (defining a new local variable) or a send designating some existing
397 // variable.
398 ast.Node identifier = node.declaredIdentifier;
399 ast.VariableDefinitions variableDeclaration =
400 identifier.asVariableDefinitions();
401 Element variableElement = elements.getForInVariable(node);
402 Selector selector = elements.getSelector(identifier);
403
404 irBuilder.buildForIn(
405 buildExpression: subbuild(node.expression),
406 buildVariableDeclaration: subbuild(variableDeclaration),
407 variableElement: variableElement,
408 variableSelector: selector,
409 buildBody: subbuild(node.body),
410 target: elements.getTargetDefinition(node),
411 closureScope: getClosureScopeForNode(node));
412 }
413
414 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
415 assert(irBuilder.isOpen);
416 if (node.modifiers.isConst) {
417 for (ast.SendSet definition in node.definitions.nodes) {
418 assert(!definition.arguments.isEmpty);
419 assert(definition.arguments.tail.isEmpty);
420 VariableElement element = elements[definition];
421 ConstantExpression value = getConstantForVariable(element);
422 irBuilder.declareLocalConstant(element, value);
423 }
424 } else {
425 for (ast.Node definition in node.definitions.nodes) {
426 Element element = elements[definition];
427 ir.Primitive initialValue;
428 // Definitions are either SendSets if there is an initializer, or
429 // Identifiers if there is no initializer.
430 if (definition is ast.SendSet) {
431 assert(!definition.arguments.isEmpty);
432 assert(definition.arguments.tail.isEmpty);
433 initialValue = visit(definition.arguments.head);
434 } else {
435 assert(definition is ast.Identifier);
436 }
437 irBuilder.declareLocalVariable(element, initialValue: initialValue);
438 }
439 }
440 return null;
441 }
442
443 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
444 // where (C', x) = Build(e, C)
445 //
446 // Return without a subexpression is translated as if it were return null.
447 ir.Primitive visitReturn(ast.Return node) {
448 assert(irBuilder.isOpen);
449 assert(invariant(node, node.beginToken.value != 'native'));
450 irBuilder.buildReturn(build(node.expression));
451 return null;
452 }
453
454 // ==== Expressions ====
455 ir.Primitive visitConditional(ast.Conditional node) {
456 return irBuilder.buildConditional(
457 build(node.condition),
458 subbuild(node.thenExpression),
459 subbuild(node.elseExpression));
460 }
461
462 // For all simple literals:
463 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
464 ir.Primitive visitLiteralBool(ast.LiteralBool node) {
465 assert(irBuilder.isOpen);
466 return translateConstant(node);
467 }
468
469 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) {
470 assert(irBuilder.isOpen);
471 return translateConstant(node);
472 }
473
474 ir.Primitive visitLiteralInt(ast.LiteralInt node) {
475 assert(irBuilder.isOpen);
476 return translateConstant(node);
477 }
478
479 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
480 assert(irBuilder.isOpen);
481 return translateConstant(node);
482 }
483
484 ir.Primitive visitLiteralString(ast.LiteralString node) {
485 assert(irBuilder.isOpen);
486 return translateConstant(node);
487 }
488
489 ConstantExpression getConstantForNode(ast.Node node) {
490 ConstantExpression constant =
491 compiler.backend.constantCompilerTask.compileNode(node, elements);
492 assert(invariant(node, constant != null,
493 message: 'No constant computed for $node'));
494 return constant;
495 }
496
497 ConstantExpression getConstantForVariable(VariableElement element) {
498 ConstantExpression constant =
499 compiler.backend.constants.getConstantForVariable(element);
500 assert(invariant(element, constant != null,
501 message: 'No constant computed for $element'));
502 return constant;
503 }
504
505 ir.Primitive visitLiteralList(ast.LiteralList node) {
506 if (node.isConst) {
507 return translateConstant(node);
508 }
509 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
510 InterfaceType type = elements.getType(node);
511 return irBuilder.buildListLiteral(type, values);
512 }
513
514 ir.Primitive visitLiteralMap(ast.LiteralMap node) {
515 if (node.isConst) {
516 return translateConstant(node);
517 }
518 InterfaceType type = elements.getType(node);
519 return irBuilder.buildMapLiteral(
520 type,
521 node.entries.nodes.map((e) => e.key),
522 node.entries.nodes.map((e) => e.value),
523 build);
524 }
525
526 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) {
527 assert(irBuilder.isOpen);
528 return translateConstant(node);
529 }
530
531 ir.Primitive visitIdentifier(ast.Identifier node) {
532 // "this" is the only identifier that should be met by the visitor.
533 assert(node.isThis());
534 return irBuilder.buildThis();
535 }
536
537 ir.Primitive visitParenthesizedExpression(
538 ast.ParenthesizedExpression node) {
539 assert(irBuilder.isOpen);
540 return visit(node.expression);
541 }
542
543 // Stores the result of visiting a CascadeReceiver, so we can return it from
544 // its enclosing Cascade.
545 ir.Primitive _currentCascadeReceiver;
546
547 ir.Primitive visitCascadeReceiver(ast.CascadeReceiver node) {
548 assert(irBuilder.isOpen);
549 return _currentCascadeReceiver = visit(node.expression);
550 }
551
552 ir.Primitive visitCascade(ast.Cascade node) {
553 assert(irBuilder.isOpen);
554 var oldCascadeReceiver = _currentCascadeReceiver;
555 // Throw away the result of visiting the expression.
556 // Instead we return the result of visiting the CascadeReceiver.
557 this.visit(node.expression);
558 ir.Primitive receiver = _currentCascadeReceiver;
559 _currentCascadeReceiver = oldCascadeReceiver;
560 return receiver;
561 }
562
563 // ==== Sends ====
564 ir.Primitive visitAssert(ast.Send node) {
565 assert(irBuilder.isOpen);
566 return giveup(node, 'Assert');
567 }
568
569 ir.Primitive visitNamedArgument(ast.NamedArgument node) {
570 assert(irBuilder.isOpen);
571 return visit(node.expression);
572 }
573
574 ir.Primitive visitClosureSend(ast.Send node) {
575 assert(irBuilder.isOpen);
576 Element element = elements[node];
577 Selector selector = elements.getSelector(node);
578 ir.Primitive receiver = (element == null)
579 ? visit(node.selector)
580 : irBuilder.buildLocalGet(element);
581 List<ir.Primitive> arguments = node.arguments.mapToList(visit);
582 arguments = normalizeDynamicArguments(selector, arguments);
583 return irBuilder.buildFunctionExpressionInvocation(
584 receiver, selector, arguments);
585 }
586
587 /// If [node] is null, returns this.
588 /// If [node] is super, returns null (for special handling)
589 /// Otherwise visits [node] and returns the result.
590 ir.Primitive visitReceiver(ast.Expression node) {
591 if (node == null) return irBuilder.buildThis();
592 if (node.isSuper()) return null;
593 return visit(node);
594 }
595
596 /// Returns `true` if [node] is a super call.
597 // TODO(johnniwinther): Remove the need for this.
598 bool isSuperCall(ast.Send node) {
599 return node != null && node.receiver != null && node.receiver.isSuper();
600 }
601
602 ir.Primitive visitDynamicSend(ast.Send node) {
603 assert(irBuilder.isOpen);
604 Selector selector = elements.getSelector(node);
605 ir.Primitive receiver = visitReceiver(node.receiver);
606 List<ir.Primitive> arguments = node.arguments.mapToList(visit);
607 arguments = normalizeDynamicArguments(selector, arguments);
608 return irBuilder.buildDynamicInvocation(receiver, selector, arguments);
609 }
610
611 _GetterElements translateGetter(ast.Send node, Selector selector) {
612 Element element = elements[node];
613 ir.Primitive result;
614 ir.Primitive receiver;
615 ir.Primitive index;
616
617 if (element != null && element.isConst) {
618 // Reference to constant local, top-level or static field
619 result = translateConstant(node);
620 } else if (Elements.isLocal(element)) {
621 // Reference to local variable
622 result = irBuilder.buildLocalGet(element);
623 } else if (element == null ||
624 Elements.isInstanceField(element) ||
625 Elements.isInstanceMethod(element) ||
626 selector.isIndex ||
627 // TODO(johnniwinther): clean up semantics of resolution.
628 node.isSuperCall) {
629 // Dynamic dispatch to a getter. Sometimes resolution will suggest a
630 // target element, but in these cases we must still emit a dynamic
631 // dispatch. The target element may be an instance method in case we are
632 // converting a method to a function object.
633
634 receiver = visitReceiver(node.receiver);
635 List<ir.Primitive> arguments = new List<ir.Primitive>();
636 if (selector.isIndex) {
637 index = visit(node.arguments.head);
638 arguments.add(index);
639 }
640
641 assert(selector.kind == SelectorKind.GETTER ||
642 selector.kind == SelectorKind.INDEX);
643 if (isSuperCall(node)) {
644 result = irBuilder.buildSuperInvocation(element, selector, arguments);
645 } else {
646 result =
647 irBuilder.buildDynamicInvocation(receiver, selector, arguments);
648 }
649 } else if (element.isField || element.isGetter || element.isErroneous ||
650 element.isSetter) {
651 // TODO(johnniwinther): Change handling of setter selectors.
652 // Access to a static field or getter (non-static case handled above).
653 // Even if there is only a setter, we compile as if it was a getter,
654 // so the vm can fail at runtime.
655 assert(selector.kind == SelectorKind.GETTER ||
656 selector.kind == SelectorKind.SETTER);
657 result = irBuilder.buildStaticGet(element, selector);
658 } else if (Elements.isStaticOrTopLevelFunction(element)) {
659 // Convert a top-level or static function to a function object.
660 result = translateConstant(node);
661 } else {
662 throw "Unexpected SendSet getter: $node, $element";
663 }
664 return new _GetterElements(
665 result: result,index: index, receiver: receiver);
666 }
667
668 ir.Primitive visitGetterSend(ast.Send node) {
669 assert(irBuilder.isOpen);
670 return translateGetter(node, elements.getSelector(node)).result;
671
672 }
673
674 ir.Primitive translateLogicalOperator(ast.Operator op,
675 ast.Expression left,
676 ast.Expression right) {
677 ir.Primitive leftValue = visit(left);
678
679 ir.Primitive buildRightValue(IrBuilder rightBuilder) {
680 return withBuilder(rightBuilder, () => visit(right));
681 }
682
683 return irBuilder.buildLogicalOperator(
684 leftValue, buildRightValue, isLazyOr: op.source == '||');
685 }
686
687 ir.Primitive visitOperatorSend(ast.Send node) {
688 assert(irBuilder.isOpen);
689 ast.Operator op = node.selector;
690 if (isUserDefinableOperator(op.source)) {
691 return visitDynamicSend(node);
692 }
693 if (op.source == '&&' || op.source == '||') {
694 assert(node.receiver != null);
695 assert(!node.arguments.isEmpty);
696 assert(node.arguments.tail.isEmpty);
697 return translateLogicalOperator(op, node.receiver, node.arguments.head);
698 }
699 if (op.source == "!") {
700 assert(node.receiver != null);
701 assert(node.arguments.isEmpty);
702 return irBuilder.buildNegation(visit(node.receiver));
703 }
704 if (op.source == "!=") {
705 assert(node.receiver != null);
706 assert(!node.arguments.isEmpty);
707 assert(node.arguments.tail.isEmpty);
708 return irBuilder.buildNegation(visitDynamicSend(node));
709 }
710 assert(invariant(node, op.source == "is" || op.source == "as",
711 message: "unexpected operator $op"));
712 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast);
713 ir.Primitive receiver = visit(node.receiver);
714 return irBuilder.buildTypeOperator(
715 receiver, type,
716 isTypeTest: op.source == "is",
717 isNotCheck: node.isIsNotCheck);
718 }
719
720 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]]
721 // where (C', xs) = arguments.fold(Build, C)
722 ir.Primitive visitStaticSend(ast.Send node) {
723 assert(irBuilder.isOpen);
724 Element element = elements[node];
725 assert(!element.isConstructor);
726 // TODO(lry): support foreign functions.
727 if (element.isForeign(compiler.backend)) {
728 return giveup(node, 'StaticSend: foreign');
729 }
730
731 Selector selector = elements.getSelector(node);
732
733 List<ir.Primitive> arguments =
734 node.arguments.mapToList(visit, growable:false);
735 arguments = normalizeStaticArguments(selector, element, arguments);
736 return irBuilder.buildStaticInvocation(element, selector, arguments);
737 }
738
739 ir.Primitive visitSuperSend(ast.Send node) {
740 assert(irBuilder.isOpen);
741 if (node.isPropertyAccess) {
742 return visitGetterSend(node);
743 } else {
744 Selector selector = elements.getSelector(node);
745 Element target = elements[node];
746 List<ir.Primitive> arguments = node.arguments.mapToList(visit);
747 arguments = normalizeStaticArguments(selector, target, arguments);
748 return irBuilder.buildSuperInvocation(target, selector, arguments);
749 }
750 }
751
752 visitTypePrefixSend(ast.Send node) {
753 compiler.internalError(node, "visitTypePrefixSend should not be called.");
754 }
755
756 ir.Primitive visitTypeLiteralSend(ast.Send node) {
757 assert(irBuilder.isOpen);
758 // If the user is trying to invoke the type literal or variable,
759 // it must be treated as a function call.
760 if (node.argumentsNode != null) {
761 // TODO(sigurdm): Handle this to match proposed semantics of issue #19725.
762 return giveup(node, 'Type literal invoked as function');
763 }
764
765 DartType type = elements.getTypeLiteralType(node);
766 if (type is TypeVariableType) {
767 ir.Primitive prim = new ir.ReifyTypeVar(type.element);
768 irBuilder.add(new ir.LetPrim(prim));
769 return prim;
770 } else {
771 return translateConstant(node);
772 }
773 }
774
775 ir.Primitive visitSendSet(ast.SendSet node) {
776 assert(irBuilder.isOpen);
777 Element element = elements[node];
778 ast.Operator op = node.assignmentOperator;
779 // For complex operators, this is the result of getting (before assigning)
780 ir.Primitive originalValue;
781 // For []+= style operators, this saves the index.
782 ir.Primitive index;
783 ir.Primitive receiver;
784 // This is what gets assigned.
785 ir.Primitive valueToStore;
786 Selector selector = elements.getSelector(node);
787 Selector operatorSelector =
788 elements.getOperatorSelectorInComplexSendSet(node);
789 Selector getterSelector =
790 elements.getGetterSelectorInComplexSendSet(node);
791 assert(
792 // Indexing send-sets have an argument for the index.
793 (selector.isIndexSet ? 1 : 0) +
794 // Non-increment send-sets have one more argument.
795 (ast.Operator.INCREMENT_OPERATORS.contains(op.source) ? 0 : 1)
796 == node.argumentCount());
797
798 ast.Node getAssignArgument() {
799 assert(invariant(node, !node.arguments.isEmpty,
800 message: "argument expected"));
801 return selector.isIndexSet
802 ? node.arguments.tail.head
803 : node.arguments.head;
804 }
805
806 // Get the value into valueToStore
807 if (op.source == "=") {
808 if (selector.isIndexSet) {
809 receiver = visitReceiver(node.receiver);
810 index = visit(node.arguments.head);
811 } else if (element == null || Elements.isInstanceField(element)) {
812 receiver = visitReceiver(node.receiver);
813 }
814 valueToStore = visit(getAssignArgument());
815 } else {
816 // Get the original value into getter
817 assert(ast.Operator.COMPLEX_OPERATORS.contains(op.source));
818
819 _GetterElements getterResult = translateGetter(node, getterSelector);
820 index = getterResult.index;
821 receiver = getterResult.receiver;
822 originalValue = getterResult.result;
823
824 // Do the modification of the value in getter.
825 ir.Primitive arg;
826 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) {
827 arg = irBuilder.buildIntegerLiteral(1);
828 } else {
829 arg = visit(getAssignArgument());
830 }
831 valueToStore = new ir.Parameter(null);
832 ir.Continuation k = new ir.Continuation([valueToStore]);
833 ir.Expression invoke =
834 new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]);
835 irBuilder.add(new ir.LetCont(k, invoke));
836 }
837
838 if (Elements.isLocal(element)) {
839 irBuilder.buildLocalSet(element, valueToStore);
840 } else if ((!node.isSuperCall && Elements.isErroneous(element)) ||
841 Elements.isStaticOrTopLevel(element)) {
842 irBuilder.buildStaticSet(
843 element, elements.getSelector(node), valueToStore);
844 } else {
845 // Setter or index-setter invocation
846 Selector selector = elements.getSelector(node);
847 assert(selector.kind == SelectorKind.SETTER ||
848 selector.kind == SelectorKind.INDEX);
849 if (selector.isIndexSet) {
850 if (isSuperCall(node)) {
851 irBuilder.buildSuperIndexSet(element, index, valueToStore);
852 } else {
853 irBuilder.buildDynamicIndexSet(receiver, index, valueToStore);
854 }
855 } else {
856 if (isSuperCall(node)) {
857 irBuilder.buildSuperSet(element, selector, valueToStore);
858 } else {
859 irBuilder.buildDynamicSet(receiver, selector, valueToStore);
860 }
861 }
862 }
863
864 if (node.isPostfix) {
865 assert(originalValue != null);
866 return originalValue;
867 } else {
868 return valueToStore;
869 }
870 }
871
872 ir.Primitive visitNewExpression(ast.NewExpression node) {
873 if (node.isConst) {
874 return translateConstant(node);
875 }
876 FunctionElement element = elements[node.send];
877 Selector selector = elements.getSelector(node.send);
878 DartType type = elements.getType(node);
879 ast.Node selectorNode = node.send.selector;
880 List<ir.Primitive> arguments =
881 node.send.arguments.mapToList(visit, growable:false);
882 arguments = normalizeStaticArguments(selector, element, arguments);
883 return irBuilder.buildConstructorInvocation(
884 element, selector, type, arguments);
885 }
886
887 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
888 assert(irBuilder.isOpen);
889 ir.Primitive first = visit(node.first);
890 ir.Primitive second = visit(node.second);
891 return irBuilder.buildStringConcatenation([first, second]);
892 }
893
894 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) {
895 assert(irBuilder.isOpen);
896 List<ir.Primitive> arguments = [];
897 arguments.add(visitLiteralString(node.string));
898 var it = node.parts.iterator;
899 while (it.moveNext()) {
900 ast.StringInterpolationPart part = it.current;
901 arguments.add(visit(part.expression));
902 arguments.add(visitLiteralString(part.string));
903 }
904 return irBuilder.buildStringConcatenation(arguments);
905 }
906
907 ir.Primitive translateConstant(ast.Node node) {
908 assert(irBuilder.isOpen);
909 return irBuilder.buildConstantLiteral(getConstantForNode(node));
910 }
911
912 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
913 try {
914 return action();
915 } catch(e, tr) {
916 if (e == ABORT_IRNODE_BUILDER) {
917 return null;
918 }
919 rethrow;
920 }
921 }
922
923 void internalError(String reason, {ast.Node node}) {
924 giveup(node);
925 }
926 }
927
928 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
929
930 dynamic giveup(ast.Node node, [String reason]) {
931 throw ABORT_IRNODE_BUILDER;
932 }
933
934 /// Classifies local variables and local functions as captured, if they
935 /// are accessed from within a nested function.
936 ///
937 /// This class is specific to the [DartIrBuilder], in that it gives up if it
938 /// sees a feature that is currently unsupport by that builder. In particular,
939 /// loop variables captured in a for-loop initializer, condition, or update
940 /// expression are unsupported.
941 class DartCapturedVariables extends ast.Visitor
942 implements DartCapturedVariableInfo {
943 final TreeElements elements;
944 DartCapturedVariables(this.elements);
945
946 FunctionElement currentFunction;
947 bool insideInitializer = false;
948 Set<Local> capturedVariables = new Set<Local>();
949
950 void markAsCaptured(Local local) {
951 capturedVariables.add(local);
952 }
953
954 visit(ast.Node node) => node.accept(this);
955
956 visitNode(ast.Node node) {
957 node.visitChildren(this);
958 }
959
960 visitFor(ast.For node) {
961 if (node.initializer != null) visit(node.initializer);
962 if (node.condition != null) visit(node.condition);
963 if (node.update != null) visit(node.update);
964
965 // Give up if a variable was captured outside of the loop body.
966 if (node.initializer is ast.VariableDefinitions) {
967 ast.VariableDefinitions definitions = node.initializer;
968 for (ast.Node node in definitions.definitions.nodes) {
969 LocalElement loopVariable = elements[node];
970 if (capturedVariables.contains(loopVariable)) {
971 return giveup(node, 'For-loop variable captured in loop header');
972 }
973 }
974 }
975
976 if (node.body != null) visit(node.body);
977 }
978
979 void handleSend(ast.Send node) {
980 Element element = elements[node];
981 if (Elements.isLocal(element) &&
982 !element.isConst &&
983 element.enclosingElement != currentFunction) {
984 LocalElement local = element;
985 markAsCaptured(local);
986 }
987 }
988
989 visitSend(ast.Send node) {
990 handleSend(node);
991 node.visitChildren(this);
992 }
993
994 visitSendSet(ast.SendSet node) {
995 handleSend(node);
996 Element element = elements[node];
997 // Initializers in an initializer-list can communicate via parameters.
998 // If a parameter is stored in an initializer list we box it.
999 if (insideInitializer &&
1000 Elements.isLocal(element) &&
1001 element.isParameter) {
1002 LocalElement local = element;
1003 // TODO(sigurdm): Fix this.
1004 // Though these variables do not outlive the activation of the function,
1005 // they still need to be boxed. As a simplification, we treat them as if
1006 // they are captured by a closure (i.e., they do outlive the activation of
1007 // the function).
1008 markAsCaptured(local);
1009 }
1010 node.visitChildren(this);
1011 }
1012
1013 visitFunctionExpression(ast.FunctionExpression node) {
1014 FunctionElement oldFunction = currentFunction;
1015 currentFunction = elements[node];
1016 if (node.initializers != null) {
1017 insideInitializer = true;
1018 visit(node.initializers);
1019 insideInitializer = false;
1020 }
1021 visit(node.body);
1022 currentFunction = oldFunction;
1023 }
1024 }
1025
1026 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder].
1027 class DartIrBuilderVisitor extends IrBuilderVisitor {
1028 /// Promote the type of [irBuilder] to [DartIrBuilder].
1029 DartIrBuilder get irBuilder => super.irBuilder;
1030
1031 DartIrBuilderVisitor(TreeElements elements,
1032 Compiler compiler,
1033 SourceFile sourceFile)
1034 : super(elements, compiler, sourceFile);
1035
1036 DartIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
1037 DartCapturedVariables closures = new DartCapturedVariables(elements);
1038 if (!element.isSynthesized) {
1039 closures.visit(node);
1040 }
1041 return new DartIrBuilder(compiler.backend.constantSystem,
1042 element,
1043 closures);
1044 }
1045
1046 /// Recursively builds the IR for the given nested function.
1047 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
1048 FunctionElement element = elements[node];
1049 assert(invariant(element, element.isImplementation));
1050
1051 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element);
1052
1053 return withBuilder(builder, () => _makeFunctionBody(element, node));
1054 }
1055
1056 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1057 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1058 }
1059
1060 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1061 LocalFunctionElement element = elements[node.function];
1062 Object inner = makeSubFunction(node.function);
1063 irBuilder.declareLocalFunction(element, inner);
1064 }
1065
1066 ClosureScope getClosureScopeForNode(ast.Node node) => null;
1067 ClosureEnvironment getClosureEnvironment() => null;
1068
1069 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
1070 return nullIfGiveup(() {
1071 if (element is FieldElement) {
1072 return buildField(element);
1073 } else if (element is FunctionElement) {
1074 return buildFunction(element);
1075 } else {
1076 compiler.internalError(element, "Unexpected element type $element");
1077 }
1078 });
1079 }
1080
1081 /// Returns a [ir.FieldDefinition] describing the initializer of [element].
1082 ir.FieldDefinition buildField(FieldElement element) {
1083 assert(invariant(element, element.isImplementation));
1084 ast.VariableDefinitions definitions = element.node;
1085 ast.Node fieldDefinition = definitions.definitions.nodes.first;
1086 if (definitions.modifiers.isConst) {
1087 // TODO(sigurdm): Just return const value.
1088 }
1089 assert(fieldDefinition != null);
1090 assert(elements[fieldDefinition] != null);
1091
1092 IrBuilder builder = makeIRBuilder(fieldDefinition, element);
1093
1094 return withBuilder(builder, () {
1095 builder.buildFieldInitializerHeader(
1096 closureScope: getClosureScopeForNode(fieldDefinition));
1097 ir.Primitive initializer;
1098 if (fieldDefinition is ast.SendSet) {
1099 ast.SendSet sendSet = fieldDefinition;
1100 initializer = visit(sendSet.arguments.first);
1101 }
1102 return builder.makeFieldDefinition(initializer);
1103 });
1104 }
1105
1106 ir.FunctionDefinition buildFunction(FunctionElement element) {
1107 assert(invariant(element, element.isImplementation));
1108 ast.FunctionExpression node = element.node;
1109
1110 if (!element.isSynthesized) {
1111 assert(node != null);
1112 assert(elements[node] != null);
1113 } else {
1114 SynthesizedConstructorElementX constructor = element;
1115 if (!constructor.isDefaultConstructor) {
1116 giveup(null, 'cannot handle synthetic forwarding constructors');
1117 }
1118 }
1119
1120 IrBuilder builder = makeIRBuilder(node, element);
1121
1122 return withBuilder(builder, () => _makeFunctionBody(element, node));
1123 }
1124
1125 List<ir.Primitive> normalizeStaticArguments(
1126 Selector selector,
1127 FunctionElement target,
1128 List<ir.Primitive> arguments) {
1129 return arguments;
1130 }
1131
1132 List<ir.Primitive> normalizeDynamicArguments(
1133 Selector selector,
1134 List<ir.Primitive> arguments) {
1135 return arguments;
1136 }
1137 }
1138
1139 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
1140 class JsIrBuilderVisitor extends IrBuilderVisitor {
1141 /// Promote the type of [irBuilder] to [JsIrBuilder].
1142 JsIrBuilder get irBuilder => super.irBuilder;
1143
1144 /// Result of closure conversion for the current body of code.
1145 ///
1146 /// Will be initialized upon entering the body of a function.
1147 /// It is computed by the [ClosureTranslator].
1148 ClosureClassMap closureMap;
1149
1150 /// During construction of a constructor factory, [fieldValues] maps fields
1151 /// to the primitive containing their initial value.
1152 Map<FieldElement, ir.Primitive> fieldValues = <FieldElement, ir.Primitive>{};
1153
1154 JsIrBuilderVisitor(TreeElements elements,
1155 Compiler compiler,
1156 SourceFile sourceFile)
1157 : super(elements, compiler, sourceFile);
1158
1159 /// Builds the IR for creating an instance of the closure class corresponding
1160 /// to the given nested function.
1161 ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
1162 ClosureClassMap innerMap =
1163 compiler.closureToClassMapper.getMappingForNestedFunction(node);
1164 ClosureClassElement closureClass = innerMap.closureClassElement;
1165 return closureClass;
1166 }
1167
1168 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1169 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1170 }
1171
1172 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1173 LocalFunctionElement element = elements[node.function];
1174 Object inner = makeSubFunction(node.function);
1175 irBuilder.declareLocalFunction(element, inner);
1176 }
1177
1178 Map mapValues(Map map, dynamic fn(dynamic)) {
1179 Map result = {};
1180 map.forEach((key, value) {
1181 result[key] = fn(value);
1182 });
1183 return result;
1184 }
1185
1186 /// Converts closure.dart's CapturedVariable into a ClosureLocation.
1187 /// There is a 1:1 corresponce between these; we do this because the
1188 /// IR builder should not depend on synthetic elements.
1189 ClosureLocation getLocation(CapturedVariable v) {
1190 if (v is BoxFieldElement) {
1191 return new ClosureLocation(v.box, v);
1192 } else {
1193 ClosureFieldElement field = v;
1194 return new ClosureLocation(null, field);
1195 }
1196 }
1197
1198 /// If the current function is a nested function with free variables (or a
1199 /// captured reference to `this`), returns a [ClosureEnvironment]
1200 /// indicating how to access these.
1201 ClosureEnvironment getClosureEnvironment() {
1202 if (closureMap.closureElement == null) return null;
1203 return new ClosureEnvironment(
1204 closureMap.closureElement,
1205 closureMap.thisLocal,
1206 mapValues(closureMap.freeVariableMap, getLocation));
1207 }
1208
1209 /// If [node] has declarations for variables that should be boxed,
1210 /// returns a [ClosureScope] naming a box to create, and enumerating the
1211 /// variables that should be stored in the box.
1212 ///
1213 /// Also see [ClosureScope].
1214 ClosureScope getClosureScopeForNode(ast.Node node) {
1215 closurelib.ClosureScope scope = closureMap.capturingScopes[node];
1216 if (scope == null) return null;
1217 // We translate a ClosureScope from closure.dart into IR builder's variant
1218 // because the IR builder should not depend on the synthetic elements
1219 // created in closure.dart.
1220 return new ClosureScope(scope.boxElement,
1221 mapValues(scope.capturedVariables, getLocation),
1222 scope.boxedLoopVariables);
1223 }
1224
1225 /// Returns the [ClosureScope] for any function, possibly different from the
1226 /// one currently being built.
1227 ClosureScope getClosureScopeForFunction(FunctionElement function) {
1228 ClosureClassMap map =
1229 compiler.closureToClassMapper.computeClosureToClassMapping(
1230 function,
1231 function.node,
1232 elements);
1233 closurelib.ClosureScope scope = map.capturingScopes[function.node];
1234 if (scope == null) return null;
1235 return new ClosureScope(scope.boxElement,
1236 mapValues(scope.capturedVariables, getLocation),
1237 scope.boxedLoopVariables);
1238 }
1239
1240 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
1241 return nullIfGiveup(() {
1242 switch (element.kind) {
1243 case ElementKind.GENERATIVE_CONSTRUCTOR:
1244 return buildConstructor(element);
1245
1246 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
1247 return buildConstructorBody(element);
1248
1249 case ElementKind.FUNCTION:
1250 case ElementKind.GETTER:
1251 case ElementKind.SETTER:
1252 return buildFunction(element);
1253
1254 default:
1255 compiler.internalError(element, "Unexpected element type $element");
1256 }
1257 });
1258 }
1259
1260 /// Builds the IR for an [expression] taken from a different [context].
1261 ///
1262 /// Such expressions need to be compiled with a different [sourceFile] and
1263 /// [elements] mapping.
1264 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) {
1265 JsIrBuilderVisitor visitor = new JsIrBuilderVisitor(
1266 context.resolvedAst.elements,
1267 compiler,
1268 elementSourceFile(context));
1269 return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
1270 }
1271
1272 /// Builds the IR for a constant taken from a different [context].
1273 ///
1274 /// Such constants need to be compiled with a different [sourceFile] and
1275 /// [elements] mapping.
1276 ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
1277 JsIrBuilderVisitor visitor = new JsIrBuilderVisitor(
1278 context.resolvedAst.elements,
1279 compiler,
1280 elementSourceFile(context));
1281 return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
1282 }
1283
1284 /// Builds the IR for a given constructor.
1285 ///
1286 /// 1. Evaluates all own or inherited field initializers.
1287 /// 2. Creates the object and assigns its fields.
1288 /// 3. Calls constructor body and super constructor bodies.
1289 /// 4. Returns the created object.
1290 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
1291 constructor = constructor.implementation;
1292 ClassElement classElement = constructor.enclosingClass.implementation;
1293
1294 JsIrBuilder builder =
1295 new JsIrBuilder(compiler.backend.constantSystem, constructor);
1296
1297 return withBuilder(builder, () {
1298 // Setup parameters and create a box if anything is captured.
1299 List<ParameterElement> parameters = [];
1300 constructor.functionSignature.orderedForEachParameter(parameters.add);
1301 builder.buildFunctionHeader(parameters,
1302 closureScope: getClosureScopeForFunction(constructor));
1303
1304 // -- Step 1: evaluate field initializers ---
1305 // Evaluate field initializers in constructor and super constructors.
1306 List<ConstructorElement> constructorList = <ConstructorElement>[];
1307 evaluateConstructorFieldInitializers(constructor, constructorList);
1308
1309 // All parameters in all constructors are now bound in the environment.
1310 // BoxLocals for captured parameters are also in the environment.
1311 // The initial value of all fields are now bound in [fieldValues].
1312
1313 // --- Step 2: create the object ---
1314 // Get the initial field values in the canonical order.
1315 List<ir.Primitive> instanceArguments = <ir.Primitive>[];
1316 classElement.forEachInstanceField((ClassElement c, FieldElement field) {
1317 ir.Primitive value = fieldValues[field];
1318 if (value != null) {
1319 instanceArguments.add(fieldValues[field]);
1320 } else {
1321 assert(Elements.isNativeOrExtendsNative(c));
1322 // Native fields are initialized elsewhere.
1323 }
1324 }, includeSuperAndInjectedMembers: true);
1325 ir.Primitive instance =
1326 new ir.CreateInstance(classElement, instanceArguments);
1327 irBuilder.add(new ir.LetPrim(instance));
1328
1329 // --- Step 3: call constructor bodies ---
1330 for (ConstructorElement target in constructorList) {
1331 ConstructorBodyElement bodyElement = getConstructorBody(target);
1332 if (bodyElement == null) continue; // Skip if constructor has no body.
1333 List<ir.Primitive> bodyArguments = <ir.Primitive>[];
1334 for (Local param in getConstructorBodyParameters(bodyElement)) {
1335 bodyArguments.add(irBuilder.environment.lookup(param));
1336 }
1337 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments);
1338 }
1339
1340 // --- step 4: return the created object ----
1341 irBuilder.buildReturn(instance);
1342
1343 return irBuilder.makeFunctionDefinition([]);
1344 });
1345 }
1346
1347 /// Evaluates all field initializers on [constructor] and all constructors
1348 /// invoked through `this()` or `super()` ("superconstructors").
1349 ///
1350 /// The resulting field values will be available in [fieldValues]. The values
1351 /// are not stored in any fields.
1352 ///
1353 /// This procedure assumes that the parameters to [constructor] are available
1354 /// in the IR builder's environment.
1355 ///
1356 /// The parameters to superconstructors are, however, assumed *not* to be in
1357 /// the environment, but will be put there by this procedure.
1358 ///
1359 /// All constructors will be added to [supers], with superconstructors first.
1360 void evaluateConstructorFieldInitializers(ConstructorElement constructor,
1361 List<ConstructorElement> supers) {
1362 // Evaluate declaration-site field initializers.
1363 ClassElement enclosingClass = constructor.enclosingClass.implementation;
1364 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) {
1365 if (field.initializer != null) {
1366 fieldValues[field] = inlineExpression(field, field.initializer);
1367 } else {
1368 if (Elements.isNativeOrExtendsNative(c)) {
1369 // Native field is initialized elsewhere.
1370 } else {
1371 // Fields without an initializer default to null.
1372 // This value will be overwritten below if an initializer is found.
1373 fieldValues[field] = irBuilder.buildNullLiteral();
1374 }
1375 }
1376 });
1377 // Evaluate initializing parameters, e.g. `Foo(this.x)`.
1378 constructor.functionSignature.orderedForEachParameter(
1379 (ParameterElement parameter) {
1380 if (parameter.isInitializingFormal) {
1381 InitializingFormalElement fieldParameter = parameter;
1382 fieldValues[fieldParameter.fieldElement] =
1383 irBuilder.buildLocalGet(parameter);
1384 }
1385 });
1386 // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
1387 ast.FunctionExpression node = constructor.node;
1388 bool hasConstructorCall = false; // Has this() or super() initializer?
1389 if (node != null && node.initializers != null) {
1390 for(ast.Node initializer in node.initializers) {
1391 if (initializer is ast.SendSet) {
1392 // Field initializer.
1393 FieldElement field = elements[initializer];
1394 fieldValues[field] =
1395 inlineExpression(constructor, initializer.arguments.head);
1396 } else if (initializer is ast.Send) {
1397 // Super or this initializer.
1398 ConstructorElement target = elements[initializer].implementation;
1399 Selector selector = elements.getSelector(initializer);
1400 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit);
1401 loadArguments(target, selector, arguments);
1402 evaluateConstructorFieldInitializers(target, supers);
1403 hasConstructorCall = true;
1404 } else {
1405 compiler.internalError(initializer,
1406 "Unexpected initializer type $initializer");
1407 }
1408 }
1409 }
1410 // If no super() or this() was found, also call default superconstructor.
1411 if (!hasConstructorCall && !enclosingClass.isObject) {
1412 ClassElement superClass = enclosingClass.superclass;
1413 FunctionElement target = superClass.lookupDefaultConstructor();
1414 if (target == null) {
1415 compiler.internalError(superClass, "No default constructor available.");
1416 }
1417 evaluateConstructorFieldInitializers(target, supers);
1418 }
1419 // Add this constructor after the superconstructors.
1420 supers.add(constructor);
1421 }
1422
1423 /// In preparation of inlining (part of) [target], the [arguments] are moved
1424 /// into the environment bindings for the corresponding parameters.
1425 ///
1426 /// Defaults for optional arguments are evaluated in order to ensure
1427 /// all parameters are available in the environment.
1428 void loadArguments(FunctionElement target,
1429 Selector selector,
1430 List<ir.Primitive> arguments) {
1431 target = target.implementation;
1432 FunctionSignature signature = target.functionSignature;
1433
1434 // Establish a scope in case parameters are captured.
1435 ClosureScope scope = getClosureScopeForFunction(target);
1436 irBuilder._enterScope(scope);
1437
1438 // Load required parameters
1439 int index = 0;
1440 signature.forEachRequiredParameter((ParameterElement param) {
1441 irBuilder.declareLocalVariable(param, initialValue: arguments[index]);
1442 index++;
1443 });
1444
1445 // Load optional parameters, evaluating default values for omitted ones.
1446 signature.forEachOptionalParameter((ParameterElement param) {
1447 ir.Primitive value;
1448 // Load argument if provided.
1449 if (signature.optionalParametersAreNamed) {
1450 int nameIndex = selector.namedArguments.indexOf(param.name);
1451 if (nameIndex != -1) {
1452 int translatedIndex = selector.positionalArgumentCount + nameIndex;
1453 value = arguments[translatedIndex];
1454 }
1455 } else if (index < arguments.length) {
1456 value = arguments[index];
1457 }
1458 // Load default if argument was not provided.
1459 if (value == null) {
1460 if (param.initializer != null) {
1461 value = inlineExpression(target, param.initializer);
1462 } else {
1463 value = irBuilder.buildNullLiteral();
1464 }
1465 }
1466 irBuilder.declareLocalVariable(param, initialValue: value);
1467 index++;
1468 });
1469 }
1470
1471 /**
1472 * Returns the constructor body associated with the given constructor or
1473 * creates a new constructor body, if none can be found.
1474 *
1475 * Returns `null` if the constructor does not have a body.
1476 */
1477 ConstructorBodyElement getConstructorBody(FunctionElement constructor) {
1478 // TODO(asgerf): This is largely inherited from the SSA builder.
1479 // The ConstructorBodyElement has an invalid function signature, but we
1480 // cannot add a BoxLocal as parameter, because BoxLocal is not an element.
1481 // Instead of forging ParameterElements to forge a FunctionSignature, we
1482 // need a way to create backend methods without creating more fake elements.
1483
1484 assert(constructor.isGenerativeConstructor);
1485 assert(invariant(constructor, constructor.isImplementation));
1486 if (constructor.isSynthesized) return null;
1487 ast.FunctionExpression node = constructor.node;
1488 // If we know the body doesn't have any code, we don't generate it.
1489 if (!node.hasBody()) return null;
1490 if (node.hasEmptyBody()) return null;
1491 ClassElement classElement = constructor.enclosingClass;
1492 ConstructorBodyElement bodyElement;
1493 classElement.forEachBackendMember((Element backendMember) {
1494 if (backendMember.isGenerativeConstructorBody) {
1495 ConstructorBodyElement body = backendMember;
1496 if (body.constructor == constructor) {
1497 bodyElement = backendMember;
1498 }
1499 }
1500 });
1501 if (bodyElement == null) {
1502 bodyElement = new ConstructorBodyElementX(constructor);
1503 classElement.addBackendMember(bodyElement);
1504
1505 if (constructor.isPatch) {
1506 // Create origin body element for patched constructors.
1507 ConstructorBodyElementX patch = bodyElement;
1508 ConstructorBodyElementX origin =
1509 new ConstructorBodyElementX(constructor.origin);
1510 origin.applyPatch(patch);
1511 classElement.origin.addBackendMember(bodyElement.origin);
1512 }
1513 }
1514 assert(bodyElement.isGenerativeConstructorBody);
1515 return bodyElement;
1516 }
1517
1518 /// The list of parameters to send from the generative constructor
1519 /// to the generative constructor body.
1520 ///
1521 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed
1522 /// containing the boxed parameters.
1523 ///
1524 /// For example, given the following constructor,
1525 ///
1526 /// Foo(x, y) : field = (() => ++x) { print(x + y) }
1527 ///
1528 /// the argument `x` would be replaced by a [BoxLocal]:
1529 ///
1530 /// Foo_body(box0, y) { print(box0.x + y) }
1531 ///
1532 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) {
1533 List<Local> parameters = <Local>[];
1534 ClosureScope scope = getClosureScopeForFunction(body.constructor);
1535 if (scope != null) {
1536 parameters.add(scope.box);
1537 }
1538 body.functionSignature.orderedForEachParameter((ParameterElement param) {
1539 if (scope != null && scope.capturedVariables.containsKey(param)) {
1540 // Do not pass this parameter; the box will carry its value.
1541 } else {
1542 parameters.add(param);
1543 }
1544 });
1545 return parameters;
1546 }
1547
1548 /// Builds the IR for the body of a constructor.
1549 ///
1550 /// This function is invoked from one or more "factory" constructors built by
1551 /// [buildConstructor].
1552 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) {
1553 ConstructorElement constructor = body.constructor;
1554 ast.FunctionExpression node = constructor.node;
1555 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
1556 constructor,
1557 node,
1558 elements);
1559
1560 JsIrBuilder builder =
1561 new JsIrBuilder(compiler.backend.constantSystem, body);
1562
1563 return withBuilder(builder, () {
1564 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body),
1565 getClosureScopeForNode(node));
1566 visit(node.body);
1567 return irBuilder.makeFunctionDefinition([]);
1568 });
1569 }
1570
1571 ir.FunctionDefinition buildFunction(FunctionElement element) {
1572 assert(invariant(element, element.isImplementation));
1573 ast.FunctionExpression node = element.node;
1574
1575 assert(!element.isSynthesized);
1576 assert(node != null);
1577 assert(elements[node] != null);
1578
1579 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
1580 element,
1581 node,
1582 elements);
1583 IrBuilder builder =
1584 new JsIrBuilder(compiler.backend.constantSystem, element);
1585 return withBuilder(builder, () => _makeFunctionBody(element, node));
1586 }
1587
1588 /// Creates a primitive for the default value of [parameter].
1589 ir.Primitive translateDefaultValue(ParameterElement parameter) {
1590 if (parameter.initializer == null) {
1591 return irBuilder.buildNullLiteral();
1592 } else {
1593 return inlineConstant(parameter.executableContext, parameter.initializer);
1594 }
1595 }
1596
1597 /// Inserts default arguments and normalizes order of named arguments.
1598 List<ir.Primitive> normalizeStaticArguments(
1599 Selector selector,
1600 FunctionElement target,
1601 List<ir.Primitive> arguments) {
1602 target = target.implementation;
1603 FunctionSignature signature = target.functionSignature;
1604 if (!signature.optionalParametersAreNamed &&
1605 signature.parameterCount == arguments.length) {
1606 // Optimization: don't copy the argument list for trivial cases.
1607 return arguments;
1608 }
1609
1610 List<ir.Primitive> result = <ir.Primitive>[];
1611 int i = 0;
1612 signature.forEachRequiredParameter((ParameterElement element) {
1613 result.add(arguments[i]);
1614 ++i;
1615 });
1616
1617 if (!signature.optionalParametersAreNamed) {
1618 signature.forEachOptionalParameter((ParameterElement element) {
1619 if (i < arguments.length) {
1620 result.add(arguments[i]);
1621 ++i;
1622 } else {
1623 result.add(translateDefaultValue(element));
1624 }
1625 });
1626 } else {
1627 int offset = i;
1628 // Iterate over the optional parameters of the signature, and try to
1629 // find them in [compiledNamedArguments]. If found, we use the
1630 // value in the temporary list, otherwise the default value.
1631 signature.orderedOptionalParameters.forEach((ParameterElement element) {
1632 int nameIndex = selector.namedArguments.indexOf(element.name);
1633 if (nameIndex != -1) {
1634 int translatedIndex = offset + nameIndex;
1635 result.add(arguments[translatedIndex]);
1636 } else {
1637 result.add(translateDefaultValue(element));
1638 }
1639 });
1640 }
1641 return result;
1642 }
1643
1644 /// Normalizes order of named arguments.
1645 List<ir.Primitive> normalizeDynamicArguments(
1646 Selector selector,
1647 List<ir.Primitive> arguments) {
1648 assert(arguments.length == selector.argumentCount);
1649 // Optimization: don't copy the argument list for trivial cases.
1650 if (selector.namedArguments.isEmpty) return arguments;
1651 List<ir.Primitive> result = <ir.Primitive>[];
1652 for (int i=0; i < selector.positionalArgumentCount; i++) {
1653 result.add(arguments[i]);
1654 }
1655 for (String argName in selector.getOrderedNamedArguments()) {
1656 int nameIndex = selector.namedArguments.indexOf(argName);
1657 int translatedIndex = selector.positionalArgumentCount + nameIndex;
1658 result.add(arguments[translatedIndex]);
1659 }
1660 return result;
1661 }
1662
1663 }
1664
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698