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

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

Powered by Google App Engine
This is Rietveld 408576698