| Index: dart/frog/leg/ssa/nodes.dart
|
| diff --git a/dart/frog/leg/ssa/nodes.dart b/dart/frog/leg/ssa/nodes.dart
|
| index 8e26719839a1240e2fef65639c8add0630cb46fe..46d41d90c791730693aca423a9bb85f79e8a383a 100644
|
| --- a/dart/frog/leg/ssa/nodes.dart
|
| +++ b/dart/frog/leg/ssa/nodes.dart
|
| @@ -12,7 +12,6 @@ interface HVisitor<R> {
|
| R visitBoolify(HBoolify node);
|
| R visitBoundsCheck(HBoundsCheck node);
|
| R visitBreak(HBreak node);
|
| - R visitConstant(HConstant node);
|
| R visitDivide(HDivide node);
|
| R visitEquals(HEquals node);
|
| R visitExit(HExit node);
|
| @@ -38,6 +37,7 @@ interface HVisitor<R> {
|
| R visitIs(HIs node);
|
| R visitLess(HLess node);
|
| R visitLessEqual(HLessEqual node);
|
| + R visitLiteral(HLiteral node);
|
| R visitLiteralList(HLiteralList node);
|
| R visitLoad(HLoad node);
|
| R visitLocal(HLocal node);
|
| @@ -116,13 +116,19 @@ class HGraph {
|
| HBasicBlock exit;
|
| final List<HBasicBlock> blocks;
|
|
|
| - // We canonicalize all constants used within a graph so we do not
|
| + // We canonicalize all literals used within a graph so we do not
|
| // have to worry about them for global value numbering.
|
| - Map<Constant, HConstant> constants;
|
| -
|
| - HGraph()
|
| - : blocks = new List<HBasicBlock>(),
|
| - constants = new Map<Constant, HConstant>() {
|
| + HLiteral nullLiteral;
|
| + HLiteral trueLiteral;
|
| + HLiteral falseLiteral;
|
| + HLiteral nanLiteral;
|
| + HLiteral negativeZeroLiteral;
|
| + Map<int, HLiteral> intLiterals;
|
| + Map<double, HLiteral> doubleLiterals;
|
| + Map<num, HLiteral> numLiterals;
|
| + Map<String, HLiteral> stringLiterals;
|
| +
|
| + HGraph() : blocks = new List<HBasicBlock>() {
|
| entry = addNewBlock();
|
| // The exit block will be added later, so it has an id that is
|
| // after all others in the system.
|
| @@ -148,45 +154,106 @@ class HGraph {
|
| return result;
|
| }
|
|
|
| - static HType mapConstantTypeToSsaType(Constant constant) {
|
| - if (constant.isNull()) return HType.UNKNOWN;
|
| - if (constant.isBool()) return HType.BOOLEAN;
|
| - if (constant.isInt()) return HType.INTEGER;
|
| - if (constant.isDouble()) return HType.DOUBLE;
|
| - if (constant.isString()) return HType.STRING;
|
| - if (constant.isList()) return HType.ARRAY;
|
| - return HType.UNKNOWN;
|
| + HLiteral addNewLiteralInt(int value) {
|
| + if (intLiterals === null) intLiterals = new Map<int, HLiteral>();
|
| + HLiteral result = intLiterals[value];
|
| + if (result === null) {
|
| + result = new HLiteral.internal(value, HType.INTEGER);
|
| + entry.addAtExit(result);
|
| + intLiterals[value] = result;
|
| + }
|
| + return result;
|
| }
|
|
|
| - HConstant addConstant(Constant constant) {
|
| - HConstant result = constants[constant];
|
| + HLiteral addNewLiteralNaN() {
|
| + if (nanLiteral === null) {
|
| + nanLiteral = new HLiteral.internal(double.NAN, HType.DOUBLE);
|
| + entry.addAtExit(nanLiteral);
|
| + }
|
| + return nanLiteral;
|
| + }
|
| +
|
| + HLiteral addNewNegativeZeroLiteral() {
|
| + if (negativeZeroLiteral === null) {
|
| + negativeZeroLiteral = new HLiteral.internal(-0.0, HType.DOUBLE);
|
| + entry.addAtExit(negativeZeroLiteral);
|
| + }
|
| + return negativeZeroLiteral;
|
| + }
|
| +
|
| + HLiteral addNewLiteralDouble(double value) {
|
| + if (value.isNaN()) return addNewLiteralNaN(); // Avoid hashing NaN.
|
| + if (value == 0 && value.isNegative()) {
|
| + // Avoid hashing -0.0 as it compares equal to 0.0.
|
| + return addNewNegativeZeroLiteral();
|
| + }
|
| + if (doubleLiterals === null) doubleLiterals = new Map<double, HLiteral>();
|
| + HLiteral result = doubleLiterals[value];
|
| if (result === null) {
|
| - HType type = mapConstantTypeToSsaType(constant);
|
| - result = new HConstant.internal(constant, type);
|
| + result = new HLiteral.internal(value, HType.DOUBLE);
|
| entry.addAtExit(result);
|
| - constants[constant] = result;
|
| + doubleLiterals[value] = result;
|
| }
|
| return result;
|
| }
|
|
|
| - HConstant addConstantInt(int i) {
|
| - return addConstant(new IntConstant(i));
|
| + HLiteral addNewLiteralNum(num value, HType type) {
|
| + // If we've propagated type information then the type must be a
|
| + // number or in conflict, but when we turn off speculative
|
| + // optimization the type may be unknown. In any case, we make it a
|
| + // number from this point forward.
|
| + assert(type.isUnknown() || type.isConflicting() || type.isNumber());
|
| + if (type.isInteger()) return addNewLiteralInt(value);
|
| + if (type.isDouble() || value.isNaN()) return addNewLiteralDouble(value);
|
| + // Probe our literals map and add a new number literal if necessary.
|
| + if (numLiterals === null) numLiterals = new Map<num, HLiteral>();
|
| + HLiteral result = numLiterals[value];
|
| + if (result === null) {
|
| + result = new HLiteral.internal(value, HType.NUMBER);
|
| + entry.addAtExit(result);
|
| + numLiterals[value] = result;
|
| + }
|
| + return result;
|
| }
|
|
|
| - HConstant addConstantDouble(int d) {
|
| - return addConstant(new DoubleConstant(d));
|
| + HLiteral addNewLiteralTrue() {
|
| + if (trueLiteral === null) {
|
| + trueLiteral = new HLiteral.internal(true, HType.BOOLEAN);
|
| + entry.addAtExit(trueLiteral);
|
| + }
|
| + return trueLiteral;
|
| + }
|
| +
|
| + HLiteral addNewLiteralFalse() {
|
| + if (falseLiteral === null) {
|
| + falseLiteral = new HLiteral.internal(false, HType.BOOLEAN);
|
| + entry.addAtExit(falseLiteral);
|
| + }
|
| + return falseLiteral;
|
| }
|
|
|
| - HConstant addConstantString(DartString str) {
|
| - return addConstant(new StringConstant(str));
|
| + HLiteral addNewLiteralBool(bool value) {
|
| + return value ? addNewLiteralTrue() : addNewLiteralFalse();
|
| }
|
|
|
| - HConstant addConstantBool(bool value) {
|
| - return addConstant(new BoolConstant(value));
|
| + HLiteral addNewLiteralString(DartString value) {
|
| + if (stringLiterals === null) stringLiterals = new Map<String, HLiteral>();
|
| + String key = value.toString(); // We need something hashable.
|
| + HLiteral result = stringLiterals[key];
|
| + if (result === null) {
|
| + result = new HLiteral.internal(value, HType.STRING);
|
| + entry.addAtExit(result);
|
| + stringLiterals[key] = result;
|
| + }
|
| + return result;
|
| }
|
|
|
| - HConstant addConstantNull() {
|
| - return addConstant(const NullConstant());
|
| + HLiteral addNewLiteralNull() {
|
| + if (nullLiteral === null) {
|
| + nullLiteral = new HLiteral.internal(null, HType.UNKNOWN);
|
| + entry.addAtExit(nullLiteral);
|
| + }
|
| + return nullLiteral;
|
| }
|
|
|
| void finalize() {
|
| @@ -257,7 +324,6 @@ class HBaseVisitor extends HGraphVisitor implements HVisitor {
|
| visitBoundsCheck(HBoundsCheck node) => visitCheck(node);
|
| visitBreak(HBreak node) => visitGoto(node);
|
| visitCheck(HCheck node) => visitInstruction(node);
|
| - visitConstant(HConstant node) => visitInstruction(node);
|
| visitDivide(HDivide node) => visitBinaryArithmetic(node);
|
| visitEquals(HEquals node) => visitRelational(node);
|
| visitExit(HExit node) => visitControlFlow(node);
|
| @@ -290,6 +356,7 @@ class HBaseVisitor extends HGraphVisitor implements HVisitor {
|
| visitLoad(HLoad node) => visitInstruction(node);
|
| visitLocal(HLocal node) => visitInstruction(node);
|
| visitLogicalOperator(HLogicalOperator node) => visitInstruction(node);
|
| + visitLiteral(HLiteral node) => visitInstruction(node);
|
| visitLiteralList(HLiteralList node) => visitInstruction(node);
|
| visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node);
|
| visitModulo(HModulo node) => visitBinaryArithmetic(node);
|
| @@ -950,9 +1017,9 @@ class HInstruction implements Hashable {
|
| assert(isValid());
|
| }
|
|
|
| - bool isConstantNull() => false;
|
| - bool isConstantNumber() => false;
|
| - bool isConstantString() => false;
|
| + bool isLiteralNull() => false;
|
| + bool isLiteralNumber() => false;
|
| + bool isLiteralString() => false;
|
|
|
| bool isValid() {
|
| HValidator validator = new HValidator();
|
| @@ -1214,10 +1281,10 @@ class HInvokeInterceptor extends HInvokeStatic {
|
| bool hasExpectedType() => builtinJsName != null;
|
|
|
| HInstruction fold(HGraph graph) {
|
| - if (name == const SourceString('length') && inputs[1].isConstantString()) {
|
| - HConstant input = inputs[1];
|
| - DartString string = input.constant.value;
|
| - return graph.addConstantInt(string.length);
|
| + if (name == const SourceString('length') && inputs[1].isLiteralString()) {
|
| + HLiteral input = inputs[1];
|
| + DartString string = input.value;
|
| + return graph.addNewLiteralInt(string.length);
|
| }
|
| return this;
|
| }
|
| @@ -1312,17 +1379,8 @@ class HInvokeBinary extends HInvokeStatic {
|
| return leftType.combine(rightType);
|
| }
|
|
|
| - HInstruction fold(HGraph graph) {
|
| - if (left is HConstant && right is HConstant) {
|
| - HConstant op1 = left;
|
| - HConstant op2 = right;
|
| - Constant folded =
|
| - op1.constant.binaryFold(operationAsString(), op2.constant);
|
| - if (folded !== null) return graph.addConstant(folded);
|
| - }
|
| - return this;
|
| - }
|
| - abstract String operationAsString();
|
| + abstract HInstruction fold(HGraph graph);
|
| + abstract evaluate(num a, num b);
|
| }
|
|
|
| class HBinaryArithmetic extends HInvokeBinary {
|
| @@ -1341,6 +1399,15 @@ class HBinaryArithmetic extends HInvokeBinary {
|
| }
|
| }
|
|
|
| + HInstruction fold(HGraph graph) {
|
| + if (left.isLiteralNumber() && right.isLiteralNumber()) {
|
| + HLiteral op1 = left;
|
| + HLiteral op2 = right;
|
| + return graph.addNewLiteralNum(evaluate(op1.value, op2.value), type);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| HType computeType() {
|
| HType type = computeInputsType();
|
| builtin = type.isNumber();
|
| @@ -1358,18 +1425,24 @@ class HBinaryArithmetic extends HInvokeBinary {
|
| }
|
|
|
| bool hasExpectedType() => builtin || type.isUnknown();
|
| +
|
| + abstract num evaluate(num a, num b);
|
| }
|
|
|
| class HAdd extends HBinaryArithmetic {
|
| HAdd(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitAdd(this);
|
| + num evaluate(num a, num b) => a + b;
|
| + int typeCode() => 5;
|
| + bool typeEquals(other) => other is HAdd;
|
| + bool dataEquals(HInstruction other) => true;
|
|
|
| HType computeType() {
|
| HType type = computeInputsType();
|
| builtin = (type.isNumber() || type.isString());
|
| if (type.isConflicting() && left.isString()) {
|
| - builtin = right is HConstant;
|
| + builtin = right is HLiteral;
|
| return HType.STRING;
|
| }
|
| if (!type.isUnknown()) return type;
|
| @@ -1391,30 +1464,24 @@ class HAdd extends HBinaryArithmetic {
|
| }
|
|
|
| HInstruction fold(HGraph graph) {
|
| - // TODO(floitsch): move this code to the compile-time-constant handler.
|
| - if (left.isConstantString() && right is HConstant) {
|
| - HConstant op1 = left;
|
| - HConstant op2 = right;
|
| - DartString leftString = op1.constant.value;
|
| + if (left.isLiteralString() && right is HLiteral) {
|
| + HLiteral op1 = left;
|
| + HLiteral op2 = right;
|
| + DartString leftString = op1.value;
|
| DartString otherString = null;
|
| - if (right.isConstantString()) {
|
| - otherString = op2.constant.value;
|
| + if (right.isLiteralString()) {
|
| + otherString = op2.value;
|
| } else {
|
| - assert(op2.isConstantNumber() ||
|
| - op2.isConstantBoolean() ||
|
| - op2.isConstantNull());
|
| - otherString = new DartString.literal(op2.constant.value.toString());
|
| + assert(op2.isLiteralNumber() ||
|
| + op2.isLiteralBoolean() ||
|
| + op2.isLiteralNull());
|
| + otherString = new DartString.literal(op2.value.toString());
|
| }
|
| DartString cons = new ConsDartString(leftString, otherString);
|
| - return graph.addConstantString(cons);
|
| + return graph.addNewLiteralString(cons);
|
| }
|
| return super.fold(graph);
|
| }
|
| -
|
| - String operationAsString() => "+";
|
| - int typeCode() => 5;
|
| - bool typeEquals(other) => other is HAdd;
|
| - bool dataEquals(HInstruction other) => true;
|
| }
|
|
|
| class HDivide extends HBinaryArithmetic {
|
| @@ -1429,7 +1496,7 @@ class HDivide extends HBinaryArithmetic {
|
| return HType.UNKNOWN;
|
| }
|
|
|
| - String operationAsString() => "/";
|
| + num evaluate(num a, num b) => a / b;
|
| int typeCode() => 6;
|
| bool typeEquals(other) => other is HDivide;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1439,8 +1506,7 @@ class HModulo extends HBinaryArithmetic {
|
| HModulo(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitModulo(this);
|
| -
|
| - String operationAsString() => "%";
|
| + num evaluate(num a, num b) => a % b;
|
| int typeCode() => 7;
|
| bool typeEquals(other) => other is HModulo;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1450,8 +1516,7 @@ class HMultiply extends HBinaryArithmetic {
|
| HMultiply(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitMultiply(this);
|
| -
|
| - String operationAsString() => "*";
|
| + num evaluate(num a, num b) => a * b;
|
| int typeCode() => 8;
|
| bool typeEquals(other) => other is HMultiply;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1461,8 +1526,7 @@ class HSubtract extends HBinaryArithmetic {
|
| HSubtract(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitSubtract(this);
|
| -
|
| - String operationAsString() => "-";
|
| + num evaluate(num a, num b) => a - b;
|
| int typeCode() => 9;
|
| bool typeEquals(other) => other is HSubtract;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1473,7 +1537,15 @@ class HTruncatingDivide extends HBinaryArithmetic {
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitTruncatingDivide(this);
|
|
|
| - String operationAsString() => "~/";
|
| + HInstruction fold(HGraph graph) {
|
| + // Avoid a DivisionByZeroException.
|
| + if (right.isLiteralNumber() && right.dynamic.value == 0) {
|
| + return this;
|
| + }
|
| + return super.fold(graph);
|
| + }
|
| +
|
| + num evaluate(num a, num b) => a ~/ b;
|
| int typeCode() => 10;
|
| bool typeEquals(other) => other is HTruncatingDivide;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1500,6 +1572,19 @@ class HBinaryBitOp extends HBinaryArithmetic {
|
| return HType.INTEGER;
|
| }
|
|
|
| + HInstruction fold(HGraph graph) {
|
| + // Bit-operations are only defined on integers.
|
| + if (left.isLiteralNumber() && right.isLiteralNumber()) {
|
| + HLiteral op1 = left;
|
| + HLiteral op2 = right;
|
| + // Avoid exceptions.
|
| + if (op1.isInteger() && op2.isInteger()) {
|
| + return graph.addNewLiteralInt(evaluate(op1.value, op2.value));
|
| + }
|
| + }
|
| + return this;
|
| + }
|
| +
|
| // TODO(floitsch): make class abstract instead of adding an abstract method.
|
| abstract accept(HVisitor visitor);
|
| }
|
| @@ -1509,7 +1594,19 @@ class HShiftLeft extends HBinaryBitOp {
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitShiftLeft(this);
|
|
|
| - String operationAsString() => "<<";
|
| + HInstruction fold(HGraph graph) {
|
| + if (right.isLiteralNumber()) {
|
| + // TODO(floitsch): find good max left-shift amount.
|
| + final int MAX_SHIFT_LEFT_AMOUNT = 50;
|
| + HLiteral op2 = right;
|
| + // Only positive shifting is allowed. Also guard against out-of-memory
|
| + // shifts.
|
| + if (op2.value < 0 || op2.value > MAX_SHIFT_LEFT_AMOUNT) return this;
|
| + }
|
| + return super.fold(graph);
|
| + }
|
| +
|
| + int evaluate(int a, int b) => a << b;
|
| int typeCode() => 11;
|
| bool typeEquals(other) => other is HShiftLeft;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1520,7 +1617,16 @@ class HShiftRight extends HBinaryBitOp {
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitShiftRight(this);
|
|
|
| - String operationAsString() => ">>";
|
| + HInstruction fold(HGraph graph) {
|
| + if (right.isLiteralNumber()) {
|
| + HLiteral op2 = right;
|
| + // Only positive shifting is allowed.
|
| + if (op2.value < 0) return this;
|
| + }
|
| + return super.fold(graph);
|
| + }
|
| +
|
| + int evaluate(int a, int b) => a >> b;
|
| int typeCode() => 12;
|
| bool typeEquals(other) => other is HShiftRight;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1531,7 +1637,7 @@ class HBitOr extends HBinaryBitOp {
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitBitOr(this);
|
|
|
| - String operationAsString() => "|";
|
| + int evaluate(int a, int b) => a | b;
|
| int typeCode() => 13;
|
| bool typeEquals(other) => other is HBitOr;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1542,7 +1648,7 @@ class HBitAnd extends HBinaryBitOp {
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitBitAnd(this);
|
|
|
| - String operationAsString() => "&";
|
| + int evaluate(int a, int b) => a & b;
|
| int typeCode() => 14;
|
| bool typeEquals(other) => other is HBitAnd;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1553,7 +1659,7 @@ class HBitXor extends HBinaryBitOp {
|
| : super(target, left, right);
|
| accept(HVisitor visitor) => visitor.visitBitXor(this);
|
|
|
| - String operationAsString() => "^";
|
| + int evaluate(int a, int b) => a ^ b;
|
| int typeCode() => 15;
|
| bool typeEquals(other) => other is HBitXor;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1593,23 +1699,24 @@ class HInvokeUnary extends HInvokeStatic {
|
|
|
| bool hasExpectedType() => builtin || (type.isUnknown());
|
|
|
| - HInstruction fold(HGraph graph) {
|
| - if (operand is HConstant) {
|
| - HConstant op = operand;
|
| - Constant folded = op.constant.unaryFold(operationAsString());
|
| - if (folded !== null) return graph.addConstant(folded);
|
| - }
|
| - return this;
|
| - }
|
| + abstract HInstruction fold(HGraph graph);
|
|
|
| - abstract String operationAsString();
|
| + abstract num evaluate(num a);
|
| }
|
|
|
| class HNegate extends HInvokeUnary {
|
| HNegate(HStatic target, HInstruction input) : super(target, input);
|
| accept(HVisitor visitor) => visitor.visitNegate(this);
|
|
|
| - String operationAsString() => "-";
|
| + HInstruction fold(HGraph graph) {
|
| + if (operand.isLiteralNumber()) {
|
| + HLiteral input = operand;
|
| + return graph.addNewLiteralNum(evaluate(input.value), type);
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + num evaluate(num a) => -a;
|
| int typeCode() => 16;
|
| bool typeEquals(other) => other is HNegate;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1632,7 +1739,17 @@ class HBitNot extends HInvokeUnary {
|
| return HType.INTEGER;
|
| }
|
|
|
| - String operationAsString() => "~";
|
| + HInstruction fold(HGraph graph) {
|
| + if (operand.isLiteralNumber()) {
|
| + HLiteral input = operand;
|
| + if (input.isInteger()) {
|
| + return graph.addNewLiteralInt(evaluate(input.value));
|
| + }
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + int evaluate(int a) => ~a;
|
| int typeCode() => 17;
|
| bool typeEquals(other) => other is HBitNot;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1705,9 +1822,9 @@ class HLoopBranch extends HConditionalBranch {
|
| }
|
| }
|
|
|
| -class HConstant extends HInstruction {
|
| - final Constant constant;
|
| - HConstant.internal(this.constant, HType type) : super(<HInstruction>[]) {
|
| +class HLiteral extends HInstruction {
|
| + final value;
|
| + HLiteral.internal(this.value, HType type) : super(<HInstruction>[]) {
|
| this.type = type;
|
| tryGenerateAtUseSite(); // Maybe avoid this if the literal is big?
|
| }
|
| @@ -1716,8 +1833,8 @@ class HConstant extends HInstruction {
|
| assert(!hasSideEffects());
|
| }
|
|
|
| - toString() => 'literal: $constant';
|
| - accept(HVisitor visitor) => visitor.visitConstant(this);
|
| + toString() => 'literal: $value';
|
| + accept(HVisitor visitor) => visitor.visitLiteral(this);
|
| HType computeType() => type;
|
|
|
| // Literals have the type they have. It can't be changed.
|
| @@ -1725,10 +1842,10 @@ class HConstant extends HInstruction {
|
|
|
| bool hasExpectedType() => true;
|
|
|
| - bool isConstantBoolean() => constant.isBool();
|
| - bool isConstantNull() => constant.isNull();
|
| - bool isConstantNumber() => constant.isNum();
|
| - bool isConstantString() => constant.isString();
|
| + bool isLiteralBoolean() => value is bool;
|
| + bool isLiteralNull() => value === null;
|
| + bool isLiteralNumber() => value is num;
|
| + bool isLiteralString() => value is DartString;
|
| }
|
|
|
| class HNot extends HInstruction {
|
| @@ -1867,6 +1984,15 @@ class HRelational extends HInvokeBinary {
|
| }
|
| }
|
|
|
| + HInstruction fold(HGraph graph) {
|
| + if (left.isLiteralNumber() && right.isLiteralNumber()) {
|
| + HLiteral op1 = left;
|
| + HLiteral op2 = right;
|
| + return graph.addNewLiteralBool(evaluate(op1.value, op2.value));
|
| + }
|
| + return this;
|
| + }
|
| +
|
| HType computeType() {
|
| builtin = computeInputsType().isNumber();
|
| return HType.BOOLEAN;
|
| @@ -1883,15 +2009,21 @@ class HRelational extends HInvokeBinary {
|
| // A HRelational goes through the builtin operator or the top level
|
| // element. Therefore, it always has the expected type.
|
| bool hasExpectedType() => true;
|
| +
|
| + abstract bool evaluate(num a, num b);
|
| }
|
|
|
| class HEquals extends HRelational {
|
| HEquals(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| + bool evaluate(num a, num b) => a == b;
|
| accept(HVisitor visitor) => visitor.visitEquals(this);
|
| + int typeCode() => 19;
|
| + bool typeEquals(other) => other is HEquals;
|
| + bool dataEquals(HInstruction other) => true;
|
|
|
| HType computeType() {
|
| - builtin = computeInputsType().isNumber() || (left is HConstant);
|
| + builtin = computeInputsType().isNumber() || (left is HLiteral);
|
| return HType.BOOLEAN;
|
| }
|
|
|
| @@ -1901,17 +2033,16 @@ class HEquals extends HRelational {
|
| if (left.isNumber() || right.isNumber()) return HType.NUMBER;
|
| return HType.UNKNOWN;
|
| }
|
| -
|
| - String operationAsString() => "==";
|
| - int typeCode() => 19;
|
| - bool typeEquals(other) => other is HEquals;
|
| - bool dataEquals(HInstruction other) => true;
|
| }
|
|
|
| class HIdentity extends HRelational {
|
| HIdentity(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| + bool evaluate(num a, num b) => a === b;
|
| accept(HVisitor visitor) => visitor.visitIdentity(this);
|
| + int typeCode() => 20;
|
| + bool typeEquals(other) => other is HIdentity;
|
| + bool dataEquals(HInstruction other) => true;
|
|
|
| HType computeType() {
|
| builtin = true;
|
| @@ -1921,19 +2052,13 @@ class HIdentity extends HRelational {
|
| bool hasExpectedType() => true;
|
|
|
| HType computeDesiredInputType(HInstruction input) => HType.UNKNOWN;
|
| -
|
| - String operationAsString() => "===";
|
| - int typeCode() => 20;
|
| - bool typeEquals(other) => other is HIdentity;
|
| - bool dataEquals(HInstruction other) => true;
|
| }
|
|
|
| class HGreater extends HRelational {
|
| HGreater(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| + bool evaluate(num a, num b) => a > b;
|
| accept(HVisitor visitor) => visitor.visitGreater(this);
|
| -
|
| - String operationAsString() => ">";
|
| int typeCode() => 21;
|
| bool typeEquals(other) => other is HGreater;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1942,9 +2067,8 @@ class HGreater extends HRelational {
|
| class HGreaterEqual extends HRelational {
|
| HGreaterEqual(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| + bool evaluate(num a, num b) => a >= b;
|
| accept(HVisitor visitor) => visitor.visitGreaterEqual(this);
|
| -
|
| - String operationAsString() => ">=";
|
| int typeCode() => 22;
|
| bool typeEquals(other) => other is HGreaterEqual;
|
| bool dataEquals(HInstruction other) => true;
|
| @@ -1953,10 +2077,8 @@ class HGreaterEqual extends HRelational {
|
| class HLess extends HRelational {
|
| HLess(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| + bool evaluate(num a, num b) => a < b;
|
| accept(HVisitor visitor) => visitor.visitLess(this);
|
| -
|
| - String operationAsString() => "<";
|
| - int typeCode() => 23;
|
| bool typeEquals(other) => other is HLess;
|
| bool dataEquals(HInstruction other) => true;
|
| }
|
| @@ -1964,10 +2086,9 @@ class HLess extends HRelational {
|
| class HLessEqual extends HRelational {
|
| HLessEqual(HStatic target, HInstruction left, HInstruction right)
|
| : super(target, left, right);
|
| + bool evaluate(num a, num b) => a <= b;
|
| accept(HVisitor visitor) => visitor.visitLessEqual(this);
|
| -
|
| - String operationAsString() => "<=";
|
| - int typeCode() => 24;
|
| + int typeCode() => 23;
|
| bool typeEquals(other) => other is HLessEqual;
|
| bool dataEquals(HInstruction other) => true;
|
| }
|
| @@ -2000,7 +2121,7 @@ class HStatic extends HInstruction {
|
| accept(HVisitor visitor) => visitor.visitStatic(this);
|
|
|
| int gvnHashCode() => super.gvnHashCode() ^ element.hashCode();
|
| - int typeCode() => 25;
|
| + int typeCode() => 24;
|
| bool typeEquals(other) => other is HStatic;
|
| bool dataEquals(HStatic other) => element == other.element;
|
| }
|
| @@ -2011,7 +2132,7 @@ class HStaticStore extends HInstruction {
|
| toString() => 'static store ${element.name}';
|
| accept(HVisitor visitor) => visitor.visitStaticStore(this);
|
|
|
| - int typeCode() => 26;
|
| + int typeCode() => 25;
|
| bool typeEquals(other) => other is HStaticStore;
|
| bool dataEquals(HStaticStore other) => element == other.element;
|
| }
|
|
|