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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder_visitor.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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.FunctionDefinition> nodes =
26 <Element, ir.FunctionDefinition>{};
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.FunctionDefinition getIr(Element element) => nodes[element.implementation];
35
36 void buildNodes({bool useNewBackend: false}) {
37 if (!irEnabled(useNewBackend: useNewBackend)) return;
38 measure(() {
39 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements;
40 resolved.forEach((AstElement element) {
41 if (canBuild(element)) {
42 TreeElements elementsMapping = element.resolvedAst.elements;
43 element = element.implementation;
44 compiler.withCurrentElement(element, () {
45 SourceFile sourceFile = elementSourceFile(element);
46 IrBuilderVisitor builder =
47 new IrBuilderVisitor(elementsMapping, compiler, sourceFile);
48 ir.FunctionDefinition function;
49 function = builder.buildFunction(element);
50
51 if (function != null) {
52 nodes[element] = function;
53 compiler.tracer.traceCompilation(element.name, null);
54 compiler.tracer.traceGraph("IR Builder", function);
55 }
56 });
57 }
58 });
59 });
60 }
61
62 bool irEnabled({bool useNewBackend: false}) {
63 // TODO(sigurdm,kmillikin): Support checked-mode checks.
64 return (useNewBackend || const bool.fromEnvironment('USE_NEW_BACKEND')) &&
65 compiler.backend is DartBackend &&
66 !compiler.enableTypeAssertions &&
67 !compiler.enableConcreteTypeInference;
68 }
69
70 bool canBuild(Element element) {
71 FunctionElement function = element.asFunctionElement();
72 // TODO(kmillikin,sigurdm): support lazy field initializers.
73 if (function == null) return false;
74
75 if (!compiler.backend.shouldOutput(function)) return false;
76
77 assert(invariant(element, !function.isNative));
78
79 // TODO(kmillikin,sigurdm): Support constructors.
80 if (function is ConstructorElement) return false;
81
82 return true;
83 }
84
85 bool get inCheckedMode {
86 bool result = false;
87 assert((result = true));
88 return result;
89 }
90
91 SourceFile elementSourceFile(Element element) {
92 if (element is FunctionElement) {
93 FunctionElement functionElement = element;
94 if (functionElement.patch != null) element = functionElement.patch;
95 }
96 return element.compilationUnit.script.file;
97 }
98 }
99
100 class _GetterElements {
101 ir.Primitive result;
102 ir.Primitive index;
103 ir.Primitive receiver;
104
105 _GetterElements({this.result, this.index, this.receiver}) ;
106 }
107
108 /**
109 * A tree visitor that builds [IrNodes]. The visit methods add statements using
110 * to the [builder] and return the last added statement for trees that represent
111 * an expression.
112 */
113 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
114 with IrBuilderMixin<ast.Node> {
115 final Compiler compiler;
116 final SourceFile sourceFile;
117
118 // In SSA terms, join-point continuation parameters are the phis and the
119 // continuation invocation arguments are the corresponding phi inputs. To
120 // support name introduction and renaming for source level variables, we use
121 // nested (delimited) visitors for constructing subparts of the IR that will
122 // need renaming. Each source variable is assigned an index.
123 //
124 // Each nested visitor maintains a list of free variable uses in the body.
125 // These are implemented as a list of parameters, each with their own use
126 // list of references. When the delimited subexpression is plugged into the
127 // surrounding context, the free occurrences can be captured or become free
128 // occurrences in the next outer delimited subexpression.
129 //
130 // Each nested visitor maintains a list that maps indexes of variables
131 // assigned in the delimited subexpression to their reaching definition ---
132 // that is, the definition in effect at the hole in 'current'. These are
133 // used to determine if a join-point continuation needs to be passed
134 // arguments, and what the arguments are.
135
136 /// Construct a top-level visitor.
137 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
138 : super(elements);
139
140 /**
141 * Builds the [ir.FunctionDefinition] for a function element. In case the
142 * function uses features that cannot be expressed in the IR, this function
143 * returns `null`.
144 */
145 ir.FunctionDefinition buildFunction(FunctionElement functionElement) {
146 return nullIfGiveup(() => buildFunctionInternal(functionElement));
147 }
148
149 ir.FunctionDefinition buildFunctionInternal(FunctionElement element) {
150 assert(invariant(element, element.isImplementation));
151 ast.FunctionExpression function = element.node;
152 assert(function != null);
153 assert(!function.modifiers.isExternal);
154 assert(elements[function] != null);
155
156 DetectClosureVariables closureLocals = new DetectClosureVariables(elements);
157 closureLocals.visit(function);
158
159 return withBuilder(
160 new IrBuilder(compiler.backend.constantSystem,
161 element, closureLocals.usedFromClosure),
162 () {
163 FunctionSignature signature = element.functionSignature;
164 signature.orderedForEachParameter((ParameterElement parameterElement) {
165 irBuilder.createParameter(parameterElement);
166 });
167
168 List<ConstantExpression> defaults = new List<ConstantExpression>();
169 signature.orderedOptionalParameters.forEach((ParameterElement element) {
170 defaults.add(getConstantForVariable(element));
171 });
172
173 visit(function.body);
174 return irBuilder.buildFunctionDefinition(element, defaults);
175 });
176 }
177
178 ir.Primitive visit(ast.Node node) => node.accept(this);
179
180 // ==== Statements ====
181 visitBlock(ast.Block node) {
182 irBuilder.buildBlock(node.statements.nodes, build);
183 }
184
185 ir.Primitive visitBreakStatement(ast.BreakStatement node) {
186 if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
187 compiler.internalError(node, "'break' target not found");
188 }
189 return null;
190 }
191
192 ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
193 if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
194 compiler.internalError(node, "'continue' target not found");
195 }
196 return null;
197 }
198
199 // Build(EmptyStatement, C) = C
200 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
201 assert(irBuilder.isOpen);
202 return null;
203 }
204
205 // Build(ExpressionStatement(e), C) = C'
206 // where (C', _) = Build(e, C)
207 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) {
208 assert(irBuilder.isOpen);
209 visit(node.expression);
210 return null;
211 }
212
213 visitFor(ast.For node) {
214 // TODO(kmillikin,sigurdm): Handle closure variables declared in a for-loop.
215 if (node.initializer is ast.VariableDefinitions) {
216 ast.VariableDefinitions definitions = node.initializer;
217 for (ast.Node definition in definitions.definitions.nodes) {
218 Element element = elements[definition];
219 if (irBuilder.isClosureVariable(element)) {
220 return giveup(definition, 'Closure variable in for loop initializer');
221 }
222 }
223 }
224
225 JumpTarget target = elements.getTargetDefinition(node);
226 irBuilder.buildFor(
227 buildInitializer: subbuild(node.initializer),
228 buildCondition: subbuild(node.condition),
229 buildBody: subbuild(node.body),
230 buildUpdate: subbuildSequence(node.update),
231 target: target);
232 }
233
234 visitIf(ast.If node) {
235 irBuilder.buildIf(
236 build(node.condition),
237 subbuild(node.thenPart),
238 subbuild(node.elsePart));
239 }
240
241 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) {
242 ast.Statement body = node.statement;
243 return body is ast.Loop
244 ? visit(body)
245 : giveup(node, 'labeled statement');
246 }
247
248 visitWhile(ast.While node) {
249 irBuilder.buildWhile(
250 buildCondition: subbuild(node.condition),
251 buildBody: subbuild(node.body),
252 target: elements.getTargetDefinition(node));
253 }
254
255 visitForIn(ast.ForIn node) {
256 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions]
257 // (defining a new local variable) or a send designating some existing
258 // variable.
259 ast.Node identifier = node.declaredIdentifier;
260 ast.VariableDefinitions variableDeclaration =
261 identifier.asVariableDefinitions();
262 Element variableElement = elements.getForInVariable(node);
263 Selector selector = elements.getSelector(identifier);
264
265 irBuilder.buildForIn(
266 buildExpression: subbuild(node.expression),
267 buildVariableDeclaration: subbuild(variableDeclaration),
268 variableElement: variableElement,
269 variableSelector: selector,
270 buildBody: subbuild(node.body),
271 target: elements.getTargetDefinition(node));
272 }
273
274 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
275 assert(irBuilder.isOpen);
276 if (node.modifiers.isConst) {
277 for (ast.SendSet definition in node.definitions.nodes) {
278 assert(!definition.arguments.isEmpty);
279 assert(definition.arguments.tail.isEmpty);
280 VariableElement element = elements[definition];
281 ConstantExpression value = getConstantForVariable(element);
282 irBuilder.declareLocalConstant(element, value);
283 }
284 } else {
285 for (ast.Node definition in node.definitions.nodes) {
286 Element element = elements[definition];
287 ir.Primitive initialValue;
288 // Definitions are either SendSets if there is an initializer, or
289 // Identifiers if there is no initializer.
290 if (definition is ast.SendSet) {
291 assert(!definition.arguments.isEmpty);
292 assert(definition.arguments.tail.isEmpty);
293 initialValue = visit(definition.arguments.head);
294 } else {
295 assert(definition is ast.Identifier);
296 }
297 irBuilder.declareLocalVariable(element, initialValue: initialValue);
298 }
299 }
300 return null;
301 }
302
303 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
304 // where (C', x) = Build(e, C)
305 //
306 // Return without a subexpression is translated as if it were return null.
307 ir.Primitive visitReturn(ast.Return node) {
308 assert(irBuilder.isOpen);
309 assert(invariant(node, node.beginToken.value != 'native'));
310 irBuilder.buildReturn(build(node.expression));
311 return null;
312 }
313
314 // ==== Expressions ====
315 ir.Primitive visitConditional(ast.Conditional node) {
316 return irBuilder.buildConditional(
317 build(node.condition),
318 subbuild(node.thenExpression),
319 subbuild(node.elseExpression));
320 }
321
322 // For all simple literals:
323 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
324 ir.Primitive visitLiteralBool(ast.LiteralBool node) {
325 assert(irBuilder.isOpen);
326 return translateConstant(node);
327 }
328
329 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) {
330 assert(irBuilder.isOpen);
331 return translateConstant(node);
332 }
333
334 ir.Primitive visitLiteralInt(ast.LiteralInt node) {
335 assert(irBuilder.isOpen);
336 return translateConstant(node);
337 }
338
339 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
340 assert(irBuilder.isOpen);
341 return translateConstant(node);
342 }
343
344 ir.Primitive visitLiteralString(ast.LiteralString node) {
345 assert(irBuilder.isOpen);
346 return translateConstant(node);
347 }
348
349 ConstantExpression getConstantForNode(ast.Node node) {
350 ConstantExpression constant =
351 compiler.backend.constantCompilerTask.compileNode(node, elements);
352 assert(invariant(node, constant != null,
353 message: 'No constant computed for $node'));
354 return constant;
355 }
356
357 ConstantExpression getConstantForVariable(VariableElement element) {
358 ConstantExpression constant =
359 compiler.backend.constants.getConstantForVariable(element);
360 assert(invariant(element, constant != null,
361 message: 'No constant computed for $element'));
362 return constant;
363 }
364
365 ir.Primitive visitLiteralList(ast.LiteralList node) {
366 if (node.isConst) {
367 return translateConstant(node);
368 }
369 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
370 InterfaceType type = elements.getType(node);
371 return irBuilder.buildListLiteral(type, values);
372 }
373
374 ir.Primitive visitLiteralMap(ast.LiteralMap node) {
375 if (node.isConst) {
376 return translateConstant(node);
377 }
378 InterfaceType type = elements.getType(node);
379 return irBuilder.buildMapLiteral(
380 type,
381 node.entries.nodes.map((e) => e.key),
382 node.entries.nodes.map((e) => e.value),
383 build);
384 }
385
386 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) {
387 assert(irBuilder.isOpen);
388 return translateConstant(node);
389 }
390
391 ir.Primitive visitIdentifier(ast.Identifier node) {
392 // "this" is the only identifier that should be met by the visitor.
393 assert(node.isThis());
394 return irBuilder.buildThis();
395 }
396
397 ir.Primitive visitParenthesizedExpression(
398 ast.ParenthesizedExpression node) {
399 assert(irBuilder.isOpen);
400 return visit(node.expression);
401 }
402
403 // Stores the result of visiting a CascadeReceiver, so we can return it from
404 // its enclosing Cascade.
405 ir.Primitive _currentCascadeReceiver;
406
407 ir.Primitive visitCascadeReceiver(ast.CascadeReceiver node) {
408 assert(irBuilder.isOpen);
409 return _currentCascadeReceiver = visit(node.expression);
410 }
411
412 ir.Primitive visitCascade(ast.Cascade node) {
413 assert(irBuilder.isOpen);
414 var oldCascadeReceiver = _currentCascadeReceiver;
415 // Throw away the result of visiting the expression.
416 // Instead we return the result of visiting the CascadeReceiver.
417 this.visit(node.expression);
418 ir.Primitive receiver = _currentCascadeReceiver;
419 _currentCascadeReceiver = oldCascadeReceiver;
420 return receiver;
421 }
422
423 // ==== Sends ====
424 ir.Primitive visitAssert(ast.Send node) {
425 assert(irBuilder.isOpen);
426 return giveup(node, 'Assert');
427 }
428
429 ir.Primitive visitNamedArgument(ast.NamedArgument node) {
430 assert(irBuilder.isOpen);
431 return visit(node.expression);
432 }
433
434 ir.Primitive translateClosureCall(ir.Primitive receiver,
435 Selector closureSelector,
436 ast.NodeList arguments) {
437 Selector namedCallSelector = new Selector(closureSelector.kind,
438 "call",
439 closureSelector.library,
440 closureSelector.argumentCount,
441 closureSelector.namedArguments);
442 List<ir.Primitive> args = arguments.nodes.mapToList(visit, growable:false);
443 return irBuilder.buildDynamicInvocation(receiver, namedCallSelector, args);
444 }
445
446 ir.Primitive visitClosureSend(ast.Send node) {
447 assert(irBuilder.isOpen);
448 Element element = elements[node];
449 ir.Primitive closureTarget;
450 if (element == null) {
451 closureTarget = visit(node.selector);
452 } else if (irBuilder.isClosureVariable(element)) {
453 LocalElement local = element;
454 closureTarget = new ir.GetClosureVariable(local);
455 irBuilder.add(new ir.LetPrim(closureTarget));
456 } else {
457 assert(Elements.isLocal(element));
458 closureTarget = irBuilder.environment.lookup(element);
459 }
460 Selector closureSelector = elements.getSelector(node);
461 return translateClosureCall(closureTarget, closureSelector,
462 node.argumentsNode);
463 }
464
465 /// If [node] is null, returns this.
466 /// If [node] is super, returns null (for special handling)
467 /// Otherwise visits [node] and returns the result.
468 ir.Primitive visitReceiver(ast.Expression node) {
469 if (node == null) return irBuilder.buildThis();
470 if (node.isSuper()) return null;
471 return visit(node);
472 }
473
474 /// Returns `true` if [node] is a super call.
475 // TODO(johnniwinther): Remove the need for this.
476 bool isSuperCall(ast.Send node) {
477 return node != null && node.receiver != null && node.receiver.isSuper();
478 }
479
480 ir.Primitive visitDynamicSend(ast.Send node) {
481 assert(irBuilder.isOpen);
482 Selector selector = elements.getSelector(node);
483 ir.Primitive receiver = visitReceiver(node.receiver);
484 List<ir.Primitive> arguments = new List<ir.Primitive>();
485 for (ast.Node n in node.arguments) {
486 arguments.add(visit(n));
487 }
488 return irBuilder.buildDynamicInvocation(receiver, selector, arguments);
489 }
490
491 _GetterElements translateGetter(ast.Send node, Selector selector) {
492 Element element = elements[node];
493 ir.Primitive result;
494 ir.Primitive receiver;
495 ir.Primitive index;
496
497 if (element != null && element.isConst) {
498 // Reference to constant local, top-level or static field
499 result = translateConstant(node);
500 } else if (Elements.isLocal(element)) {
501 // Reference to local variable
502 result = irBuilder.buildLocalGet(element);
503 } else if (element == null ||
504 Elements.isInstanceField(element) ||
505 Elements.isInstanceMethod(element) ||
506 selector.isIndex ||
507 // TODO(johnniwinther): clean up semantics of resolution.
508 node.isSuperCall) {
509 // Dynamic dispatch to a getter. Sometimes resolution will suggest a
510 // target element, but in these cases we must still emit a dynamic
511 // dispatch. The target element may be an instance method in case we are
512 // converting a method to a function object.
513
514 receiver = visitReceiver(node.receiver);
515 List<ir.Primitive> arguments = new List<ir.Primitive>();
516 if (selector.isIndex) {
517 index = visit(node.arguments.head);
518 arguments.add(index);
519 }
520
521 assert(selector.kind == SelectorKind.GETTER ||
522 selector.kind == SelectorKind.INDEX);
523 if (isSuperCall(node)) {
524 result = irBuilder.buildSuperInvocation(selector, arguments);
525 } else {
526 result =
527 irBuilder.buildDynamicInvocation(receiver, selector, arguments);
528 }
529 } else if (element.isField || element.isGetter || element.isErroneous ||
530 element.isSetter) {
531 // TODO(johnniwinther): Change handling of setter selectors.
532 // Access to a static field or getter (non-static case handled above).
533 // Even if there is only a setter, we compile as if it was a getter,
534 // so the vm can fail at runtime.
535 assert(selector.kind == SelectorKind.GETTER ||
536 selector.kind == SelectorKind.SETTER);
537 result = irBuilder.buildStaticGet(element, selector);
538 } else if (Elements.isStaticOrTopLevelFunction(element)) {
539 // Convert a top-level or static function to a function object.
540 result = translateConstant(node);
541 } else {
542 throw "Unexpected SendSet getter: $node, $element";
543 }
544 return new _GetterElements(
545 result: result,index: index, receiver: receiver);
546 }
547
548 ir.Primitive visitGetterSend(ast.Send node) {
549 assert(irBuilder.isOpen);
550 return translateGetter(node, elements.getSelector(node)).result;
551
552 }
553
554 ir.Primitive translateLogicalOperator(ast.Operator op,
555 ast.Expression left,
556 ast.Expression right) {
557 ir.Primitive leftValue = visit(left);
558
559 ir.Primitive buildRightValue(IrBuilder rightBuilder) {
560 return withBuilder(rightBuilder, () => visit(right));
561 }
562
563 return irBuilder.buildLogicalOperator(
564 leftValue, buildRightValue, isLazyOr: op.source == '||');
565 }
566
567 ir.Primitive visitOperatorSend(ast.Send node) {
568 assert(irBuilder.isOpen);
569 ast.Operator op = node.selector;
570 if (isUserDefinableOperator(op.source)) {
571 return visitDynamicSend(node);
572 }
573 if (op.source == '&&' || op.source == '||') {
574 assert(node.receiver != null);
575 assert(!node.arguments.isEmpty);
576 assert(node.arguments.tail.isEmpty);
577 return translateLogicalOperator(op, node.receiver, node.arguments.head);
578 }
579 if (op.source == "!") {
580 assert(node.receiver != null);
581 assert(node.arguments.isEmpty);
582 return irBuilder.buildNegation(visit(node.receiver));
583 }
584 if (op.source == "!=") {
585 assert(node.receiver != null);
586 assert(!node.arguments.isEmpty);
587 assert(node.arguments.tail.isEmpty);
588 return irBuilder.buildNegation(visitDynamicSend(node));
589 }
590 assert(invariant(node, op.source == "is" || op.source == "as",
591 message: "unexpected operator $op"));
592 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast);
593 ir.Primitive receiver = visit(node.receiver);
594 return irBuilder.buildTypeOperator(
595 receiver, type,
596 isTypeTest: op.source == "is",
597 isNotCheck: node.isIsNotCheck);
598 }
599
600 // Build(StaticSend(f, arguments), C) = C[C'[InvokeStatic(f, xs)]]
601 // where (C', xs) = arguments.fold(Build, C)
602 ir.Primitive visitStaticSend(ast.Send node) {
603 assert(irBuilder.isOpen);
604 Element element = elements[node];
605 assert(!element.isConstructor);
606 // TODO(lry): support foreign functions.
607 if (element.isForeign(compiler.backend)) {
608 return giveup(node, 'StaticSend: foreign');
609 }
610
611 Selector selector = elements.getSelector(node);
612
613 // TODO(lry): support default arguments, need support for locals.
614 List<ir.Definition> arguments = node.arguments.mapToList(visit,
615 growable:false);
616 return irBuilder.buildStaticInvocation(element, selector, arguments);
617 }
618
619 ir.Primitive visitSuperSend(ast.Send node) {
620 assert(irBuilder.isOpen);
621 if (node.isPropertyAccess) {
622 return visitGetterSend(node);
623 } else {
624 Selector selector = elements.getSelector(node);
625 List<ir.Primitive> arguments = new List<ir.Primitive>();
626 for (ast.Node n in node.arguments) {
627 arguments.add(visit(n));
628 }
629 return irBuilder.buildSuperInvocation(selector, arguments);
630 }
631 }
632
633 visitTypePrefixSend(ast.Send node) {
634 compiler.internalError(node, "visitTypePrefixSend should not be called.");
635 }
636
637 ir.Primitive visitTypeLiteralSend(ast.Send node) {
638 assert(irBuilder.isOpen);
639 // If the user is trying to invoke the type literal or variable,
640 // it must be treated as a function call.
641 if (node.argumentsNode != null) {
642 // TODO(sigurdm): Handle this to match proposed semantics of issue #19725.
643 return giveup(node, 'Type literal invoked as function');
644 }
645
646 DartType type = elements.getTypeLiteralType(node);
647 if (type is TypeVariableType) {
648 ir.Primitive prim = new ir.ReifyTypeVar(type.element);
649 irBuilder.add(new ir.LetPrim(prim));
650 return prim;
651 } else {
652 return translateConstant(node);
653 }
654 }
655
656 ir.Primitive visitSendSet(ast.SendSet node) {
657 assert(irBuilder.isOpen);
658 Element element = elements[node];
659 ast.Operator op = node.assignmentOperator;
660 // For complex operators, this is the result of getting (before assigning)
661 ir.Primitive originalValue;
662 // For []+= style operators, this saves the index.
663 ir.Primitive index;
664 ir.Primitive receiver;
665 // This is what gets assigned.
666 ir.Primitive valueToStore;
667 Selector selector = elements.getSelector(node);
668 Selector operatorSelector =
669 elements.getOperatorSelectorInComplexSendSet(node);
670 Selector getterSelector =
671 elements.getGetterSelectorInComplexSendSet(node);
672 assert(
673 // Indexing send-sets have an argument for the index.
674 (selector.isIndexSet ? 1 : 0) +
675 // Non-increment send-sets have one more argument.
676 (ast.Operator.INCREMENT_OPERATORS.contains(op.source) ? 0 : 1)
677 == node.argumentCount());
678
679 ast.Node getAssignArgument() {
680 assert(invariant(node, !node.arguments.isEmpty,
681 message: "argument expected"));
682 return selector.isIndexSet
683 ? node.arguments.tail.head
684 : node.arguments.head;
685 }
686
687 // Get the value into valueToStore
688 if (op.source == "=") {
689 if (selector.isIndexSet) {
690 receiver = visitReceiver(node.receiver);
691 index = visit(node.arguments.head);
692 } else if (element == null || Elements.isInstanceField(element)) {
693 receiver = visitReceiver(node.receiver);
694 }
695 valueToStore = visit(getAssignArgument());
696 } else {
697 // Get the original value into getter
698 assert(ast.Operator.COMPLEX_OPERATORS.contains(op.source));
699
700 _GetterElements getterResult = translateGetter(node, getterSelector);
701 index = getterResult.index;
702 receiver = getterResult.receiver;
703 originalValue = getterResult.result;
704
705 // Do the modification of the value in getter.
706 ir.Primitive arg;
707 if (ast.Operator.INCREMENT_OPERATORS.contains(op.source)) {
708 arg = irBuilder.buildIntegerLiteral(1);
709 } else {
710 arg = visit(getAssignArgument());
711 }
712 valueToStore = new ir.Parameter(null);
713 ir.Continuation k = new ir.Continuation([valueToStore]);
714 ir.Expression invoke =
715 new ir.InvokeMethod(originalValue, operatorSelector, k, [arg]);
716 irBuilder.add(new ir.LetCont(k, invoke));
717 }
718
719 if (Elements.isLocal(element)) {
720 irBuilder.buildLocalSet(element, valueToStore);
721 } else if ((!node.isSuperCall && Elements.isErroneousElement(element)) ||
722 Elements.isStaticOrTopLevel(element)) {
723 irBuilder.buildStaticSet(
724 element, elements.getSelector(node), valueToStore);
725 } else {
726 // Setter or index-setter invocation
727 Selector selector = elements.getSelector(node);
728 assert(selector.kind == SelectorKind.SETTER ||
729 selector.kind == SelectorKind.INDEX);
730 if (selector.isIndexSet) {
731 if (isSuperCall(node)) {
732 irBuilder.buildSuperIndexSet(index, valueToStore);
733 } else {
734 irBuilder.buildDynamicIndexSet(receiver, index, valueToStore);
735 }
736 } else {
737 if (isSuperCall(node)) {
738 irBuilder.buildSuperSet(selector, valueToStore);
739 } else {
740 irBuilder.buildDynamicSet(receiver, selector, valueToStore);
741 }
742 }
743 }
744
745 if (node.isPostfix) {
746 assert(originalValue != null);
747 return originalValue;
748 } else {
749 return valueToStore;
750 }
751 }
752
753 ir.Primitive visitNewExpression(ast.NewExpression node) {
754 if (node.isConst) {
755 return translateConstant(node);
756 }
757 FunctionElement element = elements[node.send];
758 Selector selector = elements.getSelector(node.send);
759 DartType type = elements.getType(node);
760 ast.Node selectorNode = node.send.selector;
761 List<ir.Definition> arguments =
762 node.send.arguments.mapToList(visit, growable:false);
763 return irBuilder.buildConstructorInvocation(
764 element, selector, type, arguments);
765 }
766
767 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
768 assert(irBuilder.isOpen);
769 ir.Primitive first = visit(node.first);
770 ir.Primitive second = visit(node.second);
771 return irBuilder.buildStringConcatenation([first, second]);
772 }
773
774 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) {
775 assert(irBuilder.isOpen);
776 List<ir.Primitive> arguments = [];
777 arguments.add(visitLiteralString(node.string));
778 var it = node.parts.iterator;
779 while (it.moveNext()) {
780 ast.StringInterpolationPart part = it.current;
781 arguments.add(visit(part.expression));
782 arguments.add(visitLiteralString(part.string));
783 }
784 return irBuilder.buildStringConcatenation(arguments);
785 }
786
787 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) {
788 assert(irBuilder.isOpen);
789 if (constant == null) {
790 constant = getConstantForNode(node);
791 }
792 return irBuilder.buildConstantLiteral(constant);
793 }
794
795 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
796 // TODO(johnniwinther): Share the visitor.
797 return new IrBuilderVisitor(elements, compiler, sourceFile)
798 .buildFunctionInternal(elements[node]);
799 }
800
801 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
802 FunctionElement element = elements[node];
803 ir.FunctionDefinition inner = makeSubFunction(node);
804 ir.CreateFunction prim = new ir.CreateFunction(inner);
805 irBuilder.add(new ir.LetPrim(prim));
806 return prim;
807 }
808
809 ir.Primitive visitFunctionDeclaration(ast.FunctionDeclaration node) {
810 LocalFunctionElement element = elements[node.function];
811 ir.FunctionDefinition inner = makeSubFunction(node.function);
812 if (irBuilder.isClosureVariable(element)) {
813 irBuilder.add(new ir.DeclareFunction(element, inner));
814 } else {
815 ir.CreateFunction prim = new ir.CreateFunction(inner);
816 irBuilder.add(new ir.LetPrim(prim));
817 irBuilder.environment.extend(element, prim);
818 prim.useElementAsHint(element);
819 }
820 return null;
821 }
822
823 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
824
825 dynamic giveup(ast.Node node, [String reason]) {
826 throw ABORT_IRNODE_BUILDER;
827 }
828
829 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) {
830 try {
831 return action();
832 } catch(e, tr) {
833 if (e == ABORT_IRNODE_BUILDER) {
834 return null;
835 }
836 rethrow;
837 }
838 }
839
840 void internalError(String reason, {ast.Node node}) {
841 giveup(node);
842 }
843 }
844
845 /// Classifies local variables and local functions as 'closure variables'.
846 /// A closure variable is one that is accessed from an inner function nested
847 /// one or more levels inside the one that declares it.
848 class DetectClosureVariables extends ast.Visitor {
849 final TreeElements elements;
850 DetectClosureVariables(this.elements);
851
852 FunctionElement currentFunction;
853 Set<Local> usedFromClosure = new Set<Local>();
854 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>();
855
856 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity);
857
858 void markAsClosureVariable(Local local) {
859 usedFromClosure.add(local);
860 }
861
862 visit(ast.Node node) => node.accept(this);
863
864 visitNode(ast.Node node) {
865 node.visitChildren(this);
866 }
867
868 visitSend(ast.Send node) {
869 Element element = elements[node];
870 if (Elements.isLocal(element) &&
871 !element.isConst &&
872 element.enclosingElement != currentFunction) {
873 LocalElement local = element;
874 markAsClosureVariable(local);
875 }
876 node.visitChildren(this);
877 }
878
879 visitFunctionExpression(ast.FunctionExpression node) {
880 FunctionElement oldFunction = currentFunction;
881 currentFunction = elements[node];
882 visit(node.body);
883 currentFunction = oldFunction;
884 }
885 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698