| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 | 4 |
| 5 library dart2js.cps_ir.bounds_checker; | 5 library dart2js.cps_ir.bounds_checker; |
| 6 | 6 |
| 7 import 'cps_ir_nodes.dart'; | 7 import 'cps_ir_nodes.dart'; |
| 8 import 'optimizers.dart' show Pass; | 8 import 'optimizers.dart' show Pass; |
| 9 import 'octagon.dart'; | 9 import 'octagon.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 | 262 |
| 263 bool isDefinitelyGreaterThanOrEqualToConstant(SignedVariable v1, int value) { | 263 bool isDefinitelyGreaterThanOrEqualToConstant(SignedVariable v1, int value) { |
| 264 // v1 >= value <==> -v1 - v1 <= -2 * value | 264 // v1 >= value <==> -v1 - v1 <= -2 * value |
| 265 return testConstraint(v1.negated, v1.negated, -2 * value); | 265 return testConstraint(v1.negated, v1.negated, -2 * value); |
| 266 } | 266 } |
| 267 | 267 |
| 268 // ------------- TAIL EXPRESSIONS ----------------- | 268 // ------------- TAIL EXPRESSIONS ----------------- |
| 269 | 269 |
| 270 @override | 270 @override |
| 271 void visitBranch(Branch node) { | 271 void visitBranch(Branch node) { |
| 272 Primitive condition = node.condition.definition; | 272 Primitive condition = node.condition; |
| 273 Continuation trueCont = node.trueContinuation.definition; | 273 Continuation trueCont = node.trueContinuation; |
| 274 Continuation falseCont = node.falseContinuation.definition; | 274 Continuation falseCont = node.falseContinuation; |
| 275 effectNumberAt[trueCont] = currentEffectNumber; | 275 effectNumberAt[trueCont] = currentEffectNumber; |
| 276 effectNumberAt[falseCont] = currentEffectNumber; | 276 effectNumberAt[falseCont] = currentEffectNumber; |
| 277 pushAction(() { | 277 pushAction(() { |
| 278 // If the branching condition is known statically, either or both of the | 278 // If the branching condition is known statically, either or both of the |
| 279 // branch continuations will be replaced by Unreachable. Clean up the | 279 // branch continuations will be replaced by Unreachable. Clean up the |
| 280 // branch afterwards. | 280 // branch afterwards. |
| 281 if (trueCont.body is Unreachable && falseCont.body is Unreachable) { | 281 if (trueCont.body is Unreachable && falseCont.body is Unreachable) { |
| 282 destroyAndReplace(node, new Unreachable()); | 282 destroyAndReplace(node, new Unreachable()); |
| 283 } else if (trueCont.body is Unreachable) { | 283 } else if (trueCont.body is Unreachable) { |
| 284 destroyAndReplace( | 284 destroyAndReplace( |
| 285 node, new InvokeContinuation(falseCont, <Parameter>[])); | 285 node, new InvokeContinuation(falseCont, <Parameter>[])); |
| 286 } else if (falseCont.body is Unreachable) { | 286 } else if (falseCont.body is Unreachable) { |
| 287 destroyAndReplace( | 287 destroyAndReplace( |
| 288 node, new InvokeContinuation(trueCont, <Parameter>[])); | 288 node, new InvokeContinuation(trueCont, <Parameter>[])); |
| 289 } | 289 } |
| 290 }); | 290 }); |
| 291 void pushTrue(makeConstraint()) { | 291 void pushTrue(makeConstraint()) { |
| 292 pushAction(() { | 292 pushAction(() { |
| 293 makeConstraint(); | 293 makeConstraint(); |
| 294 push(trueCont); | 294 push(trueCont); |
| 295 }); | 295 }); |
| 296 } | 296 } |
| 297 void pushFalse(makeConstraint()) { | 297 void pushFalse(makeConstraint()) { |
| 298 pushAction(() { | 298 pushAction(() { |
| 299 makeConstraint(); | 299 makeConstraint(); |
| 300 push(falseCont); | 300 push(falseCont); |
| 301 }); | 301 }); |
| 302 } | 302 } |
| 303 if (condition is ApplyBuiltinOperator && | 303 if (condition is ApplyBuiltinOperator && |
| 304 condition.arguments.length == 2 && | 304 condition.argumentRefs.length == 2 && |
| 305 isInt(condition.arguments[0].definition) && | 305 isInt(condition.argument(0)) && |
| 306 isInt(condition.arguments[1].definition)) { | 306 isInt(condition.argument(1))) { |
| 307 SignedVariable v1 = getValue(condition.arguments[0].definition); | 307 SignedVariable v1 = getValue(condition.argument(0)); |
| 308 SignedVariable v2 = getValue(condition.arguments[1].definition); | 308 SignedVariable v2 = getValue(condition.argument(1)); |
| 309 switch (condition.operator) { | 309 switch (condition.operator) { |
| 310 case BuiltinOperator.NumLe: | 310 case BuiltinOperator.NumLe: |
| 311 pushTrue(() => makeLessThanOrEqual(v1, v2)); | 311 pushTrue(() => makeLessThanOrEqual(v1, v2)); |
| 312 pushFalse(() => makeGreaterThan(v1, v2)); | 312 pushFalse(() => makeGreaterThan(v1, v2)); |
| 313 return; | 313 return; |
| 314 case BuiltinOperator.NumLt: | 314 case BuiltinOperator.NumLt: |
| 315 pushTrue(() => makeLessThan(v1, v2)); | 315 pushTrue(() => makeLessThan(v1, v2)); |
| 316 pushFalse(() => makeGreaterThanOrEqual(v1, v2)); | 316 pushFalse(() => makeGreaterThanOrEqual(v1, v2)); |
| 317 return; | 317 return; |
| 318 case BuiltinOperator.NumGe: | 318 case BuiltinOperator.NumGe: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 345 // constraints that reference it. | 345 // constraints that reference it. |
| 346 if (node.value.isInt) { | 346 if (node.value.isInt) { |
| 347 IntConstantValue constant = node.value; | 347 IntConstantValue constant = node.value; |
| 348 makeConstant(getValue(node), constant.primitiveValue); | 348 makeConstant(getValue(node), constant.primitiveValue); |
| 349 } | 349 } |
| 350 } | 350 } |
| 351 | 351 |
| 352 @override | 352 @override |
| 353 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { | 353 void visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
| 354 if (!isInt(node)) return; | 354 if (!isInt(node)) return; |
| 355 if (node.arguments.length == 1) { | 355 if (node.argumentRefs.length == 1) { |
| 356 applyUnaryOperator(node); | 356 applyUnaryOperator(node); |
| 357 } else if (node.arguments.length == 2) { | 357 } else if (node.argumentRefs.length == 2) { |
| 358 applyBinaryOperator(node); | 358 applyBinaryOperator(node); |
| 359 } | 359 } |
| 360 } | 360 } |
| 361 | 361 |
| 362 void applyBinaryOperator(ApplyBuiltinOperator node) { | 362 void applyBinaryOperator(ApplyBuiltinOperator node) { |
| 363 Primitive left = node.arguments[0].definition; | 363 Primitive left = node.argument(0); |
| 364 Primitive right = node.arguments[1].definition; | 364 Primitive right = node.argument(1); |
| 365 if (!isInt(left) || !isInt(right)) { | 365 if (!isInt(left) || !isInt(right)) { |
| 366 return; | 366 return; |
| 367 } | 367 } |
| 368 SignedVariable leftVar = getValue(left); | 368 SignedVariable leftVar = getValue(left); |
| 369 SignedVariable rightVar = getValue(right); | 369 SignedVariable rightVar = getValue(right); |
| 370 SignedVariable result = getValue(node); | 370 SignedVariable result = getValue(node); |
| 371 switch (node.operator) { | 371 switch (node.operator) { |
| 372 case BuiltinOperator.NumAdd: | 372 case BuiltinOperator.NumAdd: |
| 373 int leftConst = getIntConstant(left); | 373 int leftConst = getIntConstant(left); |
| 374 if (leftConst != null) { | 374 if (leftConst != null) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 if (isUInt32(right)) { | 455 if (isUInt32(right)) { |
| 456 makeLessThanOrEqual(result, rightVar); | 456 makeLessThanOrEqual(result, rightVar); |
| 457 } | 457 } |
| 458 break; | 458 break; |
| 459 | 459 |
| 460 default: | 460 default: |
| 461 } | 461 } |
| 462 } | 462 } |
| 463 | 463 |
| 464 void applyUnaryOperator(ApplyBuiltinOperator node) { | 464 void applyUnaryOperator(ApplyBuiltinOperator node) { |
| 465 Primitive argument = node.arguments[0].definition; | 465 Primitive argument = node.argument(0); |
| 466 if (!isInt(argument)) return; | 466 if (!isInt(argument)) return; |
| 467 if (node.operator == BuiltinOperator.NumNegate) { | 467 if (node.operator == BuiltinOperator.NumNegate) { |
| 468 valueOf[node] = getValue(argument).negated; | 468 valueOf[node] = getValue(argument).negated; |
| 469 } | 469 } |
| 470 } | 470 } |
| 471 | 471 |
| 472 int getIntConstant(Primitive prim) { | 472 int getIntConstant(Primitive prim) { |
| 473 if (prim is Constant && prim.value.isInt) { | 473 if (prim is Constant && prim.value.isInt) { |
| 474 IntConstantValue constant = prim.value; | 474 IntConstantValue constant = prim.value; |
| 475 return constant.primitiveValue; | 475 return constant.primitiveValue; |
| 476 } | 476 } |
| 477 return null; | 477 return null; |
| 478 } | 478 } |
| 479 | 479 |
| 480 @override | 480 @override |
| 481 void visitRefinement(Refinement node) { | 481 void visitRefinement(Refinement node) { |
| 482 // In general we should get the container length of the refined type and | 482 // In general we should get the container length of the refined type and |
| 483 // add a constraint if we know the length after the refinement. | 483 // add a constraint if we know the length after the refinement. |
| 484 // However, our current type system removes container information when a | 484 // However, our current type system removes container information when a |
| 485 // type becomes part of a union, so this cannot happen. | 485 // type becomes part of a union, so this cannot happen. |
| 486 } | 486 } |
| 487 | 487 |
| 488 @override | 488 @override |
| 489 void visitGetLength(GetLength node) { | 489 void visitGetLength(GetLength node) { |
| 490 valueOf[node] = getLength(node.object.definition, currentEffectNumber); | 490 valueOf[node] = getLength(node.object, currentEffectNumber); |
| 491 } | 491 } |
| 492 | 492 |
| 493 @override | 493 @override |
| 494 void visitBoundsCheck(BoundsCheck node) { | 494 void visitBoundsCheck(BoundsCheck node) { |
| 495 if (node.checks == BoundsCheck.NONE) return; | 495 if (node.checks == BoundsCheck.NONE) return; |
| 496 assert(node.index != null); // Because there is at least one check. | 496 assert(node.indexRef != null); // Because there is at least one check. |
| 497 SignedVariable length = node.length == null | 497 SignedVariable length = node.lengthRef == null |
| 498 ? null | 498 ? null |
| 499 : getValue(node.length.definition); | 499 : getValue(node.length); |
| 500 SignedVariable index = getValue(node.index.definition); | 500 SignedVariable index = getValue(node.index); |
| 501 if (node.hasUpperBoundCheck) { | 501 if (node.hasUpperBoundCheck) { |
| 502 if (isDefinitelyLessThan(index, length)) { | 502 if (isDefinitelyLessThan(index, length)) { |
| 503 node.checks &= ~BoundsCheck.UPPER_BOUND; | 503 node.checks &= ~BoundsCheck.UPPER_BOUND; |
| 504 } else { | 504 } else { |
| 505 makeLessThan(index, length); | 505 makeLessThan(index, length); |
| 506 } | 506 } |
| 507 } | 507 } |
| 508 if (node.hasLowerBoundCheck) { | 508 if (node.hasLowerBoundCheck) { |
| 509 if (isDefinitelyGreaterThanOrEqualToConstant(index, 0)) { | 509 if (isDefinitelyGreaterThanOrEqualToConstant(index, 0)) { |
| 510 node.checks &= ~BoundsCheck.LOWER_BOUND; | 510 node.checks &= ~BoundsCheck.LOWER_BOUND; |
| 511 } else { | 511 } else { |
| 512 makeGreaterThanOrEqualToConstant(index, 0); | 512 makeGreaterThanOrEqualToConstant(index, 0); |
| 513 } | 513 } |
| 514 } | 514 } |
| 515 if (node.hasEmptinessCheck) { | 515 if (node.hasEmptinessCheck) { |
| 516 if (isDefinitelyGreaterThanOrEqualToConstant(length, 1)) { | 516 if (isDefinitelyGreaterThanOrEqualToConstant(length, 1)) { |
| 517 node.checks &= ~BoundsCheck.EMPTINESS; | 517 node.checks &= ~BoundsCheck.EMPTINESS; |
| 518 } else { | 518 } else { |
| 519 makeGreaterThanOrEqualToConstant(length, 1); | 519 makeGreaterThanOrEqualToConstant(length, 1); |
| 520 } | 520 } |
| 521 } | 521 } |
| 522 if (!node.lengthUsedInCheck && node.length != null) { | 522 if (!node.lengthUsedInCheck && node.lengthRef != null) { |
| 523 node..length.unlink()..length = null; | 523 node..lengthRef.unlink()..lengthRef = null; |
| 524 } | 524 } |
| 525 if (node.checks == BoundsCheck.NONE) { | 525 if (node.checks == BoundsCheck.NONE) { |
| 526 // We can't remove the bounds check node because it may still be used to | 526 // We can't remove the bounds check node because it may still be used to |
| 527 // restrict code motion. But the index is no longer needed. | 527 // restrict code motion. But the index is no longer needed. |
| 528 node..index.unlink()..index = null; | 528 node..indexRef.unlink()..indexRef = null; |
| 529 } | 529 } |
| 530 } | 530 } |
| 531 | 531 |
| 532 void analyzeLoopEntry(InvokeContinuation node) { | 532 void analyzeLoopEntry(InvokeContinuation node) { |
| 533 foundLoop = true; | 533 foundLoop = true; |
| 534 Continuation cont = node.continuation.definition; | 534 Continuation cont = node.continuation; |
| 535 if (isStrongLoopPass) { | 535 if (isStrongLoopPass) { |
| 536 for (int i = 0; i < node.arguments.length; ++i) { | 536 for (int i = 0; i < node.argumentRefs.length; ++i) { |
| 537 Parameter param = cont.parameters[i]; | 537 Parameter param = cont.parameters[i]; |
| 538 if (!isInt(param)) continue; | 538 if (!isInt(param)) continue; |
| 539 Primitive initialValue = node.arguments[i].definition; | 539 Primitive initialValue = node.argument(i); |
| 540 SignedVariable initialVariable = getValue(initialValue); | 540 SignedVariable initialVariable = getValue(initialValue); |
| 541 Monotonicity mono = monotonicity[param]; | 541 Monotonicity mono = monotonicity[param]; |
| 542 if (mono == null) { | 542 if (mono == null) { |
| 543 // Value never changes. This is extremely uncommon. | 543 // Value never changes. This is extremely uncommon. |
| 544 param.replaceUsesWith(initialValue); | 544 param.replaceUsesWith(initialValue); |
| 545 } else if (mono == Monotonicity.Increasing) { | 545 } else if (mono == Monotonicity.Increasing) { |
| 546 makeGreaterThanOrEqual(getValue(param), initialVariable); | 546 makeGreaterThanOrEqual(getValue(param), initialVariable); |
| 547 } else if (mono == Monotonicity.Decreasing) { | 547 } else if (mono == Monotonicity.Decreasing) { |
| 548 makeLessThanOrEqual(getValue(param), initialVariable); | 548 makeLessThanOrEqual(getValue(param), initialVariable); |
| 549 } | 549 } |
| 550 } | 550 } |
| 551 } | 551 } |
| 552 if (loopEffects.changesIndexableLength(cont)) { | 552 if (loopEffects.changesIndexableLength(cont)) { |
| 553 currentEffectNumber = effectNumberAt[cont] = makeNewEffect(); | 553 currentEffectNumber = effectNumberAt[cont] = makeNewEffect(); |
| 554 } | 554 } |
| 555 push(cont); | 555 push(cont); |
| 556 } | 556 } |
| 557 | 557 |
| 558 void analyzeLoopContinue(InvokeContinuation node) { | 558 void analyzeLoopContinue(InvokeContinuation node) { |
| 559 Continuation cont = node.continuation.definition; | 559 Continuation cont = node.continuation; |
| 560 | 560 |
| 561 // During the strong loop phase, there is no need to compute monotonicity, | 561 // During the strong loop phase, there is no need to compute monotonicity, |
| 562 // and we already put bounds on the loop variables when we went into the | 562 // and we already put bounds on the loop variables when we went into the |
| 563 // loop. | 563 // loop. |
| 564 if (isStrongLoopPass) return; | 564 if (isStrongLoopPass) return; |
| 565 | 565 |
| 566 // For each loop parameter, try to prove that the new value is definitely | 566 // For each loop parameter, try to prove that the new value is definitely |
| 567 // less/greater than its old value. When we fail to prove this, update the | 567 // less/greater than its old value. When we fail to prove this, update the |
| 568 // monotonicity flag accordingly. | 568 // monotonicity flag accordingly. |
| 569 for (int i = 0; i < node.arguments.length; ++i) { | 569 for (int i = 0; i < node.argumentRefs.length; ++i) { |
| 570 Parameter param = cont.parameters[i]; | 570 Parameter param = cont.parameters[i]; |
| 571 if (!isInt(param)) continue; | 571 if (!isInt(param)) continue; |
| 572 SignedVariable arg = getValue(node.arguments[i].definition); | 572 SignedVariable arg = getValue(node.argument(i)); |
| 573 SignedVariable paramVar = getValue(param); | 573 SignedVariable paramVar = getValue(param); |
| 574 if (!isDefinitelyLessThanOrEqualTo(arg, paramVar)) { | 574 if (!isDefinitelyLessThanOrEqualTo(arg, paramVar)) { |
| 575 // We couldn't prove that the value does not increase, so assume | 575 // We couldn't prove that the value does not increase, so assume |
| 576 // henceforth that it might be increasing. | 576 // henceforth that it might be increasing. |
| 577 markMonotonicity(cont.parameters[i], Monotonicity.Increasing); | 577 markMonotonicity(cont.parameters[i], Monotonicity.Increasing); |
| 578 } | 578 } |
| 579 if (!isDefinitelyGreaterThanOrEqualTo(arg, paramVar)) { | 579 if (!isDefinitelyGreaterThanOrEqualTo(arg, paramVar)) { |
| 580 // We couldn't prove that the value does not decrease, so assume | 580 // We couldn't prove that the value does not decrease, so assume |
| 581 // henceforth that it might be decreasing. | 581 // henceforth that it might be decreasing. |
| 582 markMonotonicity(cont.parameters[i], Monotonicity.Decreasing); | 582 markMonotonicity(cont.parameters[i], Monotonicity.Decreasing); |
| 583 } | 583 } |
| 584 } | 584 } |
| 585 } | 585 } |
| 586 | 586 |
| 587 void markMonotonicity(Parameter param, Monotonicity mono) { | 587 void markMonotonicity(Parameter param, Monotonicity mono) { |
| 588 Monotonicity current = monotonicity[param]; | 588 Monotonicity current = monotonicity[param]; |
| 589 if (current == null) { | 589 if (current == null) { |
| 590 monotonicity[param] = mono; | 590 monotonicity[param] = mono; |
| 591 } else if (current != mono) { | 591 } else if (current != mono) { |
| 592 monotonicity[param] = Monotonicity.NotMonotone; | 592 monotonicity[param] = Monotonicity.NotMonotone; |
| 593 } | 593 } |
| 594 } | 594 } |
| 595 | 595 |
| 596 @override | 596 @override |
| 597 void visitInvokeContinuation(InvokeContinuation node) { | 597 void visitInvokeContinuation(InvokeContinuation node) { |
| 598 Continuation cont = node.continuation.definition; | 598 Continuation cont = node.continuation; |
| 599 if (node.isRecursive) { | 599 if (node.isRecursive) { |
| 600 analyzeLoopContinue(node); | 600 analyzeLoopContinue(node); |
| 601 } else if (cont.isRecursive) { | 601 } else if (cont.isRecursive) { |
| 602 analyzeLoopEntry(node); | 602 analyzeLoopEntry(node); |
| 603 } else { | 603 } else { |
| 604 int effect = effectNumberAt[cont]; | 604 int effect = effectNumberAt[cont]; |
| 605 if (effect == null) { | 605 if (effect == null) { |
| 606 effectNumberAt[cont] = currentEffectNumber; | 606 effectNumberAt[cont] = currentEffectNumber; |
| 607 } else if (effect != currentEffectNumber && effect != NEW_EFFECT) { | 607 } else if (effect != currentEffectNumber && effect != NEW_EFFECT) { |
| 608 effectNumberAt[cont] = NEW_EFFECT; | 608 effectNumberAt[cont] = NEW_EFFECT; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 634 TypeMask successType = | 634 TypeMask successType = |
| 635 types.receiverTypeFor(node.selector, node.dartReceiver.type); | 635 types.receiverTypeFor(node.selector, node.dartReceiver.type); |
| 636 if (types.isDefinitelyIndexable(successType)) { | 636 if (types.isDefinitelyIndexable(successType)) { |
| 637 valueOf[node] = getLength(node.dartReceiver, currentEffectNumber); | 637 valueOf[node] = getLength(node.dartReceiver, currentEffectNumber); |
| 638 } | 638 } |
| 639 } | 639 } |
| 640 } | 640 } |
| 641 | 641 |
| 642 @override | 642 @override |
| 643 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | 643 void visitApplyBuiltinMethod(ApplyBuiltinMethod node) { |
| 644 Primitive receiver = node.receiver.definition; | 644 Primitive receiver = node.receiver; |
| 645 int effectBefore = currentEffectNumber; | 645 int effectBefore = currentEffectNumber; |
| 646 currentEffectNumber = makeNewEffect(); | 646 currentEffectNumber = makeNewEffect(); |
| 647 int effectAfter = currentEffectNumber; | 647 int effectAfter = currentEffectNumber; |
| 648 SignedVariable lengthBefore = getLength(receiver, effectBefore); | 648 SignedVariable lengthBefore = getLength(receiver, effectBefore); |
| 649 SignedVariable lengthAfter = getLength(receiver, effectAfter); | 649 SignedVariable lengthAfter = getLength(receiver, effectAfter); |
| 650 switch (node.method) { | 650 switch (node.method) { |
| 651 case BuiltinMethod.Push: | 651 case BuiltinMethod.Push: |
| 652 // after = before + count | 652 // after = before + count |
| 653 int count = node.arguments.length; | 653 int count = node.argumentRefs.length; |
| 654 makeExactSum(lengthAfter, lengthBefore, count); | 654 makeExactSum(lengthAfter, lengthBefore, count); |
| 655 break; | 655 break; |
| 656 | 656 |
| 657 case BuiltinMethod.Pop: | 657 case BuiltinMethod.Pop: |
| 658 // after = before - 1 | 658 // after = before - 1 |
| 659 makeExactSum(lengthAfter, lengthBefore, -1); | 659 makeExactSum(lengthAfter, lengthBefore, -1); |
| 660 break; | 660 break; |
| 661 | 661 |
| 662 case BuiltinMethod.SetLength: | 662 case BuiltinMethod.SetLength: |
| 663 makeEqual(lengthAfter, getValue(node.arguments[0].definition)); | 663 makeEqual(lengthAfter, getValue(node.argument(0))); |
| 664 break; | 664 break; |
| 665 } | 665 } |
| 666 } | 666 } |
| 667 | 667 |
| 668 @override | 668 @override |
| 669 void visitLiteralList(LiteralList node) { | 669 void visitLiteralList(LiteralList node) { |
| 670 makeConstant(getLength(node, currentEffectNumber), node.values.length); | 670 makeConstant(getLength(node, currentEffectNumber), node.valueRefs.length); |
| 671 } | 671 } |
| 672 | 672 |
| 673 // ---------------- INTERIOR EXPRESSIONS -------------------- | 673 // ---------------- INTERIOR EXPRESSIONS -------------------- |
| 674 | 674 |
| 675 @override | 675 @override |
| 676 Expression traverseContinuation(Continuation cont) { | 676 Expression traverseContinuation(Continuation cont) { |
| 677 if (octagon.isUnsolvable) { | 677 if (octagon.isUnsolvable) { |
| 678 destroyAndReplace(cont.body, new Unreachable()); | 678 destroyAndReplace(cont.body, new Unreachable()); |
| 679 } else { | 679 } else { |
| 680 int effect = effectNumberAt[cont]; | 680 int effect = effectNumberAt[cont]; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 699 } | 699 } |
| 700 return node.body; | 700 return node.body; |
| 701 } | 701 } |
| 702 } | 702 } |
| 703 | 703 |
| 704 /// Lattice representing the known (weak) monotonicity of a loop variable. | 704 /// Lattice representing the known (weak) monotonicity of a loop variable. |
| 705 /// | 705 /// |
| 706 /// The lattice bottom is represented by `null` and represents the case where | 706 /// The lattice bottom is represented by `null` and represents the case where |
| 707 /// the loop variable never changes value during the loop. | 707 /// the loop variable never changes value during the loop. |
| 708 enum Monotonicity { NotMonotone, Increasing, Decreasing, } | 708 enum Monotonicity { NotMonotone, Increasing, Decreasing, } |
| OLD | NEW |