const double DoubleConstant::min_int = kMinInt;
const double DoubleConstant::one_half = 0.5;
+const double DoubleConstant::negative_infinity = -V8_INFINITY;
// -----------------------------------------------------------------------------
}
+ExternalReference ExternalReference::address_of_negative_infinity() {
+ return ExternalReference(reinterpret_cast<void*>(
+ const_cast<double*>(&DoubleConstant::negative_infinity)));
+}
+
+
#ifndef V8_INTERPRETED_REGEXP
ExternalReference ExternalReference::re_check_stack_guard_state() {
}
+// 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
+// S. Warren, Jr., figure 11-6, page 213.
+double power_double_int(double x, int y) {
+ double m = (y < 0) ? 1 / x : x;
+ unsigned n = (y < 0) ? -y : y;
+ double p = 1;
+ while (n != 0) {
+ if ((n & 1) != 0) p *= m;
+ m *= m;
+ if ((n & 2) != 0) p *= m;
+ m *= m;
+ n >>= 2;
+ }
+ return p;
+}
+
+
+double power_double_double(double x, double y) {
+ int y_int = static_cast<int>(y);
+ if (y == y_int) {
+ return power_double_int(x, y_int); // Returns 1.0 for exponent 0.
+ }
+ if (!isinf(x)) {
+ if (y == 0.5) return sqrt(x);
+ if (y == -0.5) return 1.0 / sqrt(x);
+ }
+ if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
+ return OS::nan_value();
+ }
+ return pow(x, y);
+}
+
+
+ExternalReference ExternalReference::power_double_double_function() {
+ return ExternalReference(Redirect(FUNCTION_ADDR(power_double_double)));
+}
+
+
+ExternalReference ExternalReference::power_double_int_function() {
+ return ExternalReference(Redirect(FUNCTION_ADDR(power_double_int)));
+}
+
+
static int native_compare_doubles(double y, double x) {
if (x == y) return EQUAL;
return x < y ? LESS : GREATER;
public:
static const double min_int;
static const double one_half;
+ static const double negative_infinity;
};
static ExternalReference double_fp_operation(Token::Value operation);
static ExternalReference compare_doubles();
+ static ExternalReference power_double_double_function();
+ static ExternalReference power_double_int_function();
static ExternalReference handle_scope_next_address();
static ExternalReference handle_scope_limit_address();
// Static variables containing common double constants.
static ExternalReference address_of_min_int();
static ExternalReference address_of_one_half();
+ static ExternalReference address_of_negative_infinity();
Address address() const {return reinterpret_cast<Address>(address_);}
return num_bits_set;
}
+// Computes pow(x, y) with the special cases in the spec for Math.pow.
+double power_double_int(double x, int y);
+double power_double_double(double x, double y);
+
} } // namespace v8::internal
#endif // V8_ASSEMBLER_H_
// HLoadKeyedFastElement
// HLoadKeyedGeneric
// HLoadNamedGeneric
+// HPower
// HStoreNamed
// HStoreNamedField
// HStoreNamedGeneric
V(ObjectLiteral) \
V(OsrEntry) \
V(Parameter) \
+ V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
V(Return) \
SetFlag(kFlexibleRepresentation);
break;
case kMathSqrt:
+ case kMathPowHalf:
default:
set_representation(Representation::Double());
}
case kMathRound:
case kMathCeil:
case kMathSqrt:
+ case kMathPowHalf:
return Representation::Double();
break;
case kMathAbs:
};
+class HPower: public HBinaryOperation {
+ public:
+ HPower(HValue* left, HValue* right)
+ : HBinaryOperation(left, right) {
+ set_representation(Representation::Double());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ return (index == 1) ? Representation::None() : Representation::Double();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(Power, "power")
+};
+
+
class HAdd: public HArithmeticBinaryOperation {
public:
HAdd(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {
return true;
}
break;
+ case kMathPow:
+ if (argument_count == 3) {
+ HValue* right = Pop();
+ HValue* left = Pop();
+ Pop(); // Pop receiver.
+ // Use sqrt() if exponent is 0.5 or -0.5.
+ if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
+ double exponent = HConstant::cast(right)->DoubleValue();
+ if (exponent == 0.5) {
+ PushAndAdd(new HUnaryMathOperation(left, kMathPowHalf));
+ return true;
+ } else if (exponent == -0.5) {
+ HConstant* double_one =
+ new HConstant(Handle<Object>(Smi::FromInt(1)),
+ Representation::Double());
+ AddInstruction(double_one);
+ HUnaryMathOperation* square_root =
+ new HUnaryMathOperation(left, kMathPowHalf);
+ AddInstruction(square_root);
+ PushAndAdd(new HDiv(double_one, square_root));
+ return true;
+ } else if (exponent == 2.0) {
+ PushAndAdd(new HMul(left, left));
+ return true;
+ }
+ } else if (right->IsConstant() &&
+ HConstant::cast(right)->HasInteger32Value() &&
+ HConstant::cast(right)->Integer32Value() == 2) {
+ PushAndAdd(new HMul(left, left));
+ return true;
+ }
+
+ PushAndAdd(new HPower(left, right));
+ return true;
+ }
+ break;
default:
// Either not a special math function or not yet supported for inlining.
break;
// Fast call to math functions.
void HGraphBuilder::GenerateMathPow(int argument_count) {
ASSERT_EQ(2, argument_count);
- PushArgumentsForStubCall(argument_count);
- PushAndAdd(new HCallStub(CodeStub::MathPow, argument_count),
- RelocInfo::kNoPosition);
+ HValue* right = Pop();
+ HValue* left = Pop();
+ PushAndAdd(new HPower(left, right));
}
}
+void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
+ XMMRegister xmm_scratch = xmm0;
+ XMMRegister input_reg = ToDoubleRegister(instr->input());
+ ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
+ ExternalReference negative_infinity =
+ ExternalReference::address_of_negative_infinity();
+ __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity));
+ __ ucomisd(xmm_scratch, input_reg);
+ DeoptimizeIf(equal, instr->environment());
+ __ sqrtsd(input_reg, input_reg);
+}
+
+
+void LCodeGen::DoPower(LPower* instr) {
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
+ Representation exponent_type = instr->hydrogen()->right()->representation();
+ if (exponent_type.IsDouble()) {
+ // Pass two doubles as arguments on the stack.
+ __ PrepareCallCFunction(4, eax);
+ __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
+ __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
+ __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+ } else if (exponent_type.IsInteger32()) {
+ __ PrepareCallCFunction(4, ebx);
+ __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
+ __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
+ __ CallCFunction(ExternalReference::power_double_int_function(), 4);
+ } else {
+ ASSERT(exponent_type.IsTagged());
+ __ PrepareCallCFunction(4, ebx);
+ __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
+ Register right_reg = ToRegister(right);
+ Label non_smi;
+ Label done;
+ __ test(right_reg, Immediate(kSmiTagMask));
+ __ j(not_zero, &non_smi);
+ __ SmiUntag(right_reg);
+ __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
+ __ CallCFunction(ExternalReference::power_double_int_function(), 4);
+ __ jmp(&done);
+
+ __ bind(&non_smi);
+ __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
+ DeoptimizeIf(not_equal, instr->environment());
+ __ movdbl(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset));
+ __ movdbl(Operand(esp, 1 * kDoubleSize), xmm1);
+ __ CallCFunction(ExternalReference::power_double_double_function(), 4);
+
+ __ bind(&done);
+ }
+
+ // Return value is in st(0) on ia32.
+ // Store it into the (fixed) result register.
+ __ sub(Operand(esp), Immediate(kDoubleSize));
+ __ fstp_d(Operand(esp, 0));
+ __ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0));
+ __ add(Operand(esp), Immediate(kDoubleSize));
+}
+
+
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
switch (instr->op()) {
case kMathAbs:
case kMathSqrt:
DoMathSqrt(instr);
break;
+ case kMathPowHalf:
+ DoMathPowHalf(instr);
+ break;
default:
UNREACHABLE();
}
void DoMathFloor(LUnaryMathOperation* instr);
void DoMathRound(LUnaryMathOperation* instr);
void DoMathSqrt(LUnaryMathOperation* instr);
+ void DoMathPowHalf(LUnaryMathOperation* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
return AssignEnvironment(DefineAsRegister(result));
case kMathSqrt:
return DefineSameAsFirst(result);
+ case kMathPowHalf:
+ return AssignEnvironment(DefineSameAsFirst(result));
default:
UNREACHABLE();
return NULL;
}
+LInstruction* LChunkBuilder::DoPower(HPower* instr) {
+ ASSERT(instr->representation().IsDouble());
+ // We call a C function for double power. It can't trigger a GC.
+ // We need to use fixed result register for the call.
+ Representation exponent_type = instr->right()->representation();
+ ASSERT(instr->left()->representation().IsDouble());
+ LOperand* left = UseFixedDouble(instr->left(), xmm1);
+ LOperand* right = exponent_type.IsDouble() ?
+ UseFixedDouble(instr->right(), xmm2) :
+ UseFixed(instr->right(), eax);
+ LPower* result = new LPower(left, right);
+ return MarkAsCall(DefineFixedDouble(result, xmm1), instr,
+ CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
Token::Value op = instr->token();
if (instr->left()->representation().IsInteger32()) {
// LLoadKeyedGeneric
// LModI
// LMulI
+// LPower
// LShiftI
// LSubI
// LCallConstantFunction
V(ObjectLiteral) \
V(OsrEntry) \
V(Parameter) \
+ V(Power) \
V(PushArgument) \
V(RegExpLiteral) \
V(Return) \
};
+class LPower: public LBinaryOperation {
+ public:
+ LPower(LOperand* left, LOperand* right)
+ : LBinaryOperation(left, right) { }
+
+ DECLARE_CONCRETE_INSTRUCTION(Power, "power")
+ DECLARE_HYDROGEN_ACCESSOR(Power)
+};
+
+
class LArithmeticD: public LBinaryOperation {
public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
%SetMathFunctionId($Math.round, 2);
%SetMathFunctionId($Math.abs, 4);
%SetMathFunctionId($Math.sqrt, 0xd);
+ %SetMathFunctionId($Math.pow, 0xe);
// TODO(erikcorry): Set the id of the other functions so they can be
// optimized.
};
kMathACos = 0xa,
kMathATan = 0xb,
kMathExp = 0xc,
- kMathSqrt = 0xd
+ kMathSqrt = 0xd,
+ kMathPow = 0xe,
+ kMathPowHalf = 0xf
};
static const int kTryFullCodegen = 1;
static const int kAllowLazyCompilation = 2;
static const int kMathFunctionShift = 3;
- static const int kMathFunctionMask = 0xf;
- static const int kLiveObjectsMayExist = 7;
- static const int kCodeAgeShift = 8;
+ static const int kMathFunctionMask = 0x1f;
+ static const int kLiveObjectsMayExist = 8;
+ static const int kCodeAgeShift = 9;
static const int kCodeAgeMask = 0x7;
- static const int kOptimizationDisabled = 11;
+ static const int kOptimizationDisabled = 12;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};
}
-// 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
-// S. Warren, Jr., figure 11-6, page 213.
-static double powi(double x, int y) {
- ASSERT(y != kMinInt);
- unsigned n = (y < 0) ? -y : y;
- double m = x;
- double p = 1;
- while (true) {
- if ((n & 1) != 0) p *= m;
- n >>= 1;
- if (n == 0) {
- if (y < 0) {
- // Unfortunately, we have to be careful when p has reached
- // infinity in the computation, because sometimes the higher
- // internal precision in the pow() implementation would have
- // given us a finite p. This happens very rarely.
- double result = 1.0 / p;
- return (result == 0 && isinf(p))
- ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
- : result;
- } else {
- return p;
- }
- }
- m *= m;
- }
-}
-
-
static MaybeObject* Runtime_Math_pow(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
// custom powi() function than the generic pow().
if (args[1]->IsSmi()) {
int y = Smi::cast(args[1])->value();
- return Heap::NumberFromDouble(powi(x, y));
+ return Heap::NumberFromDouble(power_double_int(x, y));
}
CONVERT_DOUBLE_CHECKED(y, args[1]);
-
- if (!isinf(x)) {
- if (y == 0.5) {
- // It's not uncommon to use Math.pow(x, 0.5) to compute the
- // square root of a number. To speed up such computations, we
- // explictly check for this case and use the sqrt() function
- // which is faster than pow().
- return Heap::AllocateHeapNumber(sqrt(x));
- } else if (y == -0.5) {
- // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
- return Heap::AllocateHeapNumber(1.0 / sqrt(x));
- }
- }
-
- if (y == 0) {
- return Smi::FromInt(1);
- } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
- return Heap::nan_value();
- } else {
- return Heap::AllocateHeapNumber(pow(x, y));
- }
+ return Heap::AllocateHeapNumber(power_double_double(x, y));
}
// Fast version of Math.pow if we know that y is not an integer and
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
if (y == 0) {
- return Smi::FromInt(1);
+ return Smi::FromInt(1);
} else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
- return Heap::nan_value();
+ return Heap::nan_value();
} else {
- return Heap::AllocateHeapNumber(pow(x, y));
+ return Heap::AllocateHeapNumber(pow(x, y));
}
}
UNCLASSIFIED,
36,
"LDoubleConstant::one_half");
+ Add(ExternalReference::address_of_negative_infinity().address(),
+ UNCLASSIFIED,
+ 37,
+ "LDoubleConstant::negative_infinity");
+ Add(ExternalReference::power_double_double_function().address(),
+ UNCLASSIFIED,
+ 38,
+ "power_double_double_function");
+ Add(ExternalReference::power_double_int_function().address(),
+ UNCLASSIFIED,
+ 39,
+ "power_double_int_function");
}