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

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

Issue 692513002: Remove old dart2js code. (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 final String operator;
287
288 TypeOperator(this.operator,
289 Primitive receiver,
290 this.type,
291 Continuation cont)
292 : this.receiver = new Reference(receiver),
293 this.continuation = new Reference(cont) {
294 assert(operator == "is" || operator == "as");
295 }
296
297 accept(Visitor visitor) => visitor.visitTypeOperator(this);
298 }
299
300 /// Invoke [toString] on each argument and concatenate the results.
301 class ConcatenateStrings extends Expression {
302 final Reference continuation;
303 final List<Reference> arguments;
304
305 ConcatenateStrings(Continuation cont, List<Definition> args)
306 : continuation = new Reference(cont),
307 arguments = _referenceList(args);
308
309 accept(Visitor visitor) => visitor.visitConcatenateStrings(this);
310 }
311
312 /// Gets the value from a closure variable. The identity of the variable is
313 /// determined by a [Local].
314 ///
315 /// Closure variables can be seen as ref cells that are not first-class values.
316 /// A [LetPrim] with a [GetClosureVariable] can then be seen as:
317 ///
318 /// let prim p = ![variable] in [body]
319 ///
320 class GetClosureVariable extends Primitive {
321 final Local variable;
322
323 GetClosureVariable(this.variable) {
324 assert(variable != null);
325 }
326
327 accept(Visitor visitor) => visitor.visitGetClosureVariable(this);
328 }
329
330 /// Assign or declare a closure variable. The identity of the variable is
331 /// determined by a [Local].
332 ///
333 /// Closure variables can be seen as ref cells that are not first-class values.
334 /// If [isDeclaration], this can seen as a let binding:
335 ///
336 /// let [variable] = ref [value] in [body]
337 ///
338 /// And otherwise, it can be seen as a dereferencing assignment:
339 ///
340 /// { ![variable] := [value]; [body] }
341 ///
342 /// Closure variables without a declaring [SetClosureVariable] are implicitly
343 /// declared at the entry to the [variable]'s enclosing function.
344 class SetClosureVariable extends Expression implements InteriorNode {
345 final Local variable;
346 final Reference value;
347 Expression body;
348
349 /// If true, this declares a new copy of the closure variable. If so, all
350 /// uses of the closure variable must occur in the [body].
351 ///
352 /// There can be at most one declaration per closure variable. If there is no
353 /// declaration, only one copy exists (per function execution). It is best to
354 /// avoid declaring closure variables if it is not necessary.
355 final bool isDeclaration;
356
357 SetClosureVariable(this.variable, Primitive value,
358 {this.isDeclaration : false })
359 : this.value = new Reference(value) {
360 assert(variable != null);
361 }
362
363 accept(Visitor visitor) => visitor.visitSetClosureVariable(this);
364
365 Expression plug(Expression expr) {
366 assert(body == null);
367 return body = expr;
368 }
369 }
370
371 /// Create a potentially recursive function and store it in a closure variable.
372 /// The function can access itself using [GetClosureVariable] on [variable].
373 /// There must not exist a [SetClosureVariable] to [variable].
374 ///
375 /// This can be seen as a let rec binding:
376 ///
377 /// let rec [variable] = [definition] in [body]
378 ///
379 class DeclareFunction extends Expression implements InteriorNode {
380 final Local variable;
381 final FunctionDefinition definition;
382 Expression body;
383
384 DeclareFunction(this.variable, this.definition);
385
386 Expression plug(Expression expr) {
387 assert(body == null);
388 return body = expr;
389 }
390
391 accept(Visitor visitor) => visitor.visitDeclareFunction(this);
392 }
393
394 /// Invoke a continuation in tail position.
395 class InvokeContinuation extends Expression {
396 Reference continuation;
397 List<Reference> arguments;
398
399 // An invocation of a continuation is recursive if it occurs in the body of
400 // the continuation itself.
401 bool isRecursive;
402
403 InvokeContinuation(Continuation cont, List<Definition> args,
404 {recursive: false})
405 : continuation = new Reference(cont),
406 arguments = _referenceList(args),
407 isRecursive = recursive {
408 assert(cont.parameters == null ||
409 cont.parameters.length == args.length);
410 if (recursive) cont.isRecursive = true;
411 }
412
413 /// A continuation invocation whose target and arguments will be filled
414 /// in later.
415 ///
416 /// Used as a placeholder for a jump whose target is not yet created
417 /// (e.g., in the translation of break and continue).
418 InvokeContinuation.uninitialized({recursive: false})
419 : continuation = null,
420 arguments = null,
421 isRecursive = recursive;
422
423 accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
424 }
425
426 /// The base class of things which can be tested and branched on.
427 abstract class Condition extends Node {
428 }
429
430 class IsTrue extends Condition {
431 final Reference value;
432
433 IsTrue(Definition val) : value = new Reference(val);
434
435 accept(Visitor visitor) => visitor.visitIsTrue(this);
436 }
437
438 /// Choose between a pair of continuations based on a condition value.
439 class Branch extends Expression {
440 final Condition condition;
441 final Reference trueContinuation;
442 final Reference falseContinuation;
443
444 Branch(this.condition, Continuation trueCont, Continuation falseCont)
445 : trueContinuation = new Reference(trueCont),
446 falseContinuation = new Reference(falseCont);
447
448 accept(Visitor visitor) => visitor.visitBranch(this);
449 }
450
451 class Constant extends Primitive {
452 final ConstantExpression expression;
453
454 Constant(this.expression);
455
456 values.ConstantValue get value => expression.value;
457
458 accept(Visitor visitor) => visitor.visitConstant(this);
459 }
460
461 class This extends Primitive {
462 This();
463
464 accept(Visitor visitor) => visitor.visitThis(this);
465 }
466
467 /// Reify the given type variable as a [Type].
468 /// This depends on the current binding of 'this'.
469 class ReifyTypeVar extends Primitive {
470 final TypeVariableElement typeVariable;
471
472 ReifyTypeVar(this.typeVariable);
473
474 values.ConstantValue get constant => null;
475
476 accept(Visitor visitor) => visitor.visitReifyTypeVar(this);
477 }
478
479 class LiteralList extends Primitive {
480 /// The List type being created; this is not the type argument.
481 final GenericType type;
482 final List<Reference> values;
483
484 LiteralList(this.type, List<Primitive> values)
485 : this.values = _referenceList(values);
486
487 accept(Visitor visitor) => visitor.visitLiteralList(this);
488 }
489
490 class LiteralMap extends Primitive {
491 final GenericType type;
492 final List<Reference> keys;
493 final List<Reference> values;
494
495 LiteralMap(this.type, List<Primitive> keys, List<Primitive> values)
496 : this.keys = _referenceList(keys),
497 this.values = _referenceList(values);
498
499 accept(Visitor visitor) => visitor.visitLiteralMap(this);
500 }
501
502 /// Create a non-recursive function.
503 class CreateFunction extends Primitive {
504 final FunctionDefinition definition;
505
506 CreateFunction(this.definition);
507
508 accept(Visitor visitor) => visitor.visitCreateFunction(this);
509 }
510
511 class Parameter extends Primitive {
512 Parameter(Element element) {
513 super.hint = element;
514 }
515
516 accept(Visitor visitor) => visitor.visitParameter(this);
517 }
518
519 /// Continuations are normally bound by 'let cont'. A continuation with one
520 /// parameter and no body is used to represent a function's return continuation.
521 /// The return continuation is bound by the Function, not by 'let cont'.
522 class Continuation extends Definition implements InteriorNode {
523 final List<Parameter> parameters;
524 Expression body = null;
525
526 // A continuation is recursive if it has any recursive invocations.
527 bool isRecursive = false;
528
529 bool get isReturnContinuation => body == null;
530
531 Continuation(this.parameters);
532
533 Continuation.retrn() : parameters = <Parameter>[new Parameter(null)];
534
535 accept(Visitor visitor) => visitor.visitContinuation(this);
536 }
537
538 /// A function definition, consisting of parameters and a body. The parameters
539 /// include a distinguished continuation parameter.
540 class FunctionDefinition extends Node implements InteriorNode {
541 final FunctionElement element;
542 final Continuation returnContinuation;
543 final List<Parameter> parameters;
544 Expression body;
545 final List<ConstDeclaration> localConstants;
546
547 /// Values for optional parameters.
548 final List<ConstantExpression> defaultParameterValues;
549
550 FunctionDefinition(this.element, this.returnContinuation,
551 this.parameters, this.body, this.localConstants,
552 this.defaultParameterValues);
553
554 FunctionDefinition.abstract(this.element,
555 this.parameters,
556 this.defaultParameterValues)
557 : this.returnContinuation = null,
558 this.localConstants = const <ConstDeclaration>[];
559
560 accept(Visitor visitor) => visitor.visitFunctionDefinition(this);
561
562 /// Returns `true` if this function is abstract.
563 ///
564 /// If `true`, [body] and [returnContinuation] are `null` and [localConstants]
565 /// is empty.
566 bool get isAbstract => body == null;
567 }
568
569 List<Reference> _referenceList(List<Definition> definitions) {
570 return definitions.map((e) => new Reference(e)).toList();
571 }
572
573 abstract class Visitor<T> {
574 T visit(Node node) => node.accept(this);
575 // Abstract classes.
576 T visitNode(Node node) => null;
577 T visitExpression(Expression node) => visitNode(node);
578 T visitDefinition(Definition node) => visitNode(node);
579 T visitPrimitive(Primitive node) => visitDefinition(node);
580 T visitCondition(Condition node) => visitNode(node);
581
582 // Concrete classes.
583 T visitFunctionDefinition(FunctionDefinition node) => visitNode(node);
584
585 // Expressions.
586 T visitLetPrim(LetPrim node) => visitExpression(node);
587 T visitLetCont(LetCont node) => visitExpression(node);
588 T visitInvokeStatic(InvokeStatic node) => visitExpression(node);
589 T visitInvokeContinuation(InvokeContinuation node) => visitExpression(node);
590 T visitInvokeMethod(InvokeMethod node) => visitExpression(node);
591 T visitInvokeSuperMethod(InvokeSuperMethod node) => visitExpression(node);
592 T visitInvokeConstructor(InvokeConstructor node) => visitExpression(node);
593 T visitConcatenateStrings(ConcatenateStrings node) => visitExpression(node);
594 T visitBranch(Branch node) => visitExpression(node);
595 T visitTypeOperator(TypeOperator node) => visitExpression(node);
596 T visitSetClosureVariable(SetClosureVariable node) => visitExpression(node);
597 T visitDeclareFunction(DeclareFunction node) => visitExpression(node);
598
599 // Definitions.
600 T visitLiteralList(LiteralList node) => visitPrimitive(node);
601 T visitLiteralMap(LiteralMap node) => visitPrimitive(node);
602 T visitConstant(Constant node) => visitPrimitive(node);
603 T visitThis(This node) => visitPrimitive(node);
604 T visitReifyTypeVar(ReifyTypeVar node) => visitPrimitive(node);
605 T visitCreateFunction(CreateFunction node) => visitPrimitive(node);
606 T visitGetClosureVariable(GetClosureVariable node) => visitPrimitive(node);
607 T visitParameter(Parameter node) => visitPrimitive(node);
608 T visitContinuation(Continuation node) => visitDefinition(node);
609
610 // Conditions.
611 T visitIsTrue(IsTrue node) => visitCondition(node);
612 }
613
614 /// Recursively visits the entire CPS term, and calls abstract `process*`
615 /// (i.e. `processLetPrim`) functions in pre-order.
616 abstract class RecursiveVisitor extends Visitor {
617 // Ensures that RecursiveVisitor contains overrides for all relevant nodes.
618 // As a rule of thumb, nodes with structure to traverse should be overridden
619 // with the appropriate visits in this class (for example, visitLetCont),
620 // while leaving other nodes for subclasses (i.e., visitLiteralList).
621 visitNode(Node node) {
622 throw "RecursiveVisitor is stale, add missing visit overrides";
623 }
624
625 processReference(Reference ref) {}
626
627 processFunctionDefinition(FunctionDefinition node) {}
628 visitFunctionDefinition(FunctionDefinition node) {
629 processFunctionDefinition(node);
630 node.parameters.forEach(visitParameter);
631 visit(node.body);
632 }
633
634 // Expressions.
635
636 processLetPrim(LetPrim node) {}
637 visitLetPrim(LetPrim node) {
638 processLetPrim(node);
639 visit(node.primitive);
640 visit(node.body);
641 }
642
643 processLetCont(LetCont node) {}
644 visitLetCont(LetCont node) {
645 processLetCont(node);
646 visit(node.continuation);
647 visit(node.body);
648 }
649
650 processInvokeStatic(InvokeStatic node) {}
651 visitInvokeStatic(InvokeStatic node) {
652 processInvokeStatic(node);
653 processReference(node.continuation);
654 node.arguments.forEach(processReference);
655 }
656
657 processInvokeContinuation(InvokeContinuation node) {}
658 visitInvokeContinuation(InvokeContinuation node) {
659 processInvokeContinuation(node);
660 processReference(node.continuation);
661 node.arguments.forEach(processReference);
662 }
663
664 processInvokeMethod(InvokeMethod node) {}
665 visitInvokeMethod(InvokeMethod node) {
666 processInvokeMethod(node);
667 processReference(node.receiver);
668 processReference(node.continuation);
669 node.arguments.forEach(processReference);
670 }
671
672 processInvokeSuperMethod(InvokeSuperMethod node) {}
673 visitInvokeSuperMethod(InvokeSuperMethod node) {
674 processInvokeSuperMethod(node);
675 processReference(node.continuation);
676 node.arguments.forEach(processReference);
677 }
678
679 processInvokeConstructor(InvokeConstructor node) {}
680 visitInvokeConstructor(InvokeConstructor node) {
681 processInvokeConstructor(node);
682 processReference(node.continuation);
683 node.arguments.forEach(processReference);
684 }
685
686 processConcatenateStrings(ConcatenateStrings node) {}
687 visitConcatenateStrings(ConcatenateStrings node) {
688 processConcatenateStrings(node);
689 processReference(node.continuation);
690 node.arguments.forEach(processReference);
691 }
692
693
694 processBranch(Branch node) {}
695 visitBranch(Branch node) {
696 processBranch(node);
697 processReference(node.trueContinuation);
698 processReference(node.falseContinuation);
699 visit(node.condition);
700 }
701
702 processTypeOperator(TypeOperator node) {}
703 visitTypeOperator(TypeOperator node) {
704 processTypeOperator(node);
705 processReference(node.continuation);
706 processReference(node.receiver);
707 }
708
709 processSetClosureVariable(SetClosureVariable node) {}
710 visitSetClosureVariable(SetClosureVariable node) {
711 processSetClosureVariable(node);
712 processReference(node.value);
713 visit(node.body);
714 }
715
716 processDeclareFunction(DeclareFunction node) {}
717 visitDeclareFunction(DeclareFunction node) {
718 processDeclareFunction(node);
719 visit(node.definition);
720 visit(node.body);
721 }
722
723 // Definitions.
724
725 processLiteralList(LiteralList node) {}
726 visitLiteralList(LiteralList node) {
727 processLiteralList(node);
728 node.values.forEach(processReference);
729 }
730
731 processLiteralMap(LiteralMap node) {}
732 visitLiteralMap(LiteralMap node) {
733 processLiteralMap(node);
734 for (int i = 0; i < node.keys.length; i++) {
735 processReference(node.keys[i]);
736 processReference(node.values[i]);
737 }
738 }
739
740 processConstant(Constant node) {}
741 visitConstant(Constant node) => processConstant(node);
742
743 processThis(This node) {}
744 visitThis(This node) => processThis(node);
745
746 processReifyTypeVar(ReifyTypeVar node) {}
747 visitReifyTypeVar(ReifyTypeVar node) => processReifyTypeVar(node);
748
749 processCreateFunction(CreateFunction node) {}
750 visitCreateFunction(CreateFunction node) {
751 processCreateFunction(node);
752 visit(node.definition);
753 }
754
755 processGetClosureVariable(GetClosureVariable node) {}
756 visitGetClosureVariable(GetClosureVariable node) =>
757 processGetClosureVariable(node);
758
759 processParameter(Parameter node) {}
760 visitParameter(Parameter node) => processParameter(node);
761
762 processContinuation(Continuation node) {}
763 visitContinuation(Continuation node) {
764 processContinuation(node);
765 node.parameters.forEach(visitParameter);
766 visit(node.body);
767 }
768
769 // Conditions.
770
771 processIsTrue(IsTrue node) {}
772 visitIsTrue(IsTrue node) {
773 processIsTrue(node);
774 processReference(node.value);
775 }
776 }
777
778 /// Keeps track of currently unused register indices.
779 class RegisterArray {
780 int nextIndex = 0;
781 final List<int> freeStack = <int>[];
782
783 /// Returns an index that is currently unused.
784 int makeIndex() {
785 if (freeStack.isEmpty) {
786 return nextIndex++;
787 } else {
788 return freeStack.removeLast();
789 }
790 }
791
792 void releaseIndex(int index) {
793 freeStack.add(index);
794 }
795 }
796
797 /// Assigns indices to each primitive in the IR such that primitives that are
798 /// live simultaneously never get assigned the same index.
799 /// This information is used by the dart tree builder to generate fewer
800 /// redundant variables.
801 /// Currently, the liveness analysis is very simple and is often inadequate
802 /// for removing all of the redundant variables.
803 class RegisterAllocator extends Visitor {
804 /// Separate register spaces for each source-level variable/parameter.
805 /// Note that null is used as key for primitives without elements.
806 final Map<Element, RegisterArray> elementRegisters =
807 <Element, RegisterArray>{};
808
809 RegisterArray getRegisterArray(Element element) {
810 RegisterArray registers = elementRegisters[element];
811 if (registers == null) {
812 registers = new RegisterArray();
813 elementRegisters[element] = registers;
814 }
815 return registers;
816 }
817
818 void allocate(Primitive primitive) {
819 if (primitive.registerIndex == null) {
820 primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex();
821 }
822 }
823
824 void release(Primitive primitive) {
825 // Do not share indices for temporaries as this may obstruct inlining.
826 if (primitive.hint == null) return;
827 if (primitive.registerIndex != null) {
828 getRegisterArray(primitive.hint).releaseIndex(primitive.registerIndex);
829 }
830 }
831
832 void visitReference(Reference reference) {
833 allocate(reference.definition);
834 }
835
836 void visitFunctionDefinition(FunctionDefinition node) {
837 if (!node.isAbstract) {
838 visit(node.body);
839 }
840 node.parameters.forEach(allocate); // Assign indices to unused parameters.
841 elementRegisters.clear();
842 }
843
844 void visitLetPrim(LetPrim node) {
845 visit(node.body);
846 release(node.primitive);
847 visit(node.primitive);
848 }
849
850 void visitLetCont(LetCont node) {
851 visit(node.continuation);
852 visit(node.body);
853 }
854
855 void visitInvokeStatic(InvokeStatic node) {
856 node.arguments.forEach(visitReference);
857 }
858
859 void visitInvokeContinuation(InvokeContinuation node) {
860 node.arguments.forEach(visitReference);
861 }
862
863 void visitInvokeMethod(InvokeMethod node) {
864 visitReference(node.receiver);
865 node.arguments.forEach(visitReference);
866 }
867
868 void visitInvokeSuperMethod(InvokeSuperMethod node) {
869 node.arguments.forEach(visitReference);
870 }
871
872 void visitInvokeConstructor(InvokeConstructor node) {
873 node.arguments.forEach(visitReference);
874 }
875
876 void visitConcatenateStrings(ConcatenateStrings node) {
877 node.arguments.forEach(visitReference);
878 }
879
880 void visitBranch(Branch node) {
881 visit(node.condition);
882 }
883
884 void visitLiteralList(LiteralList node) {
885 node.values.forEach(visitReference);
886 }
887
888 void visitLiteralMap(LiteralMap node) {
889 for (int i = 0; i < node.keys.length; ++i) {
890 visitReference(node.keys[i]);
891 visitReference(node.values[i]);
892 }
893 }
894
895 void visitTypeOperator(TypeOperator node) {
896 visitReference(node.receiver);
897 }
898
899 void visitConstant(Constant node) {
900 }
901
902 void visitThis(This node) {
903 }
904
905 void visitReifyTypeVar(ReifyTypeVar node) {
906 }
907
908 void visitCreateFunction(CreateFunction node) {
909 new RegisterAllocator().visit(node.definition);
910 }
911
912 void visitGetClosureVariable(GetClosureVariable node) {
913 }
914
915 void visitSetClosureVariable(SetClosureVariable node) {
916 visit(node.body);
917 visitReference(node.value);
918 }
919
920 void visitDeclareFunction(DeclareFunction node) {
921 new RegisterAllocator().visit(node.definition);
922 visit(node.body);
923 }
924
925 void visitParameter(Parameter node) {
926 throw "Parameters should not be visited by RegisterAllocator";
927 }
928
929 void visitContinuation(Continuation node) {
930 visit(node.body);
931
932 // Arguments get allocated left-to-right, so we release parameters
933 // right-to-left. This increases the likelihood that arguments can be
934 // transferred without intermediate assignments.
935 for (int i = node.parameters.length - 1; i >= 0; --i) {
936 release(node.parameters[i]);
937 }
938 }
939
940 void visitIsTrue(IsTrue node) {
941 visitReference(node.value);
942 }
943
944 }
945
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698