From 0d63cef35bb034fe122ddb3bb3d58b8c6ebf99ee Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Thu, 21 Feb 2013 11:40:37 +0000 Subject: [PATCH] Constant fold math and string operations. R=jkummerow@chromium.org BUG= Review URL: https://chromiumcodereview.appspot.com/12315005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13705 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/assembler.cc | 15 ++ src/assembler.h | 1 + src/flag-definitions.h | 1 + src/hydrogen-instructions.cc | 229 ++++++++++++++++++++----- src/hydrogen-instructions.h | 334 ++++++++++++++++++++----------------- src/hydrogen.cc | 146 ++++++++-------- src/hydrogen.h | 6 +- src/runtime.cc | 14 +- test/mjsunit/constant-folding-2.js | 258 ++++++++++++++++++++++++++++ tools/run-tests.py | 6 +- tools/test.py | 6 +- 11 files changed, 741 insertions(+), 275 deletions(-) create mode 100644 test/mjsunit/constant-folding-2.js diff --git a/src/assembler.cc b/src/assembler.cc index c92c248..fdb6399 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -1398,6 +1398,21 @@ ExternalReference ExternalReference::ForDeoptEntry(Address entry) { } +double power_helper(double x, double y) { + int y_int = static_cast(y); + if (y == y_int) { + return power_double_int(x, y_int); // Returns 1 if exponent is 0. + } + if (y == 0.5) { + return (isinf(x)) ? V8_INFINITY : fast_sqrt(x + 0.0); // Convert -0 to +0. + } + if (y == -0.5) { + return (isinf(x)) ? 0 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0. + } + return power_double_double(x, y); +} + + // Helper function to compute x^y, where y is known to be an // integer. Uses binary decomposition to limit the number of // multiplications; see the discussion in "Hacker's Delight" by Henry diff --git a/src/assembler.h b/src/assembler.h index 9e3c397..0b12375 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -968,6 +968,7 @@ inline int NumberOfBitsSet(uint32_t x) { bool EvalComparison(Token::Value op, double op1, double op2); // Computes pow(x, y) with the special cases in the spec for Math.pow. +double power_helper(double x, double y); double power_double_int(double x, int y); double power_double_double(double x, double y); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 9fd23f9..25978c5 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -213,6 +213,7 @@ DEFINE_bool(array_bounds_checks_elimination, true, DEFINE_bool(array_index_dehoisting, true, "perform array index dehoisting") DEFINE_bool(dead_code_elimination, true, "use dead code elimination") +DEFINE_bool(fold_constants, true, "use constant folding") DEFINE_bool(trace_dead_code_elimination, false, "trace dead code elimination") DEFINE_bool(unreachable_code_elimination, false, "eliminate unreachable code (hidden behind soft deopts)") diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index a99a04d..12ba829 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -27,6 +27,7 @@ #include "v8.h" +#include "double.h" #include "factory.h" #include "hydrogen.h" @@ -2784,22 +2785,22 @@ bool HStoreKeyed::NeedsCanonicalization() { #define H_CONSTANT_INT32(val) \ -new(zone) HConstant(val, Representation::Integer32()) +new(zone) HConstant(FACTORY->NewNumberFromInt(val, TENURED), \ + Representation::Integer32()) #define H_CONSTANT_DOUBLE(val) \ -new(zone) HConstant(val, Representation::Double()) +new(zone) HConstant(FACTORY->NewNumber(val, TENURED), \ + Representation::Double()) #define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \ -HInstruction* HInstr::New##HInstr(Zone* zone, \ - HValue* context, \ - HValue* left, \ - HValue* right) { \ - if (left->IsConstant() && right->IsConstant()) { \ +HInstruction* HInstr::New( \ + Zone* zone, HValue* context, HValue* left, HValue* right) { \ + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \ HConstant* c_left = HConstant::cast(left); \ HConstant* c_right = HConstant::cast(right); \ if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \ if (TypeInfo::IsInt32Double(double_res)) { \ - return H_CONSTANT_INT32(static_cast(double_res)); \ + return H_CONSTANT_INT32(double_res); \ } \ return H_CONSTANT_DOUBLE(double_res); \ } \ @@ -2815,11 +2816,168 @@ DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -) #undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR -HInstruction* HMod::NewHMod(Zone* zone, - HValue* context, - HValue* left, - HValue* right) { - if (left->IsConstant() && right->IsConstant()) { +HInstruction* HStringAdd::New( + Zone* zone, HValue* context, HValue* left, HValue* right) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { + HConstant* c_right = HConstant::cast(right); + HConstant* c_left = HConstant::cast(left); + if (c_left->HasStringValue() && c_right->HasStringValue()) { + return new(zone) HConstant(FACTORY->NewConsString(c_left->StringValue(), + c_right->StringValue()), + Representation::Tagged()); + } + } + return new(zone) HStringAdd(context, left, right); +} + + +HInstruction* HStringCharFromCode::New( + Zone* zone, HValue* context, HValue* char_code) { + if (FLAG_fold_constants && char_code->IsConstant()) { + HConstant* c_code = HConstant::cast(char_code); + if (c_code->HasNumberValue()) { + if (isfinite(c_code->DoubleValue())) { + uint32_t code = c_code->NumberValueAsInteger32() & 0xffff; + return new(zone) HConstant(LookupSingleCharacterStringFromCode(code), + Representation::Tagged()); + } + return new(zone) HConstant(FACTORY->empty_string(), + Representation::Tagged()); + } + } + return new(zone) HStringCharFromCode(context, char_code); +} + + +HInstruction* HStringLength::New(Zone* zone, HValue* string) { + if (FLAG_fold_constants && string->IsConstant()) { + HConstant* c_string = HConstant::cast(string); + if (c_string->HasStringValue()) { + return H_CONSTANT_INT32(c_string->StringValue()->length()); + } + } + return new(zone) HStringLength(string); +} + + +HInstruction* HUnaryMathOperation::New( + Zone* zone, HValue* context, HValue* value, BuiltinFunctionId op) { + do { + if (!FLAG_fold_constants) break; + if (!value->IsConstant()) break; + HConstant* constant = HConstant::cast(value); + if (!constant->HasNumberValue()) break; + double d = constant->DoubleValue(); + if (isnan(d)) { // NaN poisons everything. + return H_CONSTANT_DOUBLE(OS::nan_value()); + } + if (isinf(d)) { // +Infinity and -Infinity. + switch (op) { + case kMathSin: + case kMathCos: + case kMathTan: + return H_CONSTANT_DOUBLE(OS::nan_value()); + case kMathExp: + return H_CONSTANT_DOUBLE((d > 0.0) ? d : 0.0); + case kMathLog: + case kMathSqrt: + return H_CONSTANT_DOUBLE((d > 0.0) ? d : OS::nan_value()); + case kMathPowHalf: + case kMathAbs: + return H_CONSTANT_DOUBLE((d > 0.0) ? d : -d); + case kMathRound: + case kMathFloor: + return H_CONSTANT_DOUBLE(d); + default: + UNREACHABLE(); + break; + } + } + switch (op) { + case kMathSin: + return H_CONSTANT_DOUBLE(fast_sin(d)); + case kMathCos: + return H_CONSTANT_DOUBLE(fast_cos(d)); + case kMathTan: + return H_CONSTANT_DOUBLE(fast_tan(d)); + case kMathExp: + return H_CONSTANT_DOUBLE(fast_exp(d)); + case kMathLog: + return H_CONSTANT_DOUBLE(fast_log(d)); + case kMathSqrt: + return H_CONSTANT_DOUBLE(fast_sqrt(d)); + case kMathPowHalf: + return H_CONSTANT_DOUBLE(power_double_double(d, 0.5)); + case kMathAbs: + return H_CONSTANT_DOUBLE((d >= 0.0) ? d + 0.0 : -d); + case kMathRound: + // -0.5 .. -0.0 round to -0.0. + if ((d >= -0.5 && Double(d).Sign() < 0)) return H_CONSTANT_DOUBLE(-0.0); + // Doubles are represented as Significant * 2 ^ Exponent. If the + // Exponent is not negative, the double value is already an integer. + if (Double(d).Exponent() >= 0) return H_CONSTANT_DOUBLE(d); + return H_CONSTANT_DOUBLE(floor(d + 0.5)); + case kMathFloor: + return H_CONSTANT_DOUBLE(floor(d)); + default: + UNREACHABLE(); + break; + } + } while (false); + return new(zone) HUnaryMathOperation(context, value, op); +} + + +HInstruction* HPower::New(Zone* zone, HValue* left, HValue* right) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { + HConstant* c_left = HConstant::cast(left); + HConstant* c_right = HConstant::cast(right); + if (c_left->HasNumberValue() && c_right->HasNumberValue()) { + double result = power_helper(c_left->DoubleValue(), + c_right->DoubleValue()); + return H_CONSTANT_DOUBLE(isnan(result) ? OS::nan_value() : result); + } + } + return new(zone) HPower(left, right); +} + + +HInstruction* HMathMinMax::New( + Zone* zone, HValue* context, HValue* left, HValue* right, Operation op) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { + HConstant* c_left = HConstant::cast(left); + HConstant* c_right = HConstant::cast(right); + if (c_left->HasNumberValue() && c_right->HasNumberValue()) { + double d_left = c_left->DoubleValue(); + double d_right = c_right->DoubleValue(); + if (op == kMathMin) { + if (d_left > d_right) return H_CONSTANT_DOUBLE(d_right); + if (d_left < d_right) return H_CONSTANT_DOUBLE(d_left); + if (d_left == d_right) { + // Handle +0 and -0. + return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_left + : d_right); + } + } else { + if (d_left < d_right) return H_CONSTANT_DOUBLE(d_right); + if (d_left > d_right) return H_CONSTANT_DOUBLE(d_left); + if (d_left == d_right) { + // Handle +0 and -0. + return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_right + : d_left); + } + } + // All comparisons failed, must be NaN. + return H_CONSTANT_DOUBLE(OS::nan_value()); + } + } + return new(zone) HMathMinMax(context, left, right, op); +} + + +HInstruction* HMod::New( + Zone* zone, HValue* context, HValue* left, HValue* right) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { HConstant* c_left = HConstant::cast(left); HConstant* c_right = HConstant::cast(right); if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) { @@ -2838,21 +2996,23 @@ HInstruction* HMod::NewHMod(Zone* zone, } -HInstruction* HDiv::NewHDiv(Zone* zone, - HValue* context, - HValue* left, - HValue* right) { +HInstruction* HDiv::New( + Zone* zone, HValue* context, HValue* left, HValue* right) { // If left and right are constant values, try to return a constant value. - if (left->IsConstant() && right->IsConstant()) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { HConstant* c_left = HConstant::cast(left); HConstant* c_right = HConstant::cast(right); if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { if (c_right->DoubleValue() != 0) { double double_res = c_left->DoubleValue() / c_right->DoubleValue(); if (TypeInfo::IsInt32Double(double_res)) { - return H_CONSTANT_INT32(static_cast(double_res)); + return H_CONSTANT_INT32(double_res); } return H_CONSTANT_DOUBLE(double_res); + } else { + int sign = Double(c_left->DoubleValue()).Sign() * + Double(c_right->DoubleValue()).Sign(); // Right could be -0. + return H_CONSTANT_DOUBLE(sign * V8_INFINITY); } } } @@ -2860,12 +3020,9 @@ HInstruction* HDiv::NewHDiv(Zone* zone, } -HInstruction* HBitwise::NewHBitwise(Zone* zone, - Token::Value op, - HValue* context, - HValue* left, - HValue* right) { - if (left->IsConstant() && right->IsConstant()) { +HInstruction* HBitwise::New( + Zone* zone, Token::Value op, HValue* context, HValue* left, HValue* right) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { HConstant* c_left = HConstant::cast(left); HConstant* c_right = HConstant::cast(right); if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { @@ -2894,11 +3051,9 @@ HInstruction* HBitwise::NewHBitwise(Zone* zone, #define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \ -HInstruction* HInstr::New##HInstr(Zone* zone, \ - HValue* context, \ - HValue* left, \ - HValue* right) { \ - if (left->IsConstant() && right->IsConstant()) { \ +HInstruction* HInstr::New( \ + Zone* zone, HValue* context, HValue* left, HValue* right) { \ + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \ HConstant* c_left = HConstant::cast(left); \ HConstant* c_right = HConstant::cast(right); \ if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ @@ -2917,22 +3072,18 @@ c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f)) #undef DEFINE_NEW_H_BITWISE_INSTR -HInstruction* HShr::NewHShr(Zone* zone, - HValue* context, - HValue* left, - HValue* right) { - if (left->IsConstant() && right->IsConstant()) { +HInstruction* HShr::New( + Zone* zone, HValue* context, HValue* left, HValue* right) { + if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { HConstant* c_left = HConstant::cast(left); HConstant* c_right = HConstant::cast(right); if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { int32_t left_val = c_left->NumberValueAsInteger32(); int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f; if ((right_val == 0) && (left_val < 0)) { - return H_CONSTANT_DOUBLE( - static_cast(static_cast(left_val))); + return H_CONSTANT_DOUBLE(static_cast(left_val)); } - return H_CONSTANT_INT32(static_cast( - static_cast(left_val) >> right_val)); + return H_CONSTANT_INT32(static_cast(left_val) >> right_val); } } return new(zone) HShr(context, left, right); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 2d763d5..c1379e8 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -2373,38 +2373,10 @@ class HBitNot: public HUnaryOperation { class HUnaryMathOperation: public HTemplateInstruction<2> { public: - HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) - : op_(op) { - SetOperandAt(0, context); - SetOperandAt(1, value); - switch (op) { - case kMathFloor: - case kMathRound: - case kMathCeil: - set_representation(Representation::Integer32()); - break; - case kMathAbs: - // Not setting representation here: it is None intentionally. - SetFlag(kFlexibleRepresentation); - SetGVNFlag(kChangesNewSpacePromotion); - break; - case kMathSqrt: - case kMathPowHalf: - case kMathLog: - case kMathSin: - case kMathCos: - case kMathTan: - set_representation(Representation::Double()); - SetGVNFlag(kChangesNewSpacePromotion); - break; - case kMathExp: - set_representation(Representation::Double()); - break; - default: - UNREACHABLE(); - } - SetFlag(kUseGVN); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* value, + BuiltinFunctionId op); HValue* context() { return OperandAt(0); } HValue* value() { return OperandAt(1); } @@ -2422,7 +2394,6 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { switch (op_) { case kMathFloor: case kMathRound: - case kMathCeil: case kMathSqrt: case kMathPowHalf: case kMathLog: @@ -2454,6 +2425,39 @@ class HUnaryMathOperation: public HTemplateInstruction<2> { } private: + HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) + : op_(op) { + SetOperandAt(0, context); + SetOperandAt(1, value); + switch (op) { + case kMathFloor: + case kMathRound: + case kMathCeil: + set_representation(Representation::Integer32()); + break; + case kMathAbs: + // Not setting representation here: it is None intentionally. + SetFlag(kFlexibleRepresentation); + SetGVNFlag(kChangesNewSpacePromotion); + break; + case kMathSqrt: + case kMathPowHalf: + case kMathLog: + case kMathSin: + case kMathCos: + case kMathTan: + set_representation(Representation::Double()); + SetGVNFlag(kChangesNewSpacePromotion); + break; + case kMathExp: + set_representation(Representation::Double()); + break; + default: + UNREACHABLE(); + } + SetFlag(kUseGVN); + } + virtual bool IsDeletable() const { return true; } BuiltinFunctionId op_; @@ -3116,6 +3120,15 @@ class HConstant: public HTemplateInstruction<0> { // representation of the number in int32_value_. return int32_value_; } + bool HasStringValue() const { + if (has_double_value_ || has_int32_value_) return false; + ASSERT(!handle_.is_null()); + return handle_->IsString(); + } + Handle StringValue() const { + ASSERT(HasStringValue()); + return Handle::cast(handle_); + } bool ToBoolean(); @@ -3936,13 +3949,7 @@ class HInstanceOfKnownGlobal: public HTemplateInstruction<2> { class HPower: public HTemplateInstruction<2> { public: - HPower(HValue* left, HValue* right) { - SetOperandAt(0, left); - SetOperandAt(1, right); - set_representation(Representation::Double()); - SetFlag(kUseGVN); - SetGVNFlag(kChangesNewSpacePromotion); - } + static HInstruction* New(Zone* zone, HValue* left, HValue* right); HValue* left() { return OperandAt(0); } HValue* right() const { return OperandAt(1); } @@ -3962,6 +3969,14 @@ class HPower: public HTemplateInstruction<2> { virtual bool DataEquals(HValue* other) { return true; } private: + HPower(HValue* left, HValue* right) { + SetOperandAt(0, left); + SetOperandAt(1, right); + set_representation(Representation::Double()); + SetFlag(kUseGVN); + SetGVNFlag(kChangesNewSpacePromotion); + } + virtual bool IsDeletable() const { return !right()->representation().IsTagged(); } @@ -3990,10 +4005,10 @@ class HRandom: public HTemplateInstruction<1> { class HAdd: public HArithmeticBinaryOperation { public: - HAdd(HValue* context, HValue* left, HValue* right) - : HArithmeticBinaryOperation(context, left, right) { - SetFlag(kCanOverflow); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); // Add is only commutative if two integer values are added and not if two // tagged values are added (because it might be a String concatenation). @@ -4003,11 +4018,6 @@ class HAdd: public HArithmeticBinaryOperation { virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); - static HInstruction* NewHAdd(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - virtual HType CalculateInferredType(); virtual HValue* Canonicalize(); @@ -4035,25 +4045,26 @@ class HAdd: public HArithmeticBinaryOperation { virtual bool DataEquals(HValue* other) { return true; } virtual Range* InferRange(Zone* zone); + + private: + HAdd(HValue* context, HValue* left, HValue* right) + : HArithmeticBinaryOperation(context, left, right) { + SetFlag(kCanOverflow); + } }; class HSub: public HArithmeticBinaryOperation { public: - HSub(HValue* context, HValue* left, HValue* right) - : HArithmeticBinaryOperation(context, left, right) { - SetFlag(kCanOverflow); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); virtual HValue* Canonicalize(); - static HInstruction* NewHSub(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - virtual bool IsRelationTrueInternal(NumericRelation relation, HValue* other) { if (right()->IsInteger32Constant()) { HValue* base = left(); @@ -4071,15 +4082,21 @@ class HSub: public HArithmeticBinaryOperation { virtual bool DataEquals(HValue* other) { return true; } virtual Range* InferRange(Zone* zone); + + private: + HSub(HValue* context, HValue* left, HValue* right) + : HArithmeticBinaryOperation(context, left, right) { + SetFlag(kCanOverflow); + } }; class HMul: public HArithmeticBinaryOperation { public: - HMul(HValue* context, HValue* left, HValue* right) - : HArithmeticBinaryOperation(context, left, right) { - SetFlag(kCanOverflow); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); @@ -4088,26 +4105,27 @@ class HMul: public HArithmeticBinaryOperation { return !representation().IsTagged(); } - static HInstruction* NewHMul(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Mul) protected: virtual bool DataEquals(HValue* other) { return true; } virtual Range* InferRange(Zone* zone); + + private: + HMul(HValue* context, HValue* left, HValue* right) + : HArithmeticBinaryOperation(context, left, right) { + SetFlag(kCanOverflow); + } }; class HMod: public HArithmeticBinaryOperation { public: - HMod(HValue* context, HValue* left, HValue* right) - : HArithmeticBinaryOperation(context, left, right) { - SetFlag(kCanBeDivByZero); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); bool HasPowerOf2Divisor() { if (right()->IsConstant() && @@ -4121,27 +4139,27 @@ class HMod: public HArithmeticBinaryOperation { virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); - static HInstruction* NewHMod(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Mod) protected: virtual bool DataEquals(HValue* other) { return true; } virtual Range* InferRange(Zone* zone); + + private: + HMod(HValue* context, HValue* left, HValue* right) + : HArithmeticBinaryOperation(context, left, right) { + SetFlag(kCanBeDivByZero); + } }; class HDiv: public HArithmeticBinaryOperation { public: - HDiv(HValue* context, HValue* left, HValue* right) - : HArithmeticBinaryOperation(context, left, right) { - SetFlag(kCanBeDivByZero); - SetFlag(kCanOverflow); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); bool HasPowerOf2Divisor() { if (right()->IsConstant() && @@ -4155,17 +4173,19 @@ class HDiv: public HArithmeticBinaryOperation { virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); - static HInstruction* NewHDiv(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Div) protected: virtual bool DataEquals(HValue* other) { return true; } virtual Range* InferRange(Zone* zone); + + private: + HDiv(HValue* context, HValue* left, HValue* right) + : HArithmeticBinaryOperation(context, left, right) { + SetFlag(kCanBeDivByZero); + SetFlag(kCanOverflow); + } }; @@ -4173,9 +4193,11 @@ class HMathMinMax: public HArithmeticBinaryOperation { public: enum Operation { kMathMin, kMathMax }; - HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) - : HArithmeticBinaryOperation(context, left, right), - operation_(op) { } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right, + Operation op); virtual Representation RequiredInputRepresentation(int index) { return index == 0 ? Representation::Tagged() @@ -4213,18 +4235,21 @@ class HMathMinMax: public HArithmeticBinaryOperation { virtual Range* InferRange(Zone* zone); private: + HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) + : HArithmeticBinaryOperation(context, left, right), + operation_(op) { } + Operation operation_; }; class HBitwise: public HBitwiseBinaryOperation { public: - HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right) - : HBitwiseBinaryOperation(context, left, right), op_(op) { - ASSERT(op == Token::BIT_AND || - op == Token::BIT_OR || - op == Token::BIT_XOR); - } + static HInstruction* New(Zone* zone, + Token::Value op, + HValue* context, + HValue* left, + HValue* right); Token::Value op() const { return op_; } @@ -4232,12 +4257,6 @@ class HBitwise: public HBitwiseBinaryOperation { virtual HValue* Canonicalize(); - static HInstruction* NewHBitwise(Zone* zone, - Token::Value op, - HValue* context, - HValue* left, - HValue* right); - virtual void PrintDataTo(StringStream* stream); DECLARE_CONCRETE_INSTRUCTION(Bitwise) @@ -4250,79 +4269,82 @@ class HBitwise: public HBitwiseBinaryOperation { virtual Range* InferRange(Zone* zone); private: + HBitwise(Token::Value op, HValue* context, HValue* left, HValue* right) + : HBitwiseBinaryOperation(context, left, right), op_(op) { + ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR); + } + Token::Value op_; }; class HShl: public HBitwiseBinaryOperation { public: - HShl(HValue* context, HValue* left, HValue* right) - : HBitwiseBinaryOperation(context, left, right) { } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); virtual Range* InferRange(Zone* zone); - static HInstruction* NewHShl(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Shl) protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + HShl(HValue* context, HValue* left, HValue* right) + : HBitwiseBinaryOperation(context, left, right) { } }; class HShr: public HBitwiseBinaryOperation { public: - HShr(HValue* context, HValue* left, HValue* right) - : HBitwiseBinaryOperation(context, left, right) { } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); virtual Range* InferRange(Zone* zone); - static HInstruction* NewHShr(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Shr) protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + HShr(HValue* context, HValue* left, HValue* right) + : HBitwiseBinaryOperation(context, left, right) { } }; class HSar: public HBitwiseBinaryOperation { public: - HSar(HValue* context, HValue* left, HValue* right) - : HBitwiseBinaryOperation(context, left, right) { } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); virtual Range* InferRange(Zone* zone); - static HInstruction* NewHSar(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Sar) protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + HSar(HValue* context, HValue* left, HValue* right) + : HBitwiseBinaryOperation(context, left, right) { } }; class HRor: public HBitwiseBinaryOperation { public: HRor(HValue* context, HValue* left, HValue* right) - : HBitwiseBinaryOperation(context, left, right) { + : HBitwiseBinaryOperation(context, left, right) { ChangeRepresentation(Representation::Integer32()); } - static HInstruction* NewHRor(Zone* zone, - HValue* context, - HValue* left, - HValue* right); - DECLARE_CONCRETE_INSTRUCTION(Ror) protected: @@ -5446,13 +5468,10 @@ class HTransitionElementsKind: public HTemplateInstruction<2> { class HStringAdd: public HBinaryOperation { public: - HStringAdd(HValue* context, HValue* left, HValue* right) - : HBinaryOperation(context, left, right) { - set_representation(Representation::Tagged()); - SetFlag(kUseGVN); - SetGVNFlag(kDependsOnMaps); - SetGVNFlag(kChangesNewSpacePromotion); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* left, + HValue* right); virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); @@ -5467,8 +5486,17 @@ class HStringAdd: public HBinaryOperation { protected: virtual bool DataEquals(HValue* other) { return true; } + + private: + HStringAdd(HValue* context, HValue* left, HValue* right) + : HBinaryOperation(context, left, right) { + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetGVNFlag(kDependsOnMaps); + SetGVNFlag(kChangesNewSpacePromotion); + } + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. - // private: // virtual bool IsDeletable() const { return true; } }; @@ -5513,13 +5541,9 @@ class HStringCharCodeAt: public HTemplateInstruction<3> { class HStringCharFromCode: public HTemplateInstruction<2> { public: - HStringCharFromCode(HValue* context, HValue* char_code) { - SetOperandAt(0, context); - SetOperandAt(1, char_code); - set_representation(Representation::Tagged()); - SetFlag(kUseGVN); - SetGVNFlag(kChangesNewSpacePromotion); - } + static HInstruction* New(Zone* zone, + HValue* context, + HValue* char_code); virtual Representation RequiredInputRepresentation(int index) { return index == 0 @@ -5535,19 +5559,23 @@ class HStringCharFromCode: public HTemplateInstruction<2> { DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) + private: + HStringCharFromCode(HValue* context, HValue* char_code) { + SetOperandAt(0, context); + SetOperandAt(1, char_code); + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetGVNFlag(kChangesNewSpacePromotion); + } + // TODO(svenpanne) Might be safe, but leave it out until we know for sure. - // private: - // virtual bool IsDeletable() const { return true; } + // virtual bool IsDeletable() const { return true; } }; class HStringLength: public HUnaryOperation { public: - explicit HStringLength(HValue* string) : HUnaryOperation(string) { - set_representation(Representation::Tagged()); - SetFlag(kUseGVN); - SetGVNFlag(kDependsOnMaps); - } + static HInstruction* New(Zone* zone, HValue* string); virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); @@ -5568,6 +5596,12 @@ class HStringLength: public HUnaryOperation { } private: + explicit HStringLength(HValue* string) : HUnaryOperation(string) { + set_representation(Representation::Tagged()); + SetFlag(kUseGVN); + SetGVNFlag(kDependsOnMaps); + } + virtual bool IsDeletable() const { return true; } }; diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 3ea9156..1440fe4 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -718,9 +718,9 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody(HValue* initial, if (direction_ == kPreIncrement || direction_ == kPreDecrement) { HValue* one = builder_->graph()->GetConstant1(); if (direction_ == kPreIncrement) { - increment_ = new(zone()) HAdd(context_, phi_, one); + increment_ = HAdd::New(zone(), context_, phi_, one); } else { - increment_ = new(zone()) HSub(context_, phi_, one); + increment_ = HSub::New(zone(), context_, phi_, one); } increment_->ClearFlag(HValue::kCanOverflow); increment_->ChangeRepresentation(Representation::Integer32()); @@ -738,9 +738,9 @@ void HGraphBuilder::LoopBuilder::EndBody() { if (direction_ == kPostIncrement || direction_ == kPostDecrement) { HValue* one = builder_->graph()->GetConstant1(); if (direction_ == kPostIncrement) { - increment_ = new(zone()) HAdd(context_, phi_, one); + increment_ = HAdd::New(zone(), context_, phi_, one); } else { - increment_ = new(zone()) HSub(context_, phi_, one); + increment_ = HSub::New(zone(), context_, phi_, one); } increment_->ClearFlag(HValue::kCanOverflow); increment_->ChangeRepresentation(Representation::Integer32()); @@ -974,7 +974,7 @@ HValue* HGraphBuilder::BuildAllocateElements(HContext* context, new(zone) HConstant(elements_size, Representation::Integer32()); AddInstruction(elements_size_value); HValue* mul = AddInstruction( - new(zone) HMul(context, capacity, elements_size_value)); + HMul::New(zone, context, capacity, elements_size_value)); mul->ChangeRepresentation(Representation::Integer32()); mul->ClearFlag(HValue::kCanOverflow); @@ -982,7 +982,7 @@ HValue* HGraphBuilder::BuildAllocateElements(HContext* context, new(zone) HConstant(FixedArray::kHeaderSize, Representation::Integer32()); AddInstruction(header_size); HValue* total_size = AddInstruction( - new(zone) HAdd(context, mul, header_size)); + HAdd::New(zone, context, mul, header_size)); total_size->ChangeRepresentation(Representation::Integer32()); total_size->ClearFlag(HValue::kCanOverflow); @@ -4120,18 +4120,18 @@ class BoundsCheckBbData: public ZoneObject { HBasicBlock* basic_block_; HBoundsCheck* lower_check_; HBoundsCheck* upper_check_; - HAdd* added_lower_index_; + HInstruction* added_lower_index_; HConstant* added_lower_offset_; - HAdd* added_upper_index_; + HInstruction* added_upper_index_; HConstant* added_upper_offset_; BoundsCheckBbData* next_in_bb_; BoundsCheckBbData* father_in_dt_; // Given an existing add instruction and a bounds check it tries to // find the current context (either of the add or of the check index). - HValue* IndexContext(HAdd* add, HBoundsCheck* check) { - if (add != NULL) { - return add->context(); + HValue* IndexContext(HInstruction* add, HBoundsCheck* check) { + if (add != NULL && add->IsAdd()) { + return HAdd::cast(add)->context(); } if (check->index()->IsBinaryOperation()) { return HBinaryOperation::cast(check->index())->context(); @@ -4142,7 +4142,7 @@ class BoundsCheckBbData: public ZoneObject { // This function returns false if it cannot build the add because the // current context cannot be determined. bool BuildOffsetAdd(HBoundsCheck* check, - HAdd** add, + HInstruction** add, HConstant** constant, HValue* original_value, Representation representation, @@ -4154,9 +4154,8 @@ class BoundsCheckBbData: public ZoneObject { HConstant(new_offset, Representation::Integer32()); if (*add == NULL) { new_constant->InsertBefore(check); - *add = new(BasicBlock()->zone()) HAdd(index_context, - original_value, - new_constant); + (*add) = HAdd::New( + BasicBlock()->zone(), index_context, original_value, new_constant); (*add)->AssumeRepresentation(representation); (*add)->InsertBefore(check); } else { @@ -4167,9 +4166,9 @@ class BoundsCheckBbData: public ZoneObject { return true; } - void RemoveZeroAdd(HAdd** add, HConstant** constant) { - if (*add != NULL && (*constant)->Integer32Value() == 0) { - (*add)->DeleteAndReplaceWith((*add)->left()); + void RemoveZeroAdd(HInstruction** add, HConstant** constant) { + if (*add != NULL && (*add)->IsAdd() && (*constant)->Integer32Value() == 0) { + (*add)->DeleteAndReplaceWith(HAdd::cast(*add)->left()); (*constant)->DeleteAndReplaceWith(NULL); } } @@ -5221,9 +5220,10 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { set_current_block(body_exit); HValue* current_index = Pop(); - HInstruction* new_index = new(zone()) HAdd(environment()->LookupContext(), - current_index, - graph()->GetConstant1()); + HInstruction* new_index = HAdd::New(zone(), + environment()->LookupContext(), + current_index, + graph()->GetConstant1()); new_index->AssumeRepresentation(Representation::Integer32()); PushAndAdd(new_index); body_exit = current_block(); @@ -7127,16 +7127,16 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { HValue* string = Pop(); AddInstruction(new(zone()) HCheckNonSmi(string)); AddInstruction(HCheckInstanceType::NewIsString(string, zone())); - instr = new(zone()) HStringLength(string); + instr = HStringLength::New(zone(), string); } else if (expr->IsStringAccess()) { CHECK_ALIVE(VisitForValue(expr->key())); HValue* index = Pop(); HValue* string = Pop(); HValue* context = environment()->LookupContext(); - HStringCharCodeAt* char_code = + HInstruction* char_code = BuildStringCharCodeAt(context, string, index); AddInstruction(char_code); - instr = new(zone()) HStringCharFromCode(context, char_code); + instr = HStringCharFromCode::New(zone(), context, char_code); } else if (expr->IsFunctionPrototype()) { HValue* function = Pop(); @@ -7806,6 +7806,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, if (!FLAG_fast_math) break; // Fall through if FLAG_fast_math. case kMathRound: + case kMathFloor: case kMathAbs: case kMathSqrt: case kMathLog: @@ -7816,8 +7817,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, HValue* argument = Pop(); HValue* context = environment()->LookupContext(); Drop(1); // Receiver. - HUnaryMathOperation* op = - new(zone()) HUnaryMathOperation(context, argument, id); + HInstruction* op = + HUnaryMathOperation::New(zone(), context, argument, id); op->set_position(expr->position()); if (drop_extra) Drop(1); // Optionally drop the function. ast_context()->ReturnInstruction(op, expr->id()); @@ -7854,15 +7855,15 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), expr->holder(), zone())); - HStringCharCodeAt* char_code = + HInstruction* char_code = BuildStringCharCodeAt(context, string, index); if (id == kStringCharCodeAt) { ast_context()->ReturnInstruction(char_code, expr->id()); return true; } AddInstruction(char_code); - HStringCharFromCode* result = - new(zone()) HStringCharFromCode(context, char_code); + HInstruction* result = + HStringCharFromCode::New(zone(), context, char_code); ast_context()->ReturnInstruction(result, expr->id()); return true; } @@ -7883,8 +7884,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( HValue* argument = Pop(); HValue* context = environment()->LookupContext(); Drop(1); // Receiver. - HUnaryMathOperation* op = - new(zone()) HUnaryMathOperation(context, argument, id); + HInstruction* op = + HUnaryMathOperation::New(zone(), context, argument, id); op->set_position(expr->position()); ast_context()->ReturnInstruction(op, expr->id()); return true; @@ -7903,30 +7904,30 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( double exponent = HConstant::cast(right)->DoubleValue(); if (exponent == 0.5) { result = - new(zone()) HUnaryMathOperation(context, left, kMathPowHalf); + HUnaryMathOperation::New(zone(), context, left, kMathPowHalf); } else if (exponent == -0.5) { HConstant* double_one = new(zone()) HConstant(Handle(Smi::FromInt(1)), Representation::Double()); AddInstruction(double_one); - HUnaryMathOperation* square_root = - new(zone()) HUnaryMathOperation(context, left, kMathPowHalf); - AddInstruction(square_root); + HInstruction* sqrt = + HUnaryMathOperation::New(zone(), context, left, kMathPowHalf); + AddInstruction(sqrt); // MathPowHalf doesn't have side effects so there's no need for // an environment simulation here. - ASSERT(!square_root->HasObservableSideEffects()); - result = new(zone()) HDiv(context, double_one, square_root); + ASSERT(!sqrt->HasObservableSideEffects()); + result = HDiv::New(zone(), context, double_one, sqrt); } else if (exponent == 2.0) { - result = new(zone()) HMul(context, left, left); + result = HMul::New(zone(), context, left, left); } } else if (right->IsConstant() && HConstant::cast(right)->HasInteger32Value() && HConstant::cast(right)->Integer32Value() == 2) { - result = new(zone()) HMul(context, left, left); + result = HMul::New(zone(), context, left, left); } if (result == NULL) { - result = new(zone()) HPower(left, right); + result = HPower::New(zone(), left, right); } ast_context()->ReturnInstruction(result, expr->id()); return true; @@ -7954,7 +7955,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( HValue* context = environment()->LookupContext(); HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin : HMathMinMax::kMathMax; - HMathMinMax* result = new(zone()) HMathMinMax(context, left, right, op); + HInstruction* result = + HMathMinMax::New(zone(), context, left, right, op); ast_context()->ReturnInstruction(result, expr->id()); return true; } @@ -8528,7 +8530,7 @@ void HOptimizedGraphBuilder::VisitAdd(UnaryOperation* expr) { HValue* value = Pop(); HValue* context = environment()->LookupContext(); HInstruction* instr = - new(zone()) HMul(context, value, graph()->GetConstant1()); + HMul::New(zone(), context, value, graph()->GetConstant1()); return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -8538,14 +8540,16 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { HValue* value = Pop(); HValue* context = environment()->LookupContext(); HInstruction* instr = - new(zone()) HMul(context, value, graph()->GetConstantMinus1()); + HMul::New(zone(), context, value, graph()->GetConstantMinus1()); TypeInfo info = oracle()->UnaryType(expr); Representation rep = ToRepresentation(info); if (info.IsUninitialized()) { AddSoftDeoptimize(); info = TypeInfo::Unknown(); } - HBinaryOperation::cast(instr)->set_observed_input_representation(rep, rep); + if (instr->IsBinaryOperation()) { + HBinaryOperation::cast(instr)->set_observed_input_representation(rep, rep); + } return ast_context()->ReturnInstruction(instr, expr->id()); } @@ -8633,7 +8637,7 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement( ? graph()->GetConstant1() : graph()->GetConstantMinus1(); HValue* context = environment()->LookupContext(); - HInstruction* instr = new(zone()) HAdd(context, Top(), delta); + HInstruction* instr = HAdd::New(zone(), context, Top(), delta); // We can't insert a simulate here, because it would break deoptimization, // so the HAdd must not have side effects, so we must freeze its // representation. @@ -8829,13 +8833,25 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { } -HStringCharCodeAt* HOptimizedGraphBuilder::BuildStringCharCodeAt( +HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt( HValue* context, HValue* string, HValue* index) { + if (string->IsConstant() && index->IsConstant()) { + HConstant* c_string = HConstant::cast(string); + HConstant* c_index = HConstant::cast(index); + if (c_string->HasStringValue() && c_index->HasNumberValue()) { + int32_t i = c_index->NumberValueAsInteger32(); + Handle s = c_string->StringValue(); + if (i < 0 || i >= s->length()) { + return new(zone()) HConstant(OS::nan_value(), Representation::Double()); + } + return new(zone()) HConstant(s->Get(i), Representation::Integer32()); + } + } AddInstruction(new(zone()) HCheckNonSmi(string)); AddInstruction(HCheckInstanceType::NewIsString(string, zone())); - HStringLength* length = new(zone()) HStringLength(string); + HInstruction* length = HStringLength::New(zone(), string); AddInstruction(length); HInstruction* checked_index = AddBoundsCheck(index, length); return new(zone()) HStringCharCodeAt(context, string, checked_index); @@ -8923,26 +8939,26 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( AddInstruction(HCheckInstanceType::NewIsString(left, zone())); AddInstruction(new(zone()) HCheckNonSmi(right)); AddInstruction(HCheckInstanceType::NewIsString(right, zone())); - instr = new(zone()) HStringAdd(context, left, right); + instr = HStringAdd::New(zone(), context, left, right); } else { - instr = HAdd::NewHAdd(zone(), context, left, right); + instr = HAdd::New(zone(), context, left, right); } break; case Token::SUB: - instr = HSub::NewHSub(zone(), context, left, right); + instr = HSub::New(zone(), context, left, right); break; case Token::MUL: - instr = HMul::NewHMul(zone(), context, left, right); + instr = HMul::New(zone(), context, left, right); break; case Token::MOD: - instr = HMod::NewHMod(zone(), context, left, right); + instr = HMod::New(zone(), context, left, right); break; case Token::DIV: - instr = HDiv::NewHDiv(zone(), context, left, right); + instr = HDiv::New(zone(), context, left, right); break; case Token::BIT_XOR: case Token::BIT_AND: - instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right); + instr = HBitwise::New(zone(), expr->op(), context, left, right); break; case Token::BIT_OR: { HValue* operand, *shift_amount; @@ -8950,22 +8966,22 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( MatchRotateRight(left, right, &operand, &shift_amount)) { instr = new(zone()) HRor(context, operand, shift_amount); } else { - instr = HBitwise::NewHBitwise(zone(), expr->op(), context, left, right); + instr = HBitwise::New(zone(), expr->op(), context, left, right); } break; } case Token::SAR: - instr = HSar::NewHSar(zone(), context, left, right); + instr = HSar::New(zone(), context, left, right); break; case Token::SHR: - instr = HShr::NewHShr(zone(), context, left, right); + instr = HShr::New(zone(), context, left, right); if (FLAG_opt_safe_uint32_operations && instr->IsShr() && CanBeZero(right)) { graph()->RecordUint32Instruction(instr); } break; case Token::SHL: - instr = HShl::NewHShl(zone(), context, left, right); + instr = HShl::New(zone(), context, left, right); break; default: UNREACHABLE(); @@ -9736,7 +9752,7 @@ void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( HValue* index = Pop(); HValue* string = Pop(); HValue* context = environment()->LookupContext(); - HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index); + HInstruction* char_code = BuildStringCharCodeAt(context, string, index); AddInstruction(char_code); HSeqStringSetChar* result = new(zone()) HSeqStringSetChar( String::TWO_BYTE_ENCODING, string, index, value); @@ -9794,7 +9810,7 @@ void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { HValue* index = Pop(); HValue* string = Pop(); HValue* context = environment()->LookupContext(); - HStringCharCodeAt* result = BuildStringCharCodeAt(context, string, index); + HInstruction* result = BuildStringCharCodeAt(context, string, index); return ast_context()->ReturnInstruction(result, call->id()); } @@ -9805,8 +9821,7 @@ void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); HValue* char_code = Pop(); HValue* context = environment()->LookupContext(); - HStringCharFromCode* result = - new(zone()) HStringCharFromCode(context, char_code); + HInstruction* result = HStringCharFromCode::New(zone(), context, char_code); return ast_context()->ReturnInstruction(result, call->id()); } @@ -9819,10 +9834,9 @@ void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) { HValue* index = Pop(); HValue* string = Pop(); HValue* context = environment()->LookupContext(); - HStringCharCodeAt* char_code = BuildStringCharCodeAt(context, string, index); + HInstruction* char_code = BuildStringCharCodeAt(context, string, index); AddInstruction(char_code); - HStringCharFromCode* result = - new(zone()) HStringCharFromCode(context, char_code); + HInstruction* result = HStringCharFromCode::New(zone(), context, char_code); return ast_context()->ReturnInstruction(result, call->id()); } @@ -9982,7 +9996,7 @@ void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) { CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); HValue* right = Pop(); HValue* left = Pop(); - HPower* result = new(zone()) HPower(left, right); + HInstruction* result = HPower::New(zone(), left, right); return ast_context()->ReturnInstruction(result, call->id()); } diff --git a/src/hydrogen.h b/src/hydrogen.h index f4ab12a..0a2338a 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -1294,9 +1294,9 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor { HValue* value, NilValue nil); - HStringCharCodeAt* BuildStringCharCodeAt(HValue* context, - HValue* string, - HValue* index); + HInstruction* BuildStringCharCodeAt(HValue* context, + HValue* string, + HValue* index); HInstruction* BuildBinaryOperation(BinaryOperation* expr, HValue* left, HValue* right); diff --git a/src/runtime.cc b/src/runtime.cc index ead0281..3728646 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7093,19 +7093,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) { } CONVERT_DOUBLE_ARG_CHECKED(y, 1); - int y_int = static_cast(y); - double result; - if (y == y_int) { - result = power_double_int(x, y_int); // Returns 1 if exponent is 0. - } else if (y == 0.5) { - result = (isinf(x)) ? V8_INFINITY - : fast_sqrt(x + 0.0); // Convert -0 to +0. - } else if (y == -0.5) { - result = (isinf(x)) ? 0 - : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0. - } else { - result = power_double_double(x, y); - } + double result = power_helper(x, y); if (isnan(result)) return isolate->heap()->nan_value(); return isolate->heap()->AllocateHeapNumber(result); } diff --git a/test/mjsunit/constant-folding-2.js b/test/mjsunit/constant-folding-2.js new file mode 100644 index 0000000..6dbb4ab --- /dev/null +++ b/test/mjsunit/constant-folding-2.js @@ -0,0 +1,258 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Flags: --nodead-code-elimination --fold-constants --allow-natives-syntax + +function test(f) { + f(); + f(); + %OptimizeFunctionOnNextCall(f); + f(); + // Assert that there has been no deopt. + assertTrue(%GetOptimizationStatus(f) != 2); +} + +test(function add() { + assertEquals(2, 1 + 1); + assertEquals(2.5, 1.25 + 1.25); + assertEquals("Infinity", String(Infinity + Infinity)); + assertEquals("Infinity", String(Infinity + 3)); + assertEquals("NaN", String(Infinity + (-Infinity))); + assertEquals("NaN", String(NaN + 2)); + assertEquals("-Infinity", String(1 / (-0.0 + (-0.0)))); + assertEquals("Infinity", String(1 / (-0.0 + 0.0))); +}); + +test(function inc() { + var a = 1; + var b = Infinity; + var c = -Infinity; + var d = NaN; + assertEquals(2, ++a); + assertEquals("Infinity", String(++b)); + assertEquals("-Infinity", String(++c)); + assertEquals("NaN", String(++d)); +}); + +test(function dec() { + var a = 1; + var b = Infinity; + var c = -Infinity; + var d = NaN; + assertEquals(0, --a); + assertEquals("Infinity", String(--b)); + assertEquals("-Infinity", String(--c)); + assertEquals("NaN", String(--d)); +}); + +test(function sub() { + assertEquals(0, 1 - 1); + assertEquals(0.5, 1.5 - 1); + assertEquals("Infinity", String(Infinity - (-Infinity))); + assertEquals("Infinity", String(Infinity - 3)); + assertEquals("NaN", String(Infinity - Infinity)); + assertEquals("NaN", String(NaN - 2)); + assertEquals("-Infinity", String(1 / (-0.0 - 0.0))); + assertEquals("Infinity", String(1 / (0.0 - 0.0))); +}); + +test(function mul() { + assertEquals(1, 1 * 1); + assertEquals(2.25, 1.5 * 1.5); + assertEquals("Infinity", String(Infinity * Infinity)); + assertEquals("-Infinity", String(Infinity * (-Infinity))); + assertEquals("Infinity", String(Infinity * 3)); + assertEquals("-Infinity", String(Infinity * (-3))); + assertEquals("NaN", String(NaN * 3)); + assertEquals("-Infinity", String(1 / (-0.0 * 0.0))); + assertEquals("Infinity", String(1 / (0.0 * 0.0))); +}); + +test(function div() { + assertEquals(1, 1 / 1); + assertEquals(1.5, 2.25 / 1.5); + assertEquals("NaN", String(Infinity / Infinity)); + assertEquals("Infinity", String(Infinity / 3)); + assertEquals("-Infinity", String(Infinity / (-3))); + assertEquals("NaN", String(NaN / 3)); + assertEquals("-Infinity", String(1 / (-0.0))); + assertEquals("Infinity", String(Infinity/0.0)); +}); + +test(function mathMin() { + assertEquals(1, Math.min(1, 10)); + assertEquals(1.5, Math.min(1.5, 2.5)); + assertEquals(0, Math.min(Infinity, 0)); + assertEquals("Infinity", String(Math.min(Infinity, Infinity))); + assertEquals("-Infinity", String(Math.min(Infinity, -Infinity))); + assertEquals("NaN", String(Math.min(NaN, 1))); + assertEquals("Infinity", String(1 / Math.min(0.0, 0.0))); + assertEquals("-Infinity", String(1 / Math.min(-0.0, -0.0))); + assertEquals("-Infinity", String(1 / Math.min(0.0, -0.0))); +}); + +test(function mathMax() { + assertEquals(10, Math.max(1, 10)); + assertEquals(2.5, Math.max(1.5, 2.5)); + assertEquals(Infinity, Math.max(Infinity, 0)); + assertEquals("-Infinity", String(Math.max(-Infinity, -Infinity))); + assertEquals("Infinity", String(Math.max(Infinity, -Infinity))); + assertEquals("NaN", String(Math.max(NaN, 1))); + assertEquals("Infinity", String(1 / Math.max(0.0, 0.0))); + assertEquals("-Infinity", String(1 / Math.max(-0.0, -0.0))); + assertEquals("Infinity", String(1 / Math.max(0.0, -0.0))); +}); + +test(function mathSin() { + assertEquals(0.0, Math.sin(0.0)); + assertTrue(0.8 < Math.sin(1) && Math.sin(1) < 0.9); + assertEquals("NaN", String(Math.sin(Infinity))); + assertEquals("NaN", String(Math.sin(-Infinity))); + assertEquals("NaN", String(Math.sin(NaN))); +}); + +test(function mathCos() { + assertEquals(1.0, Math.cos(0.0)); + assertTrue(0.5 < Math.cos(1) && Math.cos(1) < 0.6); + assertEquals("NaN", String(Math.cos(Infinity))); + assertEquals("NaN", String(Math.cos(-Infinity))); + assertEquals("NaN", String(Math.cos(NaN))); +}); + +test(function mathTan() { + assertEquals(0.0, Math.tan(0.0)); + assertTrue(1.5 < Math.tan(1) && Math.tan(1) < 1.6); + assertEquals("NaN", String(Math.tan(Infinity))); + assertEquals("NaN", String(Math.tan(-Infinity))); + assertEquals("NaN", String(Math.tan(NaN))); +}); + +test(function mathExp() { + assertEquals(1.0, Math.exp(0.0)); + assertTrue(2.7 < Math.exp(1) && Math.exp(1) < 2.8); + assertEquals("Infinity", String(Math.exp(Infinity))); + assertEquals("0", String(Math.exp(-Infinity))); + assertEquals("NaN", String(Math.exp(NaN))); +}); + +test(function mathLog() { + assertEquals(0.0, Math.log(1.0)); + assertTrue(1 < Math.log(3) && Math.log(3) < 1.5); + assertEquals("Infinity", String(Math.log(Infinity))); + assertEquals("NaN", String(Math.log(-Infinity))); + assertEquals("NaN", String(Math.exp(NaN))); +}); + +test(function mathSqrt() { + assertEquals(1.0, Math.sqrt(1.0)); + assertEquals("NaN", String(Math.sqrt(-1.0))); + assertEquals("Infinity", String(Math.sqrt(Infinity))); + assertEquals("NaN", String(Math.sqrt(-Infinity))); + assertEquals("NaN", String(Math.sqrt(NaN))); +}); + +test(function mathPowHalf() { + assertEquals(1.0, Math.pow(1.0, 0.5)); + assertEquals("NaN", String(Math.sqrt(-1.0))); + assertEquals("Infinity", String(Math.pow(Infinity, 0.5))); + assertEquals("NaN", String(Math.sqrt(-Infinity, 0.5))); + assertEquals(0, Math.pow(Infinity, -0.5)); + assertEquals("NaN", String(Math.sqrt(-Infinity, -0.5))); + assertEquals("NaN", String(Math.sqrt(NaN, 0.5))); +}); + +test(function mathAbs() { + assertEquals(1.5, Math.abs(1.5)); + assertEquals(1.5, Math.abs(-1.5)); + assertEquals("Infinity", String(Math.abs(Infinity))); + assertEquals("Infinity", String(Math.abs(-Infinity))); + assertEquals("NaN", String(Math.abs(NaN))); +}); + +test(function mathRound() { + assertEquals(2, Math.round(1.5)); + assertEquals(-1, Math.round(-1.5)); + assertEquals("Infinity", String(Math.round(Infinity))); + assertEquals("-Infinity", String(Math.round(-Infinity))); + assertEquals("Infinity", String(1 / Math.round(0.0))); + assertEquals("-Infinity", String(1 / Math.round(-0.0))); + assertEquals("NaN", String(Math.round(NaN))); + assertEquals(Math.pow(2, 52) + 1, Math.round(Math.pow(2, 52) + 1)); +}); + +test(function mathFloor() { + assertEquals(1, Math.floor(1.5)); + assertEquals(-2, Math.floor(-1.5)); + assertEquals("Infinity", String(Math.floor(Infinity))); + assertEquals("-Infinity", String(Math.floor(-Infinity))); + assertEquals("Infinity", String(1 / Math.floor(0.0))); + assertEquals("-Infinity", String(1 / Math.floor(-0.0))); + assertEquals("NaN", String(Math.floor(NaN))); + assertEquals(Math.pow(2, 52) + 1, Math.floor(Math.pow(2, 52) + 1)); +}); + +test(function mathPow() { + assertEquals(2.25, Math.pow(1.5, 2)); + assertTrue(1.8 < Math.pow(1.5, 1.5) && Math.pow(1.5, 1.5) < 1.9); + assertEquals("Infinity", String(Math.pow(Infinity, 0.5))); + assertEquals("Infinity", String(Math.pow(-Infinity, 0.5))); + assertEquals(0, Math.pow(Infinity, -0.5)); + assertEquals(0, Math.pow(Infinity, -0.5)); + assertEquals("Infinity", String(Math.pow(Infinity, Infinity))); + assertEquals(0, Math.pow(Infinity, -Infinity)); + assertEquals("NaN", String(Math.pow(Infinity, NaN))); + assertEquals("NaN", String(Math.pow(NaN, 2))); +}); + +test(function stringAdd() { + assertEquals("", "" + ""); + assertEquals("folded constant", "folded " + "constant"); + assertEquals("not folded constant1", "not folded constant" + 1); +}); + +test(function stringLength() { + assertEquals(6, "abcdef".length); + assertEquals(0, "".length); + assertEquals(-5, { length: -5 }.length); +}); + +test(function stringCharCodeAt() { + assertEquals(99, "abc".charCodeAt(2)); + assertEquals("NaN", String("abc".charCodeAt(-1))); + assertEquals("NaN", String("abc".charCodeAt(4))); + assertEquals(98, "abc".charCodeAt(1.1)); + assertEquals("NaN", String("abc".charCodeAt(4.1))); +}); + +test(function stringCharAt() { + assertEquals("c", "abc".charAt(2)); + assertEquals("", "abc".charAt(-1)); + assertEquals("", "abc".charAt(4)); + assertEquals("b", "abc".charAt(1.1)); + assertEquals("", "abc".charAt(4.1)); +}); diff --git a/tools/run-tests.py b/tools/run-tests.py index 292f6f6..cb64b45 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -58,8 +58,10 @@ VARIANT_FLAGS = [[], ["--nocrankshaft"]] MODE_FLAGS = { "debug" : ["--nobreak-on-abort", "--nodead-code-elimination", - "--enable-slow-asserts", "--debug-code", "--verify-heap"], - "release" : ["--nobreak-on-abort", "--nodead-code-elimination"]} + "--nofold-constants", "--enable-slow-asserts", + "--debug-code", "--verify-heap"], + "release" : ["--nobreak-on-abort", "--nodead-code-elimination", + "--nofold-constants"]} SUPPORTED_ARCHS = ["android_arm", "android_ia32", diff --git a/tools/test.py b/tools/test.py index b3b62b3..c528fc4 100755 --- a/tools/test.py +++ b/tools/test.py @@ -685,8 +685,10 @@ SUFFIX = { 'release' : '' } FLAGS = { 'debug' : ['--nobreak-on-abort', '--nodead-code-elimination', - '--enable-slow-asserts', '--debug-code', '--verify-heap'], - 'release' : ['--nobreak-on-abort', '--nodead-code-elimination']} + '--nofold-constants', '--enable-slow-asserts', + '--debug-code', '--verify-heap'], + 'release' : ['--nobreak-on-abort', '--nodead-code-elimination', + '--nofold-constants']} TIMEOUT_SCALEFACTOR = { 'debug' : 4, 'release' : 1 } -- 2.7.4