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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.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 // IrNodes are kept in a separate library to have precise control over their
6 // dependencies on other parts of the system.
7 library dart2js.ir_nodes;
8
9 import '../constants/expressions.dart';
10 import '../constants/values.dart' as values show ConstantValue;
11 import '../dart2jslib.dart' as dart2js show invariant;
12 import '../elements/elements.dart';
13 import '../universe/universe.dart' show Selector, SelectorKind;
14 import '../dart_types.dart' show DartType, GenericType;
15
16 abstract class Node {
17 static int hashCount = 0;
18 final int hashCode = hashCount = (hashCount + 1) & 0x3fffffff;
19
20 /// A pointer to the parent node. Is null until set by optimization passes.
21 Node parent;
22
23 accept(Visitor visitor);
24 }
25
26 abstract class Expression extends Node {
27 Expression plug(Expression expr) => throw 'impossible';
28 }
29
30 /// The base class of things that variables can refer to: primitives,
31 /// continuations, function and continuation parameters, etc.
32 abstract class Definition extends Node {
33 // The head of a linked-list of occurrences, in no particular order.
34 Reference firstRef = null;
35
36 bool get hasAtMostOneUse => firstRef == null || firstRef.next == null;
37 bool get hasExactlyOneUse => firstRef != null && firstRef.next == null;
38 bool get hasAtLeastOneUse => firstRef != null;
39 bool get hasMultipleUses => !hasAtMostOneUse;
40
41 void substituteFor(Definition other) {
42 if (other.firstRef == null) return;
43 Reference previous, current = other.firstRef;
44 do {
45 current.definition = this;
46 previous = current;
47 current = current.next;
48 } while (current != null);
49 previous.next = firstRef;
50 if (firstRef != null) firstRef.previous = previous;
51 firstRef = other.firstRef;
52 }
53 }
54
55 /// An expression that cannot throw or diverge and has no side-effects.
56 /// All primitives are named using the identity of the [Primitive] object.
57 ///
58 /// Primitives may allocate objects, this is not considered side-effect here.
59 ///
60 /// Although primitives may not mutate state, they may depend on state.
61 abstract class Primitive extends Definition {
62 /// The [VariableElement] or [ParameterElement] from which the primitive
63 /// binding originated.
64 Element hint;
65
66 /// Register in which the variable binding this primitive can be allocated.
67 /// Separate register spaces are used for primitives with different [element].
68 /// Assigned by [RegisterAllocator], is null before that phase.
69 int registerIndex;
70
71 /// Use the given element as a hint for naming this primitive.
72 ///
73 /// Has no effect if this primitive already has a non-null [element].
74 void useElementAsHint(Element hint) {
75 if (this.hint == null) {
76 this.hint = hint;
77 }
78 }
79 }
80
81 /// Operands to invocations and primitives are always variables. They point to
82 /// their definition and are doubly-linked into a list of occurrences.
83 class Reference {
84 Definition definition;
85 Reference previous = null;
86 Reference next = null;
87
88 /// A pointer to the parent node. Is null until set by optimization passes.
89 Node parent;
90
91 Reference(this.definition) {
92 next = definition.firstRef;
93 if (next != null) next.previous = this;
94 definition.firstRef = this;
95 }
96
97 /// Unlinks this reference from the list of occurrences.
98 void unlink() {
99 if (previous == null) {
100 assert(definition.firstRef == this);
101 definition.firstRef = next;
102 } else {
103 previous.next = next;
104 }
105 if (next != null) next.previous = previous;
106 }
107 }
108
109 /// Binding a value (primitive or constant): 'let val x = V in E'. The bound
110 /// value is in scope in the body.
111 /// During one-pass construction a LetVal with an empty body is used to
112 /// represent one-level context 'let val x = V in []'.
113 class LetPrim extends Expression implements InteriorNode {
114 final Primitive primitive;
115 Expression body = null;
116
117 LetPrim(this.primitive);
118
119 Expression plug(Expression expr) {
120 assert(body == null);
121 return body = expr;
122 }
123
124 accept(Visitor visitor) => visitor.visitLetPrim(this);
125 }
126
127
128 /// Binding a continuation: 'let cont k(v) = E in E'. The bound continuation
129 /// is in scope in the body and the continuation parameter is in scope in the
130 /// continuation body.
131 /// During one-pass construction a LetCont with an empty continuation body is
132 /// used to represent the one-level context 'let cont k(v) = [] in E'.
133 class LetCont extends Expression implements InteriorNode {
134 Continuation continuation;
135 Expression body;
136
137 LetCont(this.continuation, this.body);
138
139 Expression plug(Expression expr) {
140 assert(continuation != null && continuation.body == null);
141 return continuation.body = expr;
142 }
143
144 accept(Visitor visitor) => visitor.visitLetCont(this);
145 }
146
147 abstract class Invoke {
148 Selector get selector;
149 List<Reference> get arguments;
150 }
151
152 /// Represents a node with a child node, which can be accessed through the
153 /// `body` member. A typical usage is when removing a node from the CPS graph:
154 ///
155 /// Node child = node.body;
156 /// InteriorNode parent = node.parent;
157 ///
158 /// child.parent = parent;
159 /// parent.body = child;
160 abstract class InteriorNode implements Node {
161 Expression body;
162 }
163
164 /// Invoke a static function or static field getter/setter.
165 class InvokeStatic extends Expression implements Invoke {
166 /// [FunctionElement] or [FieldElement].
167 final Entity target;
168
169 /**
170 * The selector encodes how the function is invoked: number of positional
171 * arguments, names used in named arguments. This information is required
172 * to build the [StaticCallSiteTypeInformation] for the inference graph.
173 */
174 final Selector selector;
175
176 final Reference continuation;
177 final List<Reference> arguments;
178
179 InvokeStatic(this.target, this.selector, Continuation cont,
180 List<Definition> args)
181 : continuation = new Reference(cont),
182 arguments = _referenceList(args) {
183 assert(target is ErroneousElement || selector.name == target.name);
184 }
185
186 accept(Visitor visitor) => visitor.visitInvokeStatic(this);
187 }
188
189 /// Invoke a method, operator, getter, setter, or index getter/setter.
190 /// Converting a method to a function object is treated as a getter invocation.
191 class InvokeMethod extends Expression implements Invoke {
192 final Reference receiver;
193 final Selector selector;
194 final Reference continuation;
195 final List<Reference> arguments;
196
197 InvokeMethod(Definition receiver,
198 this.selector,
199 Continuation cont,
200 List<Definition> args)
201 : receiver = new Reference(receiver),
202 continuation = new Reference(cont),
203 arguments = _referenceList(args) {
204 assert(selector != null);
205 assert(selector.kind == SelectorKind.CALL ||
206 selector.kind == SelectorKind.OPERATOR ||
207 (selector.kind == SelectorKind.GETTER && arguments.isEmpty) ||
208 (selector.kind == SelectorKind.SETTER && arguments.length == 1) ||
209 (selector.kind == SelectorKind.INDEX && arguments.length == 1) ||
210 (selector.kind == SelectorKind.INDEX && arguments.length == 2));
211 }
212
213 accept(Visitor visitor) => visitor.visitInvokeMethod(this);
214 }
215
216 /// Invoke a method, operator, getter, setter, or index getter/setter from the
217 /// super class in tail position.
218 class InvokeSuperMethod extends Expression implements Invoke {
219 final Selector selector;
220 final Reference continuation;
221 final List<Reference> arguments;
222
223 InvokeSuperMethod(this.selector,
224 Continuation cont,
225 List<Definition> args)
226 : continuation = new Reference(cont),
227 arguments = _referenceList(args) {
228 assert(selector != null);
229 assert(selector.kind == SelectorKind.CALL ||
230 selector.kind == SelectorKind.OPERATOR ||
231 (selector.kind == SelectorKind.GETTER && arguments.isEmpty) ||
232 (selector.kind == SelectorKind.SETTER && arguments.length == 1) ||
233 (selector.kind == SelectorKind.INDEX && arguments.length == 1) ||
234 (selector.kind == SelectorKind.INDEX && arguments.length == 2));
235 }
236
237 accept(Visitor visitor) => visitor.visitInvokeSuperMethod(this);
238 }
239
240 /// Non-const call to a constructor. The [target] may be a generative
241 /// constructor, factory, or redirecting factory.
242 class InvokeConstructor extends Expression implements Invoke {
243 final DartType type;
244 final FunctionElement target;
245 final Reference continuation;
246 final List<Reference> arguments;
247 final Selector selector;
248
249 /// The class being instantiated. This is the same as `target.enclosingClass`
250 /// and `type.element`.
251 ClassElement get targetClass => target.enclosingElement;
252
253 /// True if this is an invocation of a factory constructor.
254 bool get isFactory => target.isFactoryConstructor;
255
256 InvokeConstructor(this.type,
257 this.target,
258 this.selector,
259 Continuation cont,
260 List<Definition> args)
261 : continuation = new Reference(cont),
262 arguments = _referenceList(args) {
263 assert(dart2js.invariant(target,
264 target.isErroneous || target.isConstructor,
265 message: "Constructor invocation target is not a constructor: "
266 "$target."));
267 assert(dart2js.invariant(target,
268 target.isErroneous ||
269 type.isDynamic ||
270 type.element == target.enclosingClass.declaration,
271 message: "Constructor invocation type ${type} does not match enclosing "
272 "class of target ${target}."));
273 }
274
275 accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
276 }
277
278 /// "as" casts and "is" checks.
279 // We might want to turn "is"-checks into a [Primitive] as it can never diverge.
280 // But then we need to special-case for is-checks with an erroneous .type as
281 // these will throw.
282 class TypeOperator extends Expression {
283 final Reference receiver;
284 final DartType type;
285 final Reference continuation;
286 // TODO(johnniwinther): Use `Operator` class to encapsule the operator type.
287 final bool isTypeTest;
288
289 TypeOperator(Primitive receiver,
290 this.type,
291 Continuation cont,
292 {bool this.isTypeTest})
293 : this.receiver = new Reference(receiver),
294 this.continuation = new Reference(cont) {
295 assert(isTypeTest != null);
296 }
297
298 bool get isTypeCast => !isTypeTest;
299
300 accept(Visitor visitor) => visitor.visitTypeOperator(this);
301 }
302
303 /// Invoke [toString] on each argument and concatenate the results.
304 class ConcatenateStrings extends Expression {
305 final Reference continuation;
306 final List<Reference> arguments;
307
308 ConcatenateStrings(Continuation cont, List<Definition> args)
309 : continuation = new Reference(cont),
310 arguments = _referenceList(args);
311
312 accept(Visitor visitor) => visitor.visitConcatenateStrings(this);
313 }
314
315 /// Gets the value from a closure variable. The identity of the variable is
316 /// determined by a [Local].
317 ///
318 /// Closure variables can be seen as ref cells that are not first-class values.
319 /// A [LetPrim] with a [GetClosureVariable] can then be seen as:
320 ///
321 /// let prim p = ![variable] in [body]
322 ///
323 class GetClosureVariable extends Primitive {
324 final Local variable;
325
326 GetClosureVariable(this.variable) {
327 assert(variable != null);
328 }
329
330 accept(Visitor visitor) => visitor.visitGetClosureVariable(this);
331 }
332
333 /// Assign or declare a closure variable. The identity of the variable is
334 /// determined by a [Local].
335 ///
336 /// Closure variables can be seen as ref cells that are not first-class values.
337 /// If [isDeclaration], this can seen as a let binding:
338 ///
339 /// let [variable] = ref [value] in [body]
340 ///
341 /// And otherwise, it can be seen as a dereferencing assignment:
342 ///
343 /// { ![variable] := [value]; [body] }
344 ///
345 /// Closure variables without a declaring [SetClosureVariable] are implicitly
346 /// declared at the entry to the [variable]'s enclosing function.
347 class SetClosureVariable extends Expression implements InteriorNode {
348 final Local variable;
349 final Reference value;
350 Expression body;
351
352 /// If true, this declares a new copy of the closure variable. If so, all
353 /// uses of the closure variable must occur in the [body].
354 ///
355 /// There can be at most one declaration per closure variable. If there is no
356 /// declaration, only one copy exists (per function execution). It is best to
357 /// avoid declaring closure variables if it is not necessary.
358 final bool isDeclaration;
359
360 SetClosureVariable(this.variable, Primitive value,
361 {this.isDeclaration : false })
362 : this.value = new Reference(value) {
363 assert(variable != null);
364 }
365
366 accept(Visitor visitor) => visitor.visitSetClosureVariable(this);
367
368 Expression plug(Expression expr) {
369 assert(body == null);
370 return body = expr;
371 }
372 }
373
374 /// Create a potentially recursive function and store it in a closure variable.
375 /// The function can access itself using [GetClosureVariable] on [variable].
376 /// There must not exist a [SetClosureVariable] to [variable].
377 ///
378 /// This can be seen as a let rec binding:
379 ///
380 /// let rec [variable] = [definition] in [body]
381 ///
382 class DeclareFunction extends Expression implements InteriorNode {
383 final Local variable;
384 final FunctionDefinition definition;
385 Expression body;
386
387 DeclareFunction(this.variable, this.definition);
388
389 Expression plug(Expression expr) {
390 assert(body == null);
391 return body = expr;
392 }
393
394 accept(Visitor visitor) => visitor.visitDeclareFunction(this);
395 }
396
397 /// Invoke a continuation in tail position.
398 class InvokeContinuation extends Expression {
399 Reference continuation;
400 List<Reference> arguments;
401
402 // An invocation of a continuation is recursive if it occurs in the body of
403 // the continuation itself.
404 bool isRecursive;
405
406 InvokeContinuation(Continuation cont, List<Definition> args,
407 {recursive: false})
408 : continuation = new Reference(cont),
409 arguments = _referenceList(args),
410 isRecursive = recursive {
411 assert(cont.parameters == null ||
412 cont.parameters.length == args.length);
413 if (recursive) cont.isRecursive = true;
414 }
415
416 /// A continuation invocation whose target and arguments will be filled
417 /// in later.
418 ///
419 /// Used as a placeholder for a jump whose target is not yet created
420 /// (e.g., in the translation of break and continue).
421 InvokeContinuation.uninitialized({recursive: false})
422 : continuation = null,
423 arguments = null,
424 isRecursive = recursive;
425
426 accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
427 }
428
429 /// The base class of things which can be tested and branched on.
430 abstract class Condition extends Node {
431 }
432
433 class IsTrue extends Condition {
434 final Reference value;
435
436 IsTrue(Definition val) : value = new Reference(val);
437
438 accept(Visitor visitor) => visitor.visitIsTrue(this);
439 }
440
441 /// Choose between a pair of continuations based on a condition value.
442 class Branch extends Expression {
443 final Condition condition;
444 final Reference trueContinuation;
445 final Reference falseContinuation;
446
447 Branch(this.condition, Continuation trueCont, Continuation falseCont)
448 : trueContinuation = new Reference(trueCont),
449 falseContinuation = new Reference(falseCont);
450
451 accept(Visitor visitor) => visitor.visitBranch(this);
452 }
453
454 class Constant extends Primitive {
455 final ConstantExpression expression;
456
457 Constant(this.expression);
458
459 values.ConstantValue get value => expression.value;
460
461 accept(Visitor visitor) => visitor.visitConstant(this);
462 }
463
464 class This extends Primitive {
465 This();
466
467 accept(Visitor visitor) => visitor.visitThis(this);
468 }
469
470 /// Reify the given type variable as a [Type].
471 /// This depends on the current binding of 'this'.
472 class ReifyTypeVar extends Primitive {
473 final TypeVariableElement typeVariable;
474
475 ReifyTypeVar(this.typeVariable);
476
477 values.ConstantValue get constant => null;
478
479 accept(Visitor visitor) => visitor.visitReifyTypeVar(this);
480 }
481
482 class LiteralList extends Primitive {
483 /// The List type being created; this is not the type argument.
484 final GenericType type;
485 final List<Reference> values;
486
487 LiteralList(this.type, Iterable<Primitive> values)
488 : this.values = _referenceList(values);
489
490 accept(Visitor visitor) => visitor.visitLiteralList(this);
491 }
492
493 class LiteralMapEntry {
494 final Reference key;
495 final Reference value;
496
497 LiteralMapEntry(Primitive key, Primitive value)
498 : this.key = new Reference(key),
499 this.value = new Reference(value);
500 }
501
502 class LiteralMap extends Primitive {
503 final GenericType type;
504 final List<LiteralMapEntry> entries;
505
506 LiteralMap(this.type, this.entries);
507
508 accept(Visitor visitor) => visitor.visitLiteralMap(this);
509 }
510
511 /// Create a non-recursive function.
512 class CreateFunction extends Primitive {
513 final FunctionDefinition definition;
514
515 CreateFunction(this.definition);
516
517 accept(Visitor visitor) => visitor.visitCreateFunction(this);
518 }
519
520 class Parameter extends Primitive {
521 Parameter(Element element) {
522 super.hint = element;
523 }
524
525 accept(Visitor visitor) => visitor.visitParameter(this);
526 }
527
528 /// Continuations are normally bound by 'let cont'. A continuation with one
529 /// parameter and no body is used to represent a function's return continuation.
530 /// The return continuation is bound by the Function, not by 'let cont'.
531 class Continuation extends Definition implements InteriorNode {
532 final List<Parameter> parameters;
533 Expression body = null;
534
535 // A continuation is recursive if it has any recursive invocations.
536 bool isRecursive = false;
537
538 bool get isReturnContinuation => body == null;
539
540 Continuation(this.parameters);
541
542 Continuation.retrn() : parameters = <Parameter>[new Parameter(null)];
543
544 accept(Visitor visitor) => visitor.visitContinuation(this);
545 }
546
547 /// A function definition, consisting of parameters and a body. The parameters
548 /// include a distinguished continuation parameter.
549 class FunctionDefinition extends Node implements InteriorNode {
550 final FunctionElement element;
551 final Continuation returnContinuation;
552 final List<Parameter> parameters;
553 Expression body;
554 final List<ConstDeclaration> localConstants;
555
556 /// Values for optional parameters.
557 final List<ConstantExpression> defaultParameterValues;
558
559 FunctionDefinition(this.element, this.returnContinuation,
560 this.parameters, this.body, this.localConstants,
561 this.defaultParameterValues);
562
563 FunctionDefinition.abstract(this.element,
564 this.parameters,
565 this.defaultParameterValues)
566 : this.returnContinuation = null,
567 this.localConstants = const <ConstDeclaration>[];
568
569 accept(Visitor visitor) => visitor.visitFunctionDefinition(this);
570
571 /// Returns `true` if this function is abstract.
572 ///
573 /// If `true`, [body] and [returnContinuation] are `null` and [localConstants]
574 /// is empty.
575 bool get isAbstract => body == null;
576 }
577
578 List<Reference> _referenceList(Iterable<Definition> definitions) {
579 return definitions.map((e) => new Reference(e)).toList();
580 }
581
582 abstract class Visitor<T> {
583 T visit(Node node) => node.accept(this);
584 // Abstract classes.
585 T visitNode(Node node) => null;
586 T visitExpression(Expression node) => visitNode(node);
587 T visitDefinition(Definition node) => visitNode(node);
588 T visitPrimitive(Primitive node) => visitDefinition(node);
589 T visitCondition(Condition node) => visitNode(node);
590
591 // Concrete classes.
592 T visitFunctionDefinition(FunctionDefinition node) => visitNode(node);
593
594 // Expressions.
595 T visitLetPrim(LetPrim node) => visitExpression(node);
596 T visitLetCont(LetCont node) => visitExpression(node);
597 T visitInvokeStatic(InvokeStatic node) => visitExpression(node);
598 T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node);
599 T visitInvokeMethod(InvokeMethod node) => visitExpression(node);
600 T visitInvokeSuperMethod(InvokeSuperMethod node) => visitExpression(node);
601 T visitInvokeConstructor(InvokeConstructor node) => visitExpression(node);
602 T visitConcatenateStrings(ConcatenateStrings node) => visitExpression(node);
603 T visitBranch(Branch node) => visitExpression(node);
604 T visitTypeOperator(TypeOperator node) => visitExpression(node);
605 T visitSetClosureVariable(SetClosureVariable node) => visitExpression(node);
606 T visitDeclareFunction(DeclareFunction node) => visitExpression(node);
607
608 // Definitions.
609 T visitLiteralList(LiteralList node) => visitPrimitive(node);
610 T visitLiteralMap(LiteralMap node) => visitPrimitive(node);
611 T visitConstant(Constant node) => visitPrimitive(node);
612 T visitThis(This node) => visitPrimitive(node);
613 T visitReifyTypeVar(ReifyTypeVar node) => visitPrimitive(node);
614 T visitCreateFunction(CreateFunction node) => visitPrimitive(node);
615 T visitGetClosureVariable(GetClosureVariable node) => visitPrimitive(node);
616 T visitParameter(Parameter node) => visitPrimitive(node);
617 T visitContinuation(Continuation node) => visitDefinition(node);
618
619 // Conditions.
620 T visitIsTrue(IsTrue node) => visitCondition(node);
621 }
622
623 /// Recursively visits the entire CPS term, and calls abstract `process*`
624 /// (i.e. `processLetPrim`) functions in pre-order.
625 abstract class RecursiveVisitor extends Visitor {
626 // Ensures that RecursiveVisitor contains overrides for all relevant nodes.
627 // As a rule of thumb, nodes with structure to traverse should be overridden
628 // with the appropriate visits in this class (for example, visitLetCont),
629 // while leaving other nodes for subclasses (i.e., visitLiteralList).
630 visitNode(Node node) {
631 throw "RecursiveVisitor is stale, add missing visit overrides";
632 }
633
634 processReference(Reference ref) {}
635
636 processFunctionDefinition(FunctionDefinition node) {}
637 visitFunctionDefinition(FunctionDefinition node) {
638 processFunctionDefinition(node);
639 node.parameters.forEach(visitParameter);
640 visit(node.body);
641 }
642
643 // Expressions.
644
645 processLetPrim(LetPrim node) {}
646 visitLetPrim(LetPrim node) {
647 processLetPrim(node);
648 visit(node.primitive);
649 visit(node.body);
650 }
651
652 processLetCont(LetCont node) {}
653 visitLetCont(LetCont node) {
654 processLetCont(node);
655 visit(node.continuation);
656 visit(node.body);
657 }
658
659 processInvokeStatic(InvokeStatic node) {}
660 visitInvokeStatic(InvokeStatic node) {
661 processInvokeStatic(node);
662 processReference(node.continuation);
663 node.arguments.forEach(processReference);
664 }
665
666 processInvokeContinuation(InvokeContinuation node) {}
667 visitInvokeContinuation(InvokeContinuation node) {
668 processInvokeContinuation(node);
669 processReference(node.continuation);
670 node.arguments.forEach(processReference);
671 }
672
673 processInvokeMethod(InvokeMethod node) {}
674 visitInvokeMethod(InvokeMethod node) {
675 processInvokeMethod(node);
676 processReference(node.receiver);
677 processReference(node.continuation);
678 node.arguments.forEach(processReference);
679 }
680
681 processInvokeSuperMethod(InvokeSuperMethod node) {}
682 visitInvokeSuperMethod(InvokeSuperMethod node) {
683 processInvokeSuperMethod(node);
684 processReference(node.continuation);
685 node.arguments.forEach(processReference);
686 }
687
688 processInvokeConstructor(InvokeConstructor node) {}
689 visitInvokeConstructor(InvokeConstructor node) {
690 processInvokeConstructor(node);
691 processReference(node.continuation);
692 node.arguments.forEach(processReference);
693 }
694
695 processConcatenateStrings(ConcatenateStrings node) {}
696 visitConcatenateStrings(ConcatenateStrings node) {
697 processConcatenateStrings(node);
698 processReference(node.continuation);
699 node.arguments.forEach(processReference);
700 }
701
702
703 processBranch(Branch node) {}
704 visitBranch(Branch node) {
705 processBranch(node);
706 processReference(node.trueContinuation);
707 processReference(node.falseContinuation);
708 visit(node.condition);
709 }
710
711 processTypeOperator(TypeOperator node) {}
712 visitTypeOperator(TypeOperator node) {
713 processTypeOperator(node);
714 processReference(node.continuation);
715 processReference(node.receiver);
716 }
717
718 processSetClosureVariable(SetClosureVariable node) {}
719 visitSetClosureVariable(SetClosureVariable node) {
720 processSetClosureVariable(node);
721 processReference(node.value);
722 visit(node.body);
723 }
724
725 processDeclareFunction(DeclareFunction node) {}
726 visitDeclareFunction(DeclareFunction node) {
727 processDeclareFunction(node);
728 visit(node.definition);
729 visit(node.body);
730 }
731
732 // Definitions.
733
734 processLiteralList(LiteralList node) {}
735 visitLiteralList(LiteralList node) {
736 processLiteralList(node);
737 node.values.forEach(processReference);
738 }
739
740 processLiteralMap(LiteralMap node) {}
741 visitLiteralMap(LiteralMap node) {
742 processLiteralMap(node);
743 for (LiteralMapEntry entry in node.entries) {
744 processReference(entry.key);
745 processReference(entry.value);
746 }
747 }
748
749 processConstant(Constant node) {}
750 visitConstant(Constant node) => processConstant(node);
751
752 processThis(This node) {}
753 visitThis(This node) => processThis(node);
754
755 processReifyTypeVar(ReifyTypeVar node) {}
756 visitReifyTypeVar(ReifyTypeVar node) => processReifyTypeVar(node);
757
758 processCreateFunction(CreateFunction node) {}
759 visitCreateFunction(CreateFunction node) {
760 processCreateFunction(node);
761 visit(node.definition);
762 }
763
764 processGetClosureVariable(GetClosureVariable node) {}
765 visitGetClosureVariable(GetClosureVariable node) =>
766 processGetClosureVariable(node);
767
768 processParameter(Parameter node) {}
769 visitParameter(Parameter node) => processParameter(node);
770
771 processContinuation(Continuation node) {}
772 visitContinuation(Continuation node) {
773 processContinuation(node);
774 node.parameters.forEach(visitParameter);
775 visit(node.body);
776 }
777
778 // Conditions.
779
780 processIsTrue(IsTrue node) {}
781 visitIsTrue(IsTrue node) {
782 processIsTrue(node);
783 processReference(node.value);
784 }
785 }
786
787 /// Keeps track of currently unused register indices.
788 class RegisterArray {
789 int nextIndex = 0;
790 final List<int> freeStack = <int>[];
791
792 /// Returns an index that is currently unused.
793 int makeIndex() {
794 if (freeStack.isEmpty) {
795 return nextIndex++;
796 } else {
797 return freeStack.removeLast();
798 }
799 }
800
801 void releaseIndex(int index) {
802 freeStack.add(index);
803 }
804 }
805
806 /// Assigns indices to each primitive in the IR such that primitives that are
807 /// live simultaneously never get assigned the same index.
808 /// This information is used by the dart tree builder to generate fewer
809 /// redundant variables.
810 /// Currently, the liveness analysis is very simple and is often inadequate
811 /// for removing all of the redundant variables.
812 class RegisterAllocator extends Visitor {
813 /// Separate register spaces for each source-level variable/parameter.
814 /// Note that null is used as key for primitives without elements.
815 final Map<Element, RegisterArray> elementRegisters =
816 <Element, RegisterArray>{};
817
818 RegisterArray getRegisterArray(Element element) {
819 RegisterArray registers = elementRegisters[element];
820 if (registers == null) {
821 registers = new RegisterArray();
822 elementRegisters[element] = registers;
823 }
824 return registers;
825 }
826
827 void allocate(Primitive primitive) {
828 if (primitive.registerIndex == null) {
829 primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex();
830 }
831 }
832
833 void release(Primitive primitive) {
834 // Do not share indices for temporaries as this may obstruct inlining.
835 if (primitive.hint == null) return;
836 if (primitive.registerIndex != null) {
837 getRegisterArray(primitive.hint).releaseIndex(primitive.registerIndex);
838 }
839 }
840
841 void visitReference(Reference reference) {
842 allocate(reference.definition);
843 }
844
845 void visitFunctionDefinition(FunctionDefinition node) {
846 if (!node.isAbstract) {
847 visit(node.body);
848 }
849 node.parameters.forEach(allocate); // Assign indices to unused parameters.
850 elementRegisters.clear();
851 }
852
853 void visitLetPrim(LetPrim node) {
854 visit(node.body);
855 release(node.primitive);
856 visit(node.primitive);
857 }
858
859 void visitLetCont(LetCont node) {
860 visit(node.continuation);
861 visit(node.body);
862 }
863
864 void visitInvokeStatic(InvokeStatic node) {
865 node.arguments.forEach(visitReference);
866 }
867
868 void visitInvokeContinuation(InvokeContinuation node) {
869 node.arguments.forEach(visitReference);
870 }
871
872 void visitInvokeMethod(InvokeMethod node) {
873 visitReference(node.receiver);
874 node.arguments.forEach(visitReference);
875 }
876
877 void visitInvokeSuperMethod(InvokeSuperMethod node) {
878 node.arguments.forEach(visitReference);
879 }
880
881 void visitInvokeConstructor(InvokeConstructor node) {
882 node.arguments.forEach(visitReference);
883 }
884
885 void visitConcatenateStrings(ConcatenateStrings node) {
886 node.arguments.forEach(visitReference);
887 }
888
889 void visitBranch(Branch node) {
890 visit(node.condition);
891 }
892
893 void visitLiteralList(LiteralList node) {
894 node.values.forEach(visitReference);
895 }
896
897 void visitLiteralMap(LiteralMap node) {
898 for (LiteralMapEntry entry in node.entries) {
899 visitReference(entry.key);
900 visitReference(entry.value);
901 }
902 }
903
904 void visitTypeOperator(TypeOperator node) {
905 visitReference(node.receiver);
906 }
907
908 void visitConstant(Constant node) {
909 }
910
911 void visitThis(This node) {
912 }
913
914 void visitReifyTypeVar(ReifyTypeVar node) {
915 }
916
917 void visitCreateFunction(CreateFunction node) {
918 new RegisterAllocator().visit(node.definition);
919 }
920
921 void visitGetClosureVariable(GetClosureVariable node) {
922 }
923
924 void visitSetClosureVariable(SetClosureVariable node) {
925 visit(node.body);
926 visitReference(node.value);
927 }
928
929 void visitDeclareFunction(DeclareFunction node) {
930 new RegisterAllocator().visit(node.definition);
931 visit(node.body);
932 }
933
934 void visitParameter(Parameter node) {
935 throw "Parameters should not be visited by RegisterAllocator";
936 }
937
938 void visitContinuation(Continuation node) {
939 visit(node.body);
940
941 // Arguments get allocated left-to-right, so we release parameters
942 // right-to-left. This increases the likelihood that arguments can be
943 // transferred without intermediate assignments.
944 for (int i = node.parameters.length - 1; i >= 0; --i) {
945 release(node.parameters[i]);
946 }
947 }
948
949 void visitIsTrue(IsTrue node) {
950 visitReference(node.value);
951 }
952
953 }
954
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698