| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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 part of dart2js.optimizers; | 5 part of dart2js.optimizers; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Propagates constants throughout the IR, and replaces branches with fixed | 8 * Propagates constants throughout the IR, and replaces branches with fixed |
| 9 * jumps as well as side-effect free expressions with known constant results. | 9 * jumps as well as side-effect free expressions with known constant results. |
| 10 * Should be followed by the [ShrinkingReducer] pass. | 10 * Should be followed by the [ShrinkingReducer] pass. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 void unlink()) { | 70 void unlink()) { |
| 71 _ConstnessLattice cell = node2value[node]; | 71 _ConstnessLattice cell = node2value[node]; |
| 72 if (cell == null || !cell.isConstant) { | 72 if (cell == null || !cell.isConstant) { |
| 73 return null; | 73 return null; |
| 74 } | 74 } |
| 75 | 75 |
| 76 assert(continuation.parameters.length == 1); | 76 assert(continuation.parameters.length == 1); |
| 77 | 77 |
| 78 // Set up the replacement structure. | 78 // Set up the replacement structure. |
| 79 | 79 |
| 80 values.PrimitiveConstant primitiveConstant = cell.constant; | 80 PrimitiveConstantValue primitiveConstant = cell.constant; |
| 81 ConstExp constExp = new PrimitiveConstExp(primitiveConstant); | 81 ConstantExpression constExp = |
| 82 new PrimitiveConstantExpression(primitiveConstant); |
| 82 Constant constant = new Constant(constExp); | 83 Constant constant = new Constant(constExp); |
| 83 LetPrim letPrim = new LetPrim(constant); | 84 LetPrim letPrim = new LetPrim(constant); |
| 84 InvokeContinuation invoke = | 85 InvokeContinuation invoke = |
| 85 new InvokeContinuation(continuation, <Definition>[constant]); | 86 new InvokeContinuation(continuation, <Definition>[constant]); |
| 86 | 87 |
| 87 invoke.parent = constant.parent = letPrim; | 88 invoke.parent = constant.parent = letPrim; |
| 88 letPrim.body = invoke; | 89 letPrim.body = invoke; |
| 89 | 90 |
| 90 // Replace the method invocation. | 91 // Replace the method invocation. |
| 91 | 92 |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 } else if (lhs.isNonConst) { | 362 } else if (lhs.isNonConst) { |
| 362 setValues(_ConstnessLattice.NonConst); | 363 setValues(_ConstnessLattice.NonConst); |
| 363 return; | 364 return; |
| 364 } else if (!node.selector.isOperator) { | 365 } else if (!node.selector.isOperator) { |
| 365 // TODO(jgruber): Handle known methods on constants such as String.length. | 366 // TODO(jgruber): Handle known methods on constants such as String.length. |
| 366 setValues(_ConstnessLattice.NonConst); | 367 setValues(_ConstnessLattice.NonConst); |
| 367 return; | 368 return; |
| 368 } | 369 } |
| 369 | 370 |
| 370 // Calculate the resulting constant if possible. | 371 // Calculate the resulting constant if possible. |
| 371 values.Constant result; | 372 ConstantValue result; |
| 372 String opname = node.selector.name; | 373 String opname = node.selector.name; |
| 373 if (node.selector.argumentCount == 0) { | 374 if (node.selector.argumentCount == 0) { |
| 374 // Unary operator. | 375 // Unary operator. |
| 375 | 376 |
| 376 if (opname == "unary-") { | 377 if (opname == "unary-") { |
| 377 opname = "-"; | 378 opname = "-"; |
| 378 } | 379 } |
| 379 dart2js.UnaryOperation operation = constantSystem.lookupUnary(opname); | 380 dart2js.UnaryOperation operation = constantSystem.lookupUnary(opname); |
| 380 if (operation != null) { | 381 if (operation != null) { |
| 381 result = operation.fold(lhs.constant); | 382 result = operation.fold(lhs.constant); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 } | 439 } |
| 439 Constant constant = ref.definition; | 440 Constant constant = ref.definition; |
| 440 return constant != null && constant.value.isString; | 441 return constant != null && constant.value.isString; |
| 441 }); | 442 }); |
| 442 | 443 |
| 443 assert(cont.parameters.length == 1); | 444 assert(cont.parameters.length == 1); |
| 444 if (allStringConstants) { | 445 if (allStringConstants) { |
| 445 // All constant, we can concatenate ourselves. | 446 // All constant, we can concatenate ourselves. |
| 446 Iterable<String> allStrings = node.arguments.map((Reference ref) { | 447 Iterable<String> allStrings = node.arguments.map((Reference ref) { |
| 447 Constant constant = ref.definition; | 448 Constant constant = ref.definition; |
| 448 values.StringConstant stringConstant = constant.value; | 449 StringConstantValue stringConstant = constant.value; |
| 449 return stringConstant.value.slowToString(); | 450 return stringConstant.primitiveValue.slowToString(); |
| 450 }); | 451 }); |
| 451 LiteralDartString dartString = new LiteralDartString(allStrings.join()); | 452 LiteralDartString dartString = new LiteralDartString(allStrings.join()); |
| 452 values.Constant constant = new values.StringConstant(dartString); | 453 ConstantValue constant = new StringConstantValue(dartString); |
| 453 setValues(new _ConstnessLattice(constant)); | 454 setValues(new _ConstnessLattice(constant)); |
| 454 } else { | 455 } else { |
| 455 setValues(_ConstnessLattice.NonConst); | 456 setValues(_ConstnessLattice.NonConst); |
| 456 } | 457 } |
| 457 } | 458 } |
| 458 | 459 |
| 459 void visitBranch(Branch node) { | 460 void visitBranch(Branch node) { |
| 460 IsTrue isTrue = node.condition; | 461 IsTrue isTrue = node.condition; |
| 461 _ConstnessLattice conditionCell = getValue(isTrue.value.definition); | 462 _ConstnessLattice conditionCell = getValue(isTrue.value.definition); |
| 462 | 463 |
| 463 if (conditionCell.isUnknown) { | 464 if (conditionCell.isUnknown) { |
| 464 return; // And come back later. | 465 return; // And come back later. |
| 465 } else if (conditionCell.isNonConst) { | 466 } else if (conditionCell.isNonConst) { |
| 466 setReachable(node.trueContinuation.definition); | 467 setReachable(node.trueContinuation.definition); |
| 467 setReachable(node.falseContinuation.definition); | 468 setReachable(node.falseContinuation.definition); |
| 468 } else if (conditionCell.isConstant && | 469 } else if (conditionCell.isConstant && |
| 469 !(conditionCell.constant.isBool)) { | 470 !(conditionCell.constant.isBool)) { |
| 470 // Treat non-bool constants in condition as non-const since they result | 471 // Treat non-bool constants in condition as non-const since they result |
| 471 // in type errors in checked mode. | 472 // in type errors in checked mode. |
| 472 // TODO(jgruber): Default to false in unchecked mode. | 473 // TODO(jgruber): Default to false in unchecked mode. |
| 473 setReachable(node.trueContinuation.definition); | 474 setReachable(node.trueContinuation.definition); |
| 474 setReachable(node.falseContinuation.definition); | 475 setReachable(node.falseContinuation.definition); |
| 475 setValue(isTrue.value.definition, _ConstnessLattice.NonConst); | 476 setValue(isTrue.value.definition, _ConstnessLattice.NonConst); |
| 476 } else if (conditionCell.isConstant && | 477 } else if (conditionCell.isConstant && |
| 477 conditionCell.constant.isBool) { | 478 conditionCell.constant.isBool) { |
| 478 values.BoolConstant boolConstant = conditionCell.constant; | 479 BoolConstantValue boolConstant = conditionCell.constant; |
| 479 setReachable((boolConstant.isTrue) ? | 480 setReachable((boolConstant.isTrue) ? |
| 480 node.trueContinuation.definition : node.falseContinuation.definition); | 481 node.trueContinuation.definition : node.falseContinuation.definition); |
| 481 } | 482 } |
| 482 } | 483 } |
| 483 | 484 |
| 484 void visitTypeOperator(TypeOperator node) { | 485 void visitTypeOperator(TypeOperator node) { |
| 485 Continuation cont = node.continuation.definition; | 486 Continuation cont = node.continuation.definition; |
| 486 setReachable(cont); | 487 setReachable(cont); |
| 487 | 488 |
| 488 void setValues(_ConstnessLattice updateValue) { | 489 void setValues(_ConstnessLattice updateValue) { |
| 489 setValue(node, updateValue); | 490 setValue(node, updateValue); |
| 490 Parameter returnValue = cont.parameters[0]; | 491 Parameter returnValue = cont.parameters[0]; |
| 491 setValue(returnValue, updateValue); | 492 setValue(returnValue, updateValue); |
| 492 } | 493 } |
| 493 | 494 |
| 494 if (node.operator != "is") { | 495 if (node.operator != "is") { |
| 495 // TODO(jgruber): Add support for `as` casts. | 496 // TODO(jgruber): Add support for `as` casts. |
| 496 setValues(_ConstnessLattice.NonConst); | 497 setValues(_ConstnessLattice.NonConst); |
| 497 } | 498 } |
| 498 | 499 |
| 499 _ConstnessLattice cell = getValue(node.receiver.definition); | 500 _ConstnessLattice cell = getValue(node.receiver.definition); |
| 500 if (cell.isUnknown) { | 501 if (cell.isUnknown) { |
| 501 return; // And come back later. | 502 return; // And come back later. |
| 502 } else if (cell.isNonConst) { | 503 } else if (cell.isNonConst) { |
| 503 setValues(_ConstnessLattice.NonConst); | 504 setValues(_ConstnessLattice.NonConst); |
| 504 } else if (node.type.kind == types.TypeKind.INTERFACE) { | 505 } else if (node.type.kind == types.TypeKind.INTERFACE) { |
| 505 // Receiver is a constant, perform is-checks at compile-time. | 506 // Receiver is a constant, perform is-checks at compile-time. |
| 506 | 507 |
| 507 types.InterfaceType checkedType = node.type; | 508 types.InterfaceType checkedType = node.type; |
| 508 values.Constant constant = cell.constant; | 509 ConstantValue constant = cell.constant; |
| 509 types.DartType constantType = constant.computeType(compiler); | 510 types.DartType constantType = constant.computeType(compiler); |
| 510 | 511 |
| 511 _ConstnessLattice result = _ConstnessLattice.NonConst; | 512 _ConstnessLattice result = _ConstnessLattice.NonConst; |
| 512 if (constant.isNull && | 513 if (constant.isNull && |
| 513 checkedType.element != compiler.nullClass && | 514 checkedType.element != compiler.nullClass && |
| 514 checkedType.element != compiler.objectClass) { | 515 checkedType.element != compiler.objectClass) { |
| 515 // `(null is Type)` is true iff Type is in { Null, Object }. | 516 // `(null is Type)` is true iff Type is in { Null, Object }. |
| 516 result = new _ConstnessLattice(new values.FalseConstant()); | 517 result = new _ConstnessLattice(new FalseConstantValue()); |
| 517 } else { | 518 } else { |
| 518 // Otherwise, perform a standard subtype check. | 519 // Otherwise, perform a standard subtype check. |
| 519 result = new _ConstnessLattice( | 520 result = new _ConstnessLattice( |
| 520 constantSystem.isSubtype(compiler, constantType, checkedType) | 521 constantSystem.isSubtype(compiler, constantType, checkedType) |
| 521 ? new values.TrueConstant() | 522 ? new TrueConstantValue() |
| 522 : new values.FalseConstant()); | 523 : new FalseConstantValue()); |
| 523 } | 524 } |
| 524 | 525 |
| 525 setValues(result); | 526 setValues(result); |
| 526 } | 527 } |
| 527 } | 528 } |
| 528 | 529 |
| 529 void visitSetClosureVariable(SetClosureVariable node) { | 530 void visitSetClosureVariable(SetClosureVariable node) { |
| 530 setReachable(node.body); | 531 setReachable(node.body); |
| 531 } | 532 } |
| 532 | 533 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 555 void visitThis(This node) { | 556 void visitThis(This node) { |
| 556 setValue(node, _ConstnessLattice.NonConst); | 557 setValue(node, _ConstnessLattice.NonConst); |
| 557 } | 558 } |
| 558 | 559 |
| 559 void visitReifyTypeVar(ReifyTypeVar node) { | 560 void visitReifyTypeVar(ReifyTypeVar node) { |
| 560 setValue(node, _ConstnessLattice.NonConst); | 561 setValue(node, _ConstnessLattice.NonConst); |
| 561 } | 562 } |
| 562 | 563 |
| 563 void visitCreateFunction(CreateFunction node) { | 564 void visitCreateFunction(CreateFunction node) { |
| 564 setReachable(node.definition); | 565 setReachable(node.definition); |
| 565 values.Constant constant = | 566 ConstantValue constant = |
| 566 new values.FunctionConstant(node.definition.element); | 567 new FunctionConstantValue(node.definition.element); |
| 567 setValue(node, new _ConstnessLattice(constant)); | 568 setValue(node, new _ConstnessLattice(constant)); |
| 568 } | 569 } |
| 569 | 570 |
| 570 void visitGetClosureVariable(GetClosureVariable node) { | 571 void visitGetClosureVariable(GetClosureVariable node) { |
| 571 setValue(node, _ConstnessLattice.NonConst); | 572 setValue(node, _ConstnessLattice.NonConst); |
| 572 } | 573 } |
| 573 | 574 |
| 574 void visitParameter(Parameter node) { | 575 void visitParameter(Parameter node) { |
| 575 if (node.parent is FunctionDefinition) { | 576 if (node.parent is FunctionDefinition) { |
| 576 // Functions may escape and thus their parameters must be initialized to | 577 // Functions may escape and thus their parameters must be initialized to |
| (...skipping 30 matching lines...) Expand all Loading... |
| 607 /// Represents the constant-state of a variable at some point in the program. | 608 /// Represents the constant-state of a variable at some point in the program. |
| 608 /// UNKNOWN: may be some as yet undetermined constant. | 609 /// UNKNOWN: may be some as yet undetermined constant. |
| 609 /// CONSTANT: is a constant as stored in the local field. | 610 /// CONSTANT: is a constant as stored in the local field. |
| 610 /// NONCONST: not a constant. | 611 /// NONCONST: not a constant. |
| 611 class _ConstnessLattice { | 612 class _ConstnessLattice { |
| 612 static const int UNKNOWN = 0; | 613 static const int UNKNOWN = 0; |
| 613 static const int CONSTANT = 1; | 614 static const int CONSTANT = 1; |
| 614 static const int NONCONST = 2; | 615 static const int NONCONST = 2; |
| 615 | 616 |
| 616 final int kind; | 617 final int kind; |
| 617 final values.Constant constant; | 618 final ConstantValue constant; |
| 618 | 619 |
| 619 static final _ConstnessLattice Unknown = | 620 static final _ConstnessLattice Unknown = |
| 620 new _ConstnessLattice._internal(UNKNOWN, null); | 621 new _ConstnessLattice._internal(UNKNOWN, null); |
| 621 static final _ConstnessLattice NonConst = | 622 static final _ConstnessLattice NonConst = |
| 622 new _ConstnessLattice._internal(NONCONST, null); | 623 new _ConstnessLattice._internal(NONCONST, null); |
| 623 | 624 |
| 624 _ConstnessLattice._internal(this.kind, this.constant); | 625 _ConstnessLattice._internal(this.kind, this.constant); |
| 625 _ConstnessLattice(this.constant) : kind = CONSTANT { | 626 _ConstnessLattice(this.constant) : kind = CONSTANT { |
| 626 assert(this.constant != null); | 627 assert(this.constant != null); |
| 627 } | 628 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 656 return that; | 657 return that; |
| 657 } | 658 } |
| 658 | 659 |
| 659 if (this.constant == that.constant) { | 660 if (this.constant == that.constant) { |
| 660 return this; | 661 return this; |
| 661 } | 662 } |
| 662 | 663 |
| 663 return NonConst; | 664 return NonConst; |
| 664 } | 665 } |
| 665 } | 666 } |
| OLD | NEW |