OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 library dart2js.ir_nodes; | 4 library dart2js.ir_nodes; |
5 | 5 |
6 import 'dart:collection'; | |
6 import '../constants/values.dart' as values show ConstantValue; | 7 import '../constants/values.dart' as values show ConstantValue; |
7 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
8 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
9 import '../io/source_information.dart' show SourceInformation; | 10 import '../io/source_information.dart' show SourceInformation; |
10 import '../types/types.dart' show TypeMask; | 11 import '../types/types.dart' show TypeMask; |
11 import '../universe/universe.dart' show Selector; | 12 import '../universe/universe.dart' show Selector; |
12 | 13 |
13 import 'builtin_operator.dart'; | 14 import 'builtin_operator.dart'; |
14 export 'builtin_operator.dart'; | 15 export 'builtin_operator.dart'; |
15 | 16 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
112 previous = current; | 113 previous = current; |
113 current = current.next; | 114 current = current.next; |
114 } while (current != null); | 115 } while (current != null); |
115 previous.next = firstRef; | 116 previous.next = firstRef; |
116 if (firstRef != null) firstRef.previous = previous; | 117 if (firstRef != null) firstRef.previous = previous; |
117 firstRef = other.firstRef; | 118 firstRef = other.firstRef; |
118 other.firstRef = null; | 119 other.firstRef = null; |
119 } | 120 } |
120 } | 121 } |
121 | 122 |
123 class EffectiveUseIterator extends Iterator<Reference<Primitive>> { | |
124 Reference<Primitive> current; | |
125 Reference<Primitive> next; | |
126 final List<Primitive> stack = <Primitive>[]; | |
Kevin Millikin (Google)
2015/09/03 10:21:06
Probably clearer to make this List<Refinement>.
asgerf
2015/09/03 12:31:39
Done.
| |
127 | |
128 EffectiveUseIterator(Primitive prim) : next = prim.firstRef; | |
129 | |
130 bool moveNext() { | |
131 Reference<Primitive> ref = next; | |
132 while (true) { | |
133 if (ref == null) { | |
134 if (stack.isNotEmpty) { | |
135 ref = stack.removeLast().firstRef; | |
136 } else { | |
137 return false; | |
Kevin Millikin (Google)
2015/09/03 10:21:06
current should be null when the iterator has finis
asgerf
2015/09/03 12:31:39
Thanks, nice catch.
| |
138 } | |
139 } else if (ref.parent is Refinement) { | |
140 stack.add(ref.parent); | |
141 ref = ref.next; | |
142 } else { | |
143 current = ref; | |
144 next = current.next; | |
145 return true; | |
146 } | |
147 } | |
Kevin Millikin (Google)
2015/09/03 10:21:05
I think of this algorithm as a pair of nested loop
asgerf
2015/09/03 12:31:39
The problem is that 'next = ref.next' might be a R
| |
148 } | |
149 } | |
150 | |
151 class EffectiveUseIterable extends IterableBase<Reference<Primitive>> { | |
152 Primitive primitive; | |
153 EffectiveUseIterable(this.primitive); | |
154 EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive); | |
155 } | |
156 | |
122 /// A named value. | 157 /// A named value. |
123 /// | 158 /// |
124 /// The identity of the [Primitive] object is the name of the value. | 159 /// The identity of the [Primitive] object is the name of the value. |
125 /// The subclass describes how to compute the value. | 160 /// The subclass describes how to compute the value. |
126 /// | 161 /// |
127 /// All primitives except [Parameter] must be bound by a [LetPrim]. | 162 /// All primitives except [Parameter] must be bound by a [LetPrim]. |
128 abstract class Primitive extends Definition<Primitive> { | 163 abstract class Primitive extends Definition<Primitive> { |
129 /// The [VariableElement] or [ParameterElement] from which the primitive | 164 /// The [VariableElement] or [ParameterElement] from which the primitive |
130 /// binding originated. | 165 /// binding originated. |
131 Entity hint; | 166 Entity hint; |
(...skipping 14 matching lines...) Expand all Loading... | |
146 /// observable side-effects. | 181 /// observable side-effects. |
147 bool get isSafeForElimination; | 182 bool get isSafeForElimination; |
148 | 183 |
149 /// True if time-of-evaluation is irrelevant for the given primitive, | 184 /// True if time-of-evaluation is irrelevant for the given primitive, |
150 /// assuming its inputs are the same values. | 185 /// assuming its inputs are the same values. |
151 bool get isSafeForReordering; | 186 bool get isSafeForReordering; |
152 | 187 |
153 /// The source information associated with this primitive. | 188 /// The source information associated with this primitive. |
154 // TODO(johnniwinther): Require source information for all primitives. | 189 // TODO(johnniwinther): Require source information for all primitives. |
155 SourceInformation get sourceInformation => null; | 190 SourceInformation get sourceInformation => null; |
191 | |
192 /// If this is a [Refinement] node, returns the value being refined. | |
193 Primitive get effectiveDefinition => this; | |
194 | |
195 /// True if the two primitives are (refinements of) the same value. | |
196 bool sameValue(Primitive other) { | |
197 return effectiveDefinition == other.effectiveDefinition; | |
198 } | |
199 | |
200 /// Iterates all non-refinement uses of the primitive and all uses of | |
201 /// a [Refinement] of this primitive (transitively). | |
202 /// | |
203 /// Notes regarding concurrent modification: | |
204 /// - The current reference may safely be unlinked. | |
205 /// - Yet unvisited references may not be unlinked. | |
206 /// - References to this primitive created during iteration will not be seen. | |
207 /// - References to a refinement of this primitive may not be created during | |
208 /// iteration. | |
209 EffectiveUseIterable get effectiveUses => new EffectiveUseIterable(this); | |
210 | |
211 bool get hasMultipleEffectiveUses { | |
212 Iterator it = effectiveUses.iterator; | |
213 return it.moveNext() && it.moveNext(); | |
214 } | |
215 | |
216 bool get hasNoEffectiveUses { | |
217 return effectiveUses.isEmpty; | |
218 } | |
156 } | 219 } |
157 | 220 |
158 /// Operands to invocations and primitives are always variables. They point to | 221 /// Operands to invocations and primitives are always variables. They point to |
159 /// their definition and are doubly-linked into a list of occurrences. | 222 /// their definition and are doubly-linked into a list of occurrences. |
160 class Reference<T extends Definition<T>> { | 223 class Reference<T extends Definition<T>> { |
161 T definition; | 224 T definition; |
162 Reference<T> previous; | 225 Reference<T> previous; |
163 Reference<T> next; | 226 Reference<T> next; |
164 | 227 |
165 /// A pointer to the parent node. Is null until set by optimization passes. | 228 /// A pointer to the parent node. Is null until set by optimization passes. |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 this.selector, | 495 this.selector, |
433 List<Primitive> args, | 496 List<Primitive> args, |
434 Continuation cont, | 497 Continuation cont, |
435 this.sourceInformation) | 498 this.sourceInformation) |
436 : arguments = _referenceList(args), | 499 : arguments = _referenceList(args), |
437 continuation = new Reference<Continuation>(cont); | 500 continuation = new Reference<Continuation>(cont); |
438 | 501 |
439 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); | 502 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); |
440 } | 503 } |
441 | 504 |
505 /// An alias for [value] in a context where the value is known to satisfy | |
506 /// [type]. | |
507 /// | |
508 /// Refinement nodes are inserted before the type propagator pass and removed | |
509 /// afterwards, so as not to complicate passes that don't reason about types, | |
510 /// but need to reason about value references being identical (i.e. referring | |
511 /// to the same primitive). | |
512 class Refinement extends Primitive { | |
513 Reference<Primitive> value; | |
514 final TypeMask type; | |
515 | |
516 Refinement(Primitive value, this.type) | |
517 : value = new Reference<Primitive>(value); | |
518 | |
519 bool get isSafeForElimination => true; | |
520 bool get isSafeForReordering => false; | |
521 | |
522 accept(Visitor visitor) => visitor.visitRefinement(this); | |
523 | |
524 Primitive get effectiveDefinition => value.definition.effectiveDefinition; | |
525 } | |
526 | |
442 /// An "is" type test. | 527 /// An "is" type test. |
443 /// | 528 /// |
444 /// Returns `true` if [value] is an instance of [type]. | 529 /// Returns `true` if [value] is an instance of [type]. |
445 /// | 530 /// |
446 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might | 531 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might |
447 /// be a type variable containing one of these types). This design is chosen | 532 /// be a type variable containing one of these types). This design is chosen |
448 /// to simplify code generation for type tests. | 533 /// to simplify code generation for type tests. |
449 class TypeTest extends Primitive { | 534 class TypeTest extends Primitive { |
450 Reference<Primitive> value; | 535 Reference<Primitive> value; |
451 final DartType type; | 536 final DartType type; |
(...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1194 T visitReifyRuntimeType(ReifyRuntimeType node); | 1279 T visitReifyRuntimeType(ReifyRuntimeType node); |
1195 T visitReadTypeVariable(ReadTypeVariable node); | 1280 T visitReadTypeVariable(ReadTypeVariable node); |
1196 T visitTypeExpression(TypeExpression node); | 1281 T visitTypeExpression(TypeExpression node); |
1197 T visitCreateInvocationMirror(CreateInvocationMirror node); | 1282 T visitCreateInvocationMirror(CreateInvocationMirror node); |
1198 T visitTypeTest(TypeTest node); | 1283 T visitTypeTest(TypeTest node); |
1199 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); | 1284 T visitApplyBuiltinOperator(ApplyBuiltinOperator node); |
1200 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); | 1285 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); |
1201 T visitGetLength(GetLength node); | 1286 T visitGetLength(GetLength node); |
1202 T visitGetIndex(GetIndex node); | 1287 T visitGetIndex(GetIndex node); |
1203 T visitSetIndex(SetIndex node); | 1288 T visitSetIndex(SetIndex node); |
1289 T visitRefinement(Refinement node); | |
1204 | 1290 |
1205 // Support for literal foreign code. | 1291 // Support for literal foreign code. |
1206 T visitForeignCode(ForeignCode node); | 1292 T visitForeignCode(ForeignCode node); |
1207 } | 1293 } |
1208 | 1294 |
1209 /// Visits all non-recursive children of a CPS term, i.e. anything | 1295 /// Visits all non-recursive children of a CPS term, i.e. anything |
1210 /// not of type [Expression] or [Continuation]. | 1296 /// not of type [Expression] or [Continuation]. |
1211 /// | 1297 /// |
1212 /// The `process*` methods are called in pre-order for every node visited. | 1298 /// The `process*` methods are called in pre-order for every node visited. |
1213 /// These can be overridden without disrupting the visitor traversal. | 1299 /// These can be overridden without disrupting the visitor traversal. |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1497 processReference(node.index); | 1583 processReference(node.index); |
1498 } | 1584 } |
1499 | 1585 |
1500 processSetIndex(SetIndex node) {} | 1586 processSetIndex(SetIndex node) {} |
1501 visitSetIndex(SetIndex node) { | 1587 visitSetIndex(SetIndex node) { |
1502 processSetIndex(node); | 1588 processSetIndex(node); |
1503 processReference(node.object); | 1589 processReference(node.object); |
1504 processReference(node.index); | 1590 processReference(node.index); |
1505 processReference(node.value); | 1591 processReference(node.value); |
1506 } | 1592 } |
1593 | |
1594 processRefinement(Refinement node) {} | |
1595 visitRefinement(Refinement node) { | |
1596 processRefinement(node); | |
1597 processReference(node.value); | |
1598 } | |
1507 } | 1599 } |
1508 | 1600 |
1509 typedef void StackAction(); | 1601 typedef void StackAction(); |
1510 | 1602 |
1511 /// Calls `process*` for all nodes in a tree. | 1603 /// Calls `process*` for all nodes in a tree. |
1512 /// For simple usage, only override the `process*` methods. | 1604 /// For simple usage, only override the `process*` methods. |
1513 /// | 1605 /// |
1514 /// To avoid deep recursion, this class uses an "action stack" containing | 1606 /// To avoid deep recursion, this class uses an "action stack" containing |
1515 /// callbacks to be invoked after the processing of some term has finished. | 1607 /// callbacks to be invoked after the processing of some term has finished. |
1516 /// | 1608 /// |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1628 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 1720 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
1629 class RemovalVisitor extends RecursiveVisitor { | 1721 class RemovalVisitor extends RecursiveVisitor { |
1630 processReference(Reference reference) { | 1722 processReference(Reference reference) { |
1631 reference.unlink(); | 1723 reference.unlink(); |
1632 } | 1724 } |
1633 | 1725 |
1634 static void remove(Node node) { | 1726 static void remove(Node node) { |
1635 (new RemovalVisitor()).visit(node); | 1727 (new RemovalVisitor()).visit(node); |
1636 } | 1728 } |
1637 } | 1729 } |
OLD | NEW |