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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/constant_propagation.dart

Issue 800433003: First version of typr propagation in the new IR. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rename constant_propagation.dart to type_propagation.dart. Created 6 years 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, 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.optimizers;
6
7 /**
8 * Propagates constants throughout the IR, and replaces branches with fixed
9 * jumps as well as side-effect free expressions with known constant results.
10 * Should be followed by the [ShrinkingReducer] pass.
11 *
12 * Implemented according to 'Constant Propagation with Conditional Branches'
13 * by Wegman, Zadeck.
14 */
15 class ConstantPropagator extends Pass {
16
17 // Required for type determination in analysis of TypeOperator expressions.
18 final dart2js.Compiler _compiler;
19
20 // The constant system is used for evaluation of expressions with constant
21 // arguments.
22 final dart2js.ConstantSystem _constantSystem;
23
24 ConstantPropagator(this._compiler, this._constantSystem);
25
26 void _rewriteExecutableDefinition(ExecutableDefinition root) {
27 // Set all parent pointers.
28 new ParentVisitor().visit(root);
29
30 // Analyze. In this phase, the entire term is analyzed for reachability
31 // and the constant status of each expression.
32
33 _ConstPropagationVisitor analyzer =
34 new _ConstPropagationVisitor(_compiler, _constantSystem);
35 analyzer.analyze(root);
36
37 // Transform. Uses the data acquired in the previous analysis phase to
38 // replace branches with fixed targets and side-effect-free expressions
39 // with constant results.
40
41 _TransformingVisitor transformer = new _TransformingVisitor(
42 analyzer.reachableNodes, analyzer.node2value);
43 transformer.transform(root);
44 }
45
46 void rewriteFunctionDefinition(FunctionDefinition root) {
47 if (root.isAbstract) return;
48 _rewriteExecutableDefinition(root);
49 }
50
51 void rewriteFieldDefinition(FieldDefinition root) {
52 if (!root.hasInitializer) return;
53 _rewriteExecutableDefinition(root);
54 }
55
56 }
57
58 /**
59 * Uses the information from a preceding analysis pass in order to perform the
60 * actual transformations on the CPS graph.
61 */
62 class _TransformingVisitor extends RecursiveVisitor {
63
64 final Set<Node> reachable;
65 final Map<Node, _ConstnessLattice> node2value;
66
67 _TransformingVisitor(this.reachable, this.node2value);
68
69 void transform(ExecutableDefinition root) {
70 visit(root);
71 }
72
73 /// Given an expression with a known constant result and a continuation,
74 /// replaces the expression by a new LetPrim / InvokeContinuation construct.
75 /// `unlink` is a closure responsible for unlinking all removed references.
76 LetPrim constifyExpression(Expression node,
77 Continuation continuation,
78 void unlink()) {
79 _ConstnessLattice cell = node2value[node];
80 if (cell == null || !cell.isConstant) {
81 return null;
82 }
83
84 assert(continuation.parameters.length == 1);
85
86 // Set up the replacement structure.
87
88 PrimitiveConstantValue primitiveConstant = cell.constant;
89 ConstantExpression constExp =
90 new PrimitiveConstantExpression(primitiveConstant);
91 Constant constant = new Constant(constExp);
92 LetPrim letPrim = new LetPrim(constant);
93 InvokeContinuation invoke =
94 new InvokeContinuation(continuation, <Primitive>[constant]);
95
96 invoke.parent = constant.parent = letPrim;
97 letPrim.body = invoke;
98
99 // Replace the method invocation.
100
101 InteriorNode parent = node.parent;
102 letPrim.parent = parent;
103 parent.body = letPrim;
104
105 unlink();
106
107 return letPrim;
108 }
109
110 // A branch can be eliminated and replaced by an invocation if only one of
111 // the possible continuations is reachable. Removal often leads to both dead
112 // primitives (the condition variable) and dead continuations (the unreachable
113 // branch), which are both removed by the shrinking reductions pass.
114 //
115 // (Branch (IsTrue true) k0 k1) -> (InvokeContinuation k0)
116 void visitBranch(Branch node) {
117 bool trueReachable = reachable.contains(node.trueContinuation.definition);
118 bool falseReachable = reachable.contains(node.falseContinuation.definition);
119 bool bothReachable = (trueReachable && falseReachable);
120 bool noneReachable = !(trueReachable || falseReachable);
121
122 if (bothReachable || noneReachable) {
123 // Nothing to do, shrinking reductions take care of the unreachable case.
124 super.visitBranch(node);
125 return;
126 }
127
128 Continuation successor = (trueReachable) ?
129 node.trueContinuation.definition : node.falseContinuation.definition;
130
131 // Replace the branch by a continuation invocation.
132
133 assert(successor.parameters.isEmpty);
134 InvokeContinuation invoke =
135 new InvokeContinuation(successor, <Primitive>[]);
136
137 InteriorNode parent = node.parent;
138 invoke.parent = parent;
139 parent.body = invoke;
140
141 // Unlink all removed references.
142
143 node.trueContinuation.unlink();
144 node.falseContinuation.unlink();
145 IsTrue isTrue = node.condition;
146 isTrue.value.unlink();
147
148 visitInvokeContinuation(invoke);
149 }
150
151 // Side-effect free method calls with constant results can be replaced by
152 // a LetPrim / InvokeContinuation pair. May lead to dead primitives which
153 // are removed by the shrinking reductions pass.
154 //
155 // (InvokeMethod v0 == v1 k0)
156 // -> (assuming the result is a constant `true`)
157 // (LetPrim v2 (Constant true))
158 // (InvokeContinuation k0 v2)
159 void visitInvokeMethod(InvokeMethod node) {
160 Continuation cont = node.continuation.definition;
161 LetPrim letPrim = constifyExpression(node, cont, () {
162 node.receiver.unlink();
163 node.continuation.unlink();
164 node.arguments.forEach((Reference ref) => ref.unlink());
165 });
166
167 if (letPrim == null) {
168 super.visitInvokeMethod(node);
169 } else {
170 visitLetPrim(letPrim);
171 }
172 }
173
174 // See [visitInvokeMethod].
175 void visitConcatenateStrings(ConcatenateStrings node) {
176 Continuation cont = node.continuation.definition;
177 LetPrim letPrim = constifyExpression(node, cont, () {
178 node.continuation.unlink();
179 node.arguments.forEach((Reference ref) => ref.unlink());
180 });
181
182 if (letPrim == null) {
183 super.visitConcatenateStrings(node);
184 } else {
185 visitLetPrim(letPrim);
186 }
187 }
188
189 // See [visitInvokeMethod].
190 void visitTypeOperator(TypeOperator node) {
191 Continuation cont = node.continuation.definition;
192 LetPrim letPrim = constifyExpression(node, cont, () {
193 node.receiver.unlink();
194 node.continuation.unlink();
195 });
196
197 if (letPrim == null) {
198 super.visitTypeOperator(node);
199 } else {
200 visitLetPrim(letPrim);
201 }
202 }
203 }
204
205 /**
206 * Runs an analysis pass on the given function definition in order to detect
207 * const-ness as well as reachability, both of which are used in the subsequent
208 * transformation pass.
209 */
210 class _ConstPropagationVisitor extends Visitor {
211 // The node worklist stores nodes that are both reachable and need to be
212 // processed, but have not been processed yet. Using a worklist avoids deep
213 // recursion.
214 // The node worklist and the reachable set operate in concert: nodes are
215 // only ever added to the worklist when they have not yet been marked as
216 // reachable, and adding a node to the worklist is always followed by marking
217 // it reachable.
218 // TODO(jgruber): Storing reachability per-edge instead of per-node would
219 // allow for further optimizations.
220 final List<Node> nodeWorklist = <Node>[];
221 final Set<Node> reachableNodes = new Set<Node>();
222
223 // The definition workset stores all definitions which need to be reprocessed
224 // since their lattice value has changed.
225 final Set<Definition> defWorkset = new Set<Definition>();
226
227 final dart2js.Compiler compiler;
228 final dart2js.ConstantSystem constantSystem;
229
230 // Stores the current lattice value for nodes. Note that it contains not only
231 // definitions as keys, but also expressions such as method invokes.
232 // Access through [getValue] and [setValue].
233 final Map<Node, _ConstnessLattice> node2value = <Node, _ConstnessLattice>{};
234
235 _ConstPropagationVisitor(this.compiler, this.constantSystem);
236
237 void analyze(ExecutableDefinition root) {
238 reachableNodes.clear();
239 defWorkset.clear();
240 nodeWorklist.clear();
241
242 // Initially, only the root node is reachable.
243 setReachable(root);
244
245 while (true) {
246 if (nodeWorklist.isNotEmpty) {
247 // Process a new reachable expression.
248 Node node = nodeWorklist.removeLast();
249 visit(node);
250 } else if (defWorkset.isNotEmpty) {
251 // Process all usages of a changed definition.
252 Definition def = defWorkset.first;
253 defWorkset.remove(def);
254
255 // Visit all uses of this definition. This might add new entries to
256 // [nodeWorklist], for example by visiting a newly-constant usage within
257 // a branch node.
258 for (Reference ref = def.firstRef; ref != null; ref = ref.next) {
259 visit(ref.parent);
260 }
261 } else {
262 break; // Both worklists empty.
263 }
264 }
265 }
266
267 /// If the passed node is not yet reachable, mark it reachable and add it
268 /// to the work list.
269 void setReachable(Node node) {
270 if (!reachableNodes.contains(node)) {
271 reachableNodes.add(node);
272 nodeWorklist.add(node);
273 }
274 }
275
276 /// Returns the lattice value corresponding to [node], defaulting to unknown.
277 ///
278 /// Never returns null.
279 _ConstnessLattice getValue(Node node) {
280 _ConstnessLattice value = node2value[node];
281 return (value == null) ? _ConstnessLattice.Unknown : value;
282 }
283
284 /// Joins the passed lattice [updateValue] to the current value of [node],
285 /// and adds it to the definition work set if it has changed and [node] is
286 /// a definition.
287 void setValue(Node node, _ConstnessLattice updateValue) {
288 _ConstnessLattice oldValue = getValue(node);
289 _ConstnessLattice newValue = updateValue.join(oldValue);
290 if (oldValue == newValue) {
291 return;
292 }
293
294 // Values may only move in the direction UNKNOWN -> CONSTANT -> NONCONST.
295 assert(newValue.kind >= oldValue.kind);
296
297 node2value[node] = newValue;
298 if (node is Definition) {
299 defWorkset.add(node);
300 }
301 }
302
303 // -------------------------- Visitor overrides ------------------------------
304
305 void visitNode(Node node) {
306 compiler.internalError(NO_LOCATION_SPANNABLE,
307 "_ConstPropagationVisitor is stale, add missing visit overrides");
308 }
309
310 void visitFunctionDefinition(FunctionDefinition node) {
311 node.parameters.forEach(visit);
312 setReachable(node.body);
313 }
314
315 void visitFieldDefinition(FieldDefinition node) {
316 if (node.hasInitializer) {
317 setReachable(node.body);
318 }
319 }
320
321 // Expressions.
322
323 void visitLetPrim(LetPrim node) {
324 visit(node.primitive); // No reason to delay visits to primitives.
325 setReachable(node.body);
326 }
327
328 void visitLetCont(LetCont node) {
329 // The continuation is only marked as reachable on use.
330 setReachable(node.body);
331 }
332
333 void visitInvokeStatic(InvokeStatic node) {
334 Continuation cont = node.continuation.definition;
335 setReachable(cont);
336
337 assert(cont.parameters.length == 1);
338 Parameter returnValue = cont.parameters[0];
339 setValue(returnValue, _ConstnessLattice.NonConst);
340 }
341
342 void visitInvokeContinuation(InvokeContinuation node) {
343 Continuation cont = node.continuation.definition;
344 setReachable(cont);
345
346 // Forward the constant status of all continuation invokes to the
347 // continuation. Note that this is effectively a phi node in SSA terms.
348 for (int i = 0; i < node.arguments.length; i++) {
349 Definition def = node.arguments[i].definition;
350 _ConstnessLattice cell = getValue(def);
351 setValue(cont.parameters[i], cell);
352 }
353 }
354
355 void visitInvokeMethod(InvokeMethod node) {
356 Continuation cont = node.continuation.definition;
357 setReachable(cont);
358
359 /// Sets the value of both the current node and the target continuation
360 /// parameter.
361 void setValues(_ConstnessLattice updateValue) {
362 setValue(node, updateValue);
363 Parameter returnValue = cont.parameters[0];
364 setValue(returnValue, updateValue);
365 }
366
367 _ConstnessLattice lhs = getValue(node.receiver.definition);
368 if (lhs.isUnknown) {
369 // This may seem like a missed opportunity for evaluating short-circuiting
370 // boolean operations; we are currently skipping these intentionally since
371 // expressions such as `(new Foo() || true)` may introduce type errors
372 // and thus evaluation to `true` would not be correct.
373 // TODO(jgruber): Handle such cases while ensuring that new Foo() and
374 // a type-check (in checked mode) are still executed.
375 return; // And come back later.
376 } else if (lhs.isNonConst) {
377 setValues(_ConstnessLattice.NonConst);
378 return;
379 } else if (!node.selector.isOperator) {
380 // TODO(jgruber): Handle known methods on constants such as String.length.
381 setValues(_ConstnessLattice.NonConst);
382 return;
383 }
384
385 // Calculate the resulting constant if possible.
386 ConstantValue result;
387 String opname = node.selector.name;
388 if (node.selector.argumentCount == 0) {
389 // Unary operator.
390
391 if (opname == "unary-") {
392 opname = "-";
393 }
394 dart2js.UnaryOperation operation = constantSystem.lookupUnary(opname);
395 if (operation != null) {
396 result = operation.fold(lhs.constant);
397 }
398 } else if (node.selector.argumentCount == 1) {
399 // Binary operator.
400
401 _ConstnessLattice rhs = getValue(node.arguments[0].definition);
402 if (!rhs.isConstant) {
403 setValues(rhs);
404 return;
405 }
406
407 dart2js.BinaryOperation operation = constantSystem.lookupBinary(opname);
408 if (operation != null) {
409 result = operation.fold(lhs.constant, rhs.constant);
410 }
411 }
412
413 // Update value of the continuation parameter. Again, this is effectively
414 // a phi.
415
416 setValues((result == null) ?
417 _ConstnessLattice.NonConst : new _ConstnessLattice(result));
418 }
419
420 void visitInvokeSuperMethod(InvokeSuperMethod node) {
421 Continuation cont = node.continuation.definition;
422 setReachable(cont);
423
424 assert(cont.parameters.length == 1);
425 Parameter returnValue = cont.parameters[0];
426 setValue(returnValue, _ConstnessLattice.NonConst);
427 }
428
429 void visitInvokeConstructor(InvokeConstructor node) {
430 Continuation cont = node.continuation.definition;
431 setReachable(cont);
432
433 assert(cont.parameters.length == 1);
434 Parameter returnValue = cont.parameters[0];
435 setValue(returnValue, _ConstnessLattice.NonConst);
436 }
437
438 void visitConcatenateStrings(ConcatenateStrings node) {
439 Continuation cont = node.continuation.definition;
440 setReachable(cont);
441
442 void setValues(_ConstnessLattice updateValue) {
443 setValue(node, updateValue);
444 Parameter returnValue = cont.parameters[0];
445 setValue(returnValue, updateValue);
446 }
447
448 // TODO(jgruber): Currently we only optimize if all arguments are string
449 // constants, but we could also handle cases such as "foo${42}".
450 bool allStringConstants = node.arguments.every((Reference ref) {
451 if (!(ref.definition is Constant)) {
452 return false;
453 }
454 Constant constant = ref.definition;
455 return constant != null && constant.value.isString;
456 });
457
458 assert(cont.parameters.length == 1);
459 if (allStringConstants) {
460 // All constant, we can concatenate ourselves.
461 Iterable<String> allStrings = node.arguments.map((Reference ref) {
462 Constant constant = ref.definition;
463 StringConstantValue stringConstant = constant.value;
464 return stringConstant.primitiveValue.slowToString();
465 });
466 LiteralDartString dartString = new LiteralDartString(allStrings.join());
467 ConstantValue constant = new StringConstantValue(dartString);
468 setValues(new _ConstnessLattice(constant));
469 } else {
470 setValues(_ConstnessLattice.NonConst);
471 }
472 }
473
474 void visitBranch(Branch node) {
475 IsTrue isTrue = node.condition;
476 _ConstnessLattice conditionCell = getValue(isTrue.value.definition);
477
478 if (conditionCell.isUnknown) {
479 return; // And come back later.
480 } else if (conditionCell.isNonConst) {
481 setReachable(node.trueContinuation.definition);
482 setReachable(node.falseContinuation.definition);
483 } else if (conditionCell.isConstant &&
484 !(conditionCell.constant.isBool)) {
485 // Treat non-bool constants in condition as non-const since they result
486 // in type errors in checked mode.
487 // TODO(jgruber): Default to false in unchecked mode.
488 setReachable(node.trueContinuation.definition);
489 setReachable(node.falseContinuation.definition);
490 setValue(isTrue.value.definition, _ConstnessLattice.NonConst);
491 } else if (conditionCell.isConstant &&
492 conditionCell.constant.isBool) {
493 BoolConstantValue boolConstant = conditionCell.constant;
494 setReachable((boolConstant.isTrue) ?
495 node.trueContinuation.definition : node.falseContinuation.definition);
496 }
497 }
498
499 void visitTypeOperator(TypeOperator node) {
500 Continuation cont = node.continuation.definition;
501 setReachable(cont);
502
503 void setValues(_ConstnessLattice updateValue) {
504 setValue(node, updateValue);
505 Parameter returnValue = cont.parameters[0];
506 setValue(returnValue, updateValue);
507 }
508
509 if (node.isTypeCast) {
510 // TODO(jgruber): Add support for `as` casts.
511 setValues(_ConstnessLattice.NonConst);
512 }
513
514 _ConstnessLattice cell = getValue(node.receiver.definition);
515 if (cell.isUnknown) {
516 return; // And come back later.
517 } else if (cell.isNonConst) {
518 setValues(_ConstnessLattice.NonConst);
519 } else if (node.type.kind == types.TypeKind.INTERFACE) {
520 // Receiver is a constant, perform is-checks at compile-time.
521
522 types.InterfaceType checkedType = node.type;
523 ConstantValue constant = cell.constant;
524 types.DartType constantType = constant.computeType(compiler);
525
526 _ConstnessLattice result = _ConstnessLattice.NonConst;
527 if (constant.isNull &&
528 checkedType.element != compiler.nullClass &&
529 checkedType.element != compiler.objectClass) {
530 // `(null is Type)` is true iff Type is in { Null, Object }.
531 result = new _ConstnessLattice(new FalseConstantValue());
532 } else {
533 // Otherwise, perform a standard subtype check.
534 result = new _ConstnessLattice(
535 constantSystem.isSubtype(compiler, constantType, checkedType)
536 ? new TrueConstantValue()
537 : new FalseConstantValue());
538 }
539
540 setValues(result);
541 }
542 }
543
544 void visitSetClosureVariable(SetClosureVariable node) {
545 setReachable(node.body);
546 }
547
548 void visitDeclareFunction(DeclareFunction node) {
549 setReachable(node.definition);
550 setReachable(node.body);
551 }
552
553 // Definitions.
554 void visitLiteralList(LiteralList node) {
555 // Constant lists are translated into (Constant ListConstant(...)) IR nodes,
556 // and thus LiteralList nodes are NonConst.
557 setValue(node, _ConstnessLattice.NonConst);
558 }
559
560 void visitLiteralMap(LiteralMap node) {
561 // Constant maps are translated into (Constant MapConstant(...)) IR nodes,
562 // and thus LiteralMap nodes are NonConst.
563 setValue(node, _ConstnessLattice.NonConst);
564 }
565
566 void visitConstant(Constant node) {
567 setValue(node, new _ConstnessLattice(node.value));
568 }
569
570 void visitThis(This node) {
571 setValue(node, _ConstnessLattice.NonConst);
572 }
573
574 void visitReifyTypeVar(ReifyTypeVar node) {
575 setValue(node, _ConstnessLattice.NonConst);
576 }
577
578 void visitCreateFunction(CreateFunction node) {
579 setReachable(node.definition);
580 ConstantValue constant =
581 new FunctionConstantValue(node.definition.element);
582 setValue(node, new _ConstnessLattice(constant));
583 }
584
585 void visitGetClosureVariable(GetClosureVariable node) {
586 setValue(node, _ConstnessLattice.NonConst);
587 }
588
589 void visitClosureVariable(ClosureVariable node) {
590 }
591
592 void visitParameter(Parameter node) {
593 if (node.parent is FunctionDefinition) {
594 // Functions may escape and thus their parameters must be initialized to
595 // NonConst.
596 setValue(node, _ConstnessLattice.NonConst);
597 } else if (node.parent is Continuation) {
598 // Continuations on the other hand are local, and parameters are
599 // initialized to Unknown.
600 setValue(node, _ConstnessLattice.Unknown);
601 } else {
602 compiler.internalError(node.hint, "Unexpected parent of Parameter");
603 }
604 }
605
606 void visitContinuation(Continuation node) {
607 node.parameters.forEach((Parameter p) {
608 setValue(p, _ConstnessLattice.Unknown);
609 defWorkset.add(p);
610 });
611
612 if (node.body != null) {
613 setReachable(node.body);
614 }
615 }
616
617 // Conditions.
618
619 void visitIsTrue(IsTrue node) {
620 Branch branch = node.parent;
621 visitBranch(branch);
622 }
623
624 // JavaScript specific nodes.
625
626 void visitIdentical(Identical node) {
627 _ConstnessLattice leftConst = getValue(node.left.definition);
628 _ConstnessLattice rightConst = getValue(node.left.definition);
629 ConstantValue leftValue = leftConst.constant;
630 ConstantValue rightValue = rightConst.constant;
631 if (leftConst.isUnknown || rightConst.isUnknown) {
632 // Come back later.
633 return;
634 } else if (!leftConst.isConstant || !rightConst.isConstant) {
635 setValue(node, _ConstnessLattice.NonConst);
636 } else if (leftValue.isPrimitive && rightValue.isPrimitive) {
637 assert(leftConst.isConstant && rightConst.isConstant);
638 PrimitiveConstantValue left = leftValue;
639 PrimitiveConstantValue right = rightValue;
640 ConstantValue result =
641 new BoolConstantValue(left.primitiveValue == right.primitiveValue);
642 setValue(node, new _ConstnessLattice(result));
643 }
644 }
645 }
646
647 /// Represents the constant-state of a variable at some point in the program.
648 /// UNKNOWN: may be some as yet undetermined constant.
649 /// CONSTANT: is a constant as stored in the local field.
650 /// NONCONST: not a constant.
651 class _ConstnessLattice {
652 static const int UNKNOWN = 0;
653 static const int CONSTANT = 1;
654 static const int NONCONST = 2;
655
656 final int kind;
657 final ConstantValue constant;
658
659 static final _ConstnessLattice Unknown =
660 new _ConstnessLattice._internal(UNKNOWN, null);
661 static final _ConstnessLattice NonConst =
662 new _ConstnessLattice._internal(NONCONST, null);
663
664 _ConstnessLattice._internal(this.kind, this.constant);
665 _ConstnessLattice(this.constant) : kind = CONSTANT {
666 assert(this.constant != null);
667 }
668
669 bool get isUnknown => (kind == UNKNOWN);
670 bool get isConstant => (kind == CONSTANT);
671 bool get isNonConst => (kind == NONCONST);
672
673 int get hashCode => kind | (constant.hashCode << 2);
674 bool operator==(_ConstnessLattice that) =>
675 (that.kind == this.kind && that.constant == this.constant);
676
677 String toString() {
678 switch (kind) {
679 case UNKNOWN: return "Unknown";
680 case CONSTANT: return "Constant: $constant";
681 case NONCONST: return "Non-constant";
682 default: assert(false);
683 }
684 return null;
685 }
686
687 /// Compute the join of two values in the lattice.
688 _ConstnessLattice join(_ConstnessLattice that) {
689 assert(that != null);
690
691 if (this.isNonConst || that.isUnknown) {
692 return this;
693 }
694
695 if (this.isUnknown || that.isNonConst) {
696 return that;
697 }
698
699 if (this.constant == that.constant) {
700 return this;
701 }
702
703 return NonConst;
704 }
705 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698