Inline Math.sqrt().
Also changed name of GeneratePow and the %_ call name to follow convention based on MathSin and MathCos. Moved GeneratePow down to the other methods. Review URL: http://codereview.chromium.org/661179 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4054 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d2fbf9436e
commit
b60eba5fc5
@ -381,9 +381,10 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
|
||||
{&CodeGenerator::GenerateStringCompare, "_StringCompare"},
|
||||
{&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
|
||||
{&CodeGenerator::GenerateNumberToString, "_NumberToString"},
|
||||
{&CodeGenerator::GeneratePow, "_Pow"},
|
||||
{&CodeGenerator::GenerateMathPow, "_Math_pow"},
|
||||
{&CodeGenerator::GenerateMathSin, "_Math_sin"},
|
||||
{&CodeGenerator::GenerateMathCos, "_Math_cos"},
|
||||
{&CodeGenerator::GenerateMathSqrt, "_Math_sqrt"},
|
||||
};
|
||||
|
||||
|
||||
|
@ -5445,182 +5445,6 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
// Generates the Math.pow method - only handles special cases and branches to
|
||||
// the runtime system if not. Uses eax to store result and as temporary reg.
|
||||
void CodeGenerator::GeneratePow(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 2);
|
||||
if (CpuFeatures::IsSupported(SSE2)) {
|
||||
CpuFeatures::Scope use_sse2(SSE2);
|
||||
Load(args->at(0));
|
||||
Load(args->at(1));
|
||||
Label go_runtime;
|
||||
Label return_preg;
|
||||
Result p = allocator()->Allocate(eax);
|
||||
Result y = frame_->Pop();
|
||||
Result x= frame_->Pop();
|
||||
if (p.is_valid() && p.reg().is(eax)) {
|
||||
x.ToRegister();
|
||||
y.ToRegister();
|
||||
frame_->Spill(x.reg());
|
||||
frame_->Spill(y.reg());
|
||||
ASSERT(x.is_valid());
|
||||
ASSERT(y.is_valid());
|
||||
|
||||
// Save 1 in xmm3 - we need this several times later on
|
||||
__ mov(p.reg(), Immediate(1));
|
||||
__ cvtsi2sd(xmm3, Operand(p.reg()));
|
||||
|
||||
Label y_nonsmi;
|
||||
Label x_is_double;
|
||||
// If y is a heap number go to that specific case.
|
||||
__ test(y.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &y_nonsmi);
|
||||
__ test(x.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &x_is_double);
|
||||
|
||||
// Bot numbers are smis.
|
||||
Label powi;
|
||||
__ SmiUntag(x.reg());
|
||||
__ cvtsi2sd(xmm0, Operand(x.reg()));
|
||||
__ jmp(&powi);
|
||||
// Y is smi and x is a double.
|
||||
__ bind(&x_is_double);
|
||||
__ cmp(FieldOperand(x.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
__ j(not_equal, &go_runtime);
|
||||
__ movdbl(xmm0, FieldOperand(x.reg(), HeapNumber::kValueOffset));
|
||||
|
||||
__ bind(&powi);
|
||||
__ SmiUntag(y.reg());
|
||||
|
||||
// Save y in x as we need to check if y is negative later.
|
||||
__ mov(x.reg(), y.reg());
|
||||
|
||||
|
||||
// Get absolute value of y.
|
||||
Label no_neg;
|
||||
__ cmp(y.reg(), 0);
|
||||
__ j(greater_equal, &no_neg);
|
||||
__ neg(y.reg());
|
||||
__ bind(&no_neg);
|
||||
|
||||
// Optimized version of pow if y is an integer.
|
||||
// Load xmm1 with 1.
|
||||
__ movsd(xmm1, xmm3);
|
||||
Label while_true;
|
||||
Label no_multiply;
|
||||
Label powi_done;
|
||||
Label allocate_and_return;
|
||||
__ bind(&while_true);
|
||||
__ shr(y.reg(), 1);
|
||||
__ j(not_carry, &no_multiply);
|
||||
__ mulsd(xmm1, xmm0);
|
||||
__ bind(&no_multiply);
|
||||
__ test(y.reg(), Operand(y.reg()));
|
||||
__ mulsd(xmm0, xmm0);
|
||||
__ j(not_zero, &while_true);
|
||||
|
||||
__ bind(&powi_done);
|
||||
// x has the original value of y - if y is negative return 1/result.
|
||||
__ test(x.reg(), Operand(x.reg()));
|
||||
__ j(positive, &allocate_and_return);
|
||||
// Special case if xmm1 has reached infinity
|
||||
__ mov(p.reg(), Immediate(0x7FB00000));
|
||||
__ movd(xmm0, Operand(p.reg()));
|
||||
__ cvtss2sd(xmm0, xmm0);
|
||||
__ ucomisd(xmm0, xmm1);
|
||||
__ j(equal, &go_runtime);
|
||||
__ divsd(xmm3, xmm1);
|
||||
__ movsd(xmm1, xmm3);
|
||||
__ jmp(&allocate_and_return);
|
||||
|
||||
// y (or both) is a double - no matter what we should now work
|
||||
// on doubles.
|
||||
__ bind(&y_nonsmi);
|
||||
__ cmp(FieldOperand(y.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
__ j(not_equal, &go_runtime);
|
||||
// Y must be a double.
|
||||
__ movdbl(xmm1, FieldOperand(y.reg(), HeapNumber::kValueOffset));
|
||||
// Test if y is nan.
|
||||
__ ucomisd(xmm1, xmm1);
|
||||
__ j(parity_even, &go_runtime);
|
||||
|
||||
Label x_not_smi;
|
||||
Label handle_special_cases;
|
||||
__ test(x.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &x_not_smi);
|
||||
__ SmiUntag(x.reg());
|
||||
__ cvtsi2sd(xmm0, Operand(x.reg()));
|
||||
__ jmp(&handle_special_cases);
|
||||
__ bind(&x_not_smi);
|
||||
__ cmp(FieldOperand(x.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
__ j(not_equal, &go_runtime);
|
||||
__ mov(p.reg(), FieldOperand(x.reg(), HeapNumber::kExponentOffset));
|
||||
__ and_(p.reg(), HeapNumber::kExponentMask);
|
||||
__ cmp(Operand(p.reg()), Immediate(HeapNumber::kExponentMask));
|
||||
// x is NaN or +/-Infinity
|
||||
__ j(greater_equal, &go_runtime);
|
||||
__ movdbl(xmm0, FieldOperand(x.reg(), HeapNumber::kValueOffset));
|
||||
|
||||
// x is in xmm0 and y is in xmm1.
|
||||
__ bind(&handle_special_cases);
|
||||
Label not_minus_half;
|
||||
// Test for -0.5.
|
||||
// Load xmm2 with -0.5.
|
||||
__ mov(p.reg(), Immediate(0xBF000000));
|
||||
__ movd(xmm2, Operand(p.reg()));
|
||||
__ cvtss2sd(xmm2, xmm2);
|
||||
// xmm2 now has -0.5.
|
||||
__ ucomisd(xmm2, xmm1);
|
||||
__ j(not_equal, ¬_minus_half);
|
||||
|
||||
// Calculates reciprocal of square root.
|
||||
// Note that 1/sqrt(x) = sqrt(1/x))
|
||||
__ divsd(xmm3, xmm0);
|
||||
__ movsd(xmm1, xmm3);
|
||||
__ sqrtsd(xmm1, xmm1);
|
||||
__ jmp(&allocate_and_return);
|
||||
|
||||
// Test for 0.5.
|
||||
__ bind(¬_minus_half);
|
||||
// Load xmm2 with 0.5.
|
||||
// Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 = xmm3
|
||||
__ addsd(xmm2, xmm3);
|
||||
// xmm2 now has 0.5.
|
||||
__ ucomisd(xmm2, xmm1);
|
||||
__ j(not_equal, &go_runtime);
|
||||
// Calculates square root.
|
||||
__ movsd(xmm1, xmm0);
|
||||
__ sqrtsd(xmm1, xmm1);
|
||||
|
||||
__ bind(&allocate_and_return);
|
||||
__ AllocateHeapNumber(p.reg(), y.reg(), x.reg(), &go_runtime);
|
||||
__ movdbl(FieldOperand(p.reg(), HeapNumber::kValueOffset), xmm1);
|
||||
__ jmp(&return_preg);
|
||||
}
|
||||
__ bind(&go_runtime);
|
||||
x.Unuse();
|
||||
y.Unuse();
|
||||
p.Unuse();
|
||||
Load(args->at(0));
|
||||
Load(args->at(1));
|
||||
frame_->CallRuntime(Runtime::kMath_pow_cfunction, 2);
|
||||
|
||||
// Since we store the result in p.reg() which is eax - return this value.
|
||||
// If we called runtime the result is also in eax.
|
||||
__ bind(&return_preg);
|
||||
frame_->Push(eax);
|
||||
} else { // Simply call runtime.
|
||||
Load(args->at(0));
|
||||
Load(args->at(1));
|
||||
Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
|
||||
frame_->Push(&res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This generates code that performs a charCodeAt() call or returns
|
||||
// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
|
||||
// It can handle flat, 8 and 16 bit characters and cons strings where the
|
||||
@ -6209,6 +6033,194 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
// Generates the Math.pow method - only handles special cases and branches to
|
||||
// the runtime system if not.Please note - this function assumes that
|
||||
// the callsite has executed ToNumber on both arguments and that the
|
||||
// arguments are not the same identifier.
|
||||
void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 2);
|
||||
Load(args->at(0));
|
||||
Load(args->at(1));
|
||||
if (!CpuFeatures::IsSupported(SSE2)) {
|
||||
Result res = frame_->CallRuntime(Runtime::kMath_pow, 2);
|
||||
frame_->Push(&res);
|
||||
} else {
|
||||
CpuFeatures::Scope use_sse2(SSE2);
|
||||
Label allocate_return;
|
||||
// Load the two operands while leaving the values on the frame.
|
||||
frame()->Dup();
|
||||
Result exponent = frame()->Pop();
|
||||
exponent.ToRegister();
|
||||
frame()->Spill(exponent.reg());
|
||||
frame()->PushElementAt(1);
|
||||
Result base = frame()->Pop();
|
||||
base.ToRegister();
|
||||
frame()->Spill(base.reg());
|
||||
|
||||
Result answer = allocator()->Allocate();
|
||||
ASSERT(answer.is_valid());
|
||||
// We can safely assume that the base and exponent is not in the same
|
||||
// register since we only call this from one callsite (math.js).
|
||||
ASSERT(!exponent.reg().is(base.reg()));
|
||||
JumpTarget call_runtime;
|
||||
|
||||
// Save 1 in xmm3 - we need this several times later on.
|
||||
__ mov(answer.reg(), Immediate(1));
|
||||
__ cvtsi2sd(xmm3, Operand(answer.reg()));
|
||||
|
||||
Label exponent_nonsmi;
|
||||
Label base_nonsmi;
|
||||
// If the exponent is a heap number go to that specific case.
|
||||
__ test(exponent.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &exponent_nonsmi);
|
||||
__ test(base.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &base_nonsmi);
|
||||
|
||||
// Optimized version when y is an integer.
|
||||
Label powi;
|
||||
__ SmiUntag(base.reg());
|
||||
__ cvtsi2sd(xmm0, Operand(base.reg()));
|
||||
__ jmp(&powi);
|
||||
// exponent is smi and base is a heapnumber.
|
||||
__ bind(&base_nonsmi);
|
||||
__ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
call_runtime.Branch(not_equal);
|
||||
|
||||
__ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset));
|
||||
|
||||
// Optimized version of pow if y is an integer.
|
||||
__ bind(&powi);
|
||||
__ SmiUntag(exponent.reg());
|
||||
|
||||
// Save exponent in base as we need to check if exponent is negative later.
|
||||
// We know that base and exponent are in different registers.
|
||||
__ mov(base.reg(), exponent.reg());
|
||||
|
||||
// Get absolute value of exponent.
|
||||
Label no_neg;
|
||||
__ cmp(exponent.reg(), 0);
|
||||
__ j(greater_equal, &no_neg);
|
||||
__ neg(exponent.reg());
|
||||
__ bind(&no_neg);
|
||||
|
||||
// Load xmm1 with 1.
|
||||
__ movsd(xmm1, xmm3);
|
||||
Label while_true;
|
||||
Label no_multiply;
|
||||
|
||||
// Label allocate_and_return;
|
||||
__ bind(&while_true);
|
||||
__ shr(exponent.reg(), 1);
|
||||
__ j(not_carry, &no_multiply);
|
||||
__ mulsd(xmm1, xmm0);
|
||||
__ bind(&no_multiply);
|
||||
__ test(exponent.reg(), Operand(exponent.reg()));
|
||||
__ mulsd(xmm0, xmm0);
|
||||
__ j(not_zero, &while_true);
|
||||
|
||||
// x has the original value of y - if y is negative return 1/result.
|
||||
__ test(base.reg(), Operand(base.reg()));
|
||||
__ j(positive, &allocate_return);
|
||||
// Special case if xmm1 has reached infinity.
|
||||
__ mov(answer.reg(), Immediate(0x7FB00000));
|
||||
__ movd(xmm0, Operand(answer.reg()));
|
||||
__ cvtss2sd(xmm0, xmm0);
|
||||
__ ucomisd(xmm0, xmm1);
|
||||
call_runtime.Branch(equal);
|
||||
__ divsd(xmm3, xmm1);
|
||||
__ movsd(xmm1, xmm3);
|
||||
__ jmp(&allocate_return);
|
||||
|
||||
// exponent (or both) is a heapnumber - no matter what we should now work
|
||||
// on doubles.
|
||||
__ bind(&exponent_nonsmi);
|
||||
__ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
call_runtime.Branch(not_equal);
|
||||
__ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset));
|
||||
// Test if exponent is nan.
|
||||
__ ucomisd(xmm1, xmm1);
|
||||
call_runtime.Branch(parity_even);
|
||||
|
||||
Label base_not_smi;
|
||||
Label handle_special_cases;
|
||||
__ test(base.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &base_not_smi);
|
||||
__ SmiUntag(base.reg());
|
||||
__ cvtsi2sd(xmm0, Operand(base.reg()));
|
||||
__ jmp(&handle_special_cases);
|
||||
__ bind(&base_not_smi);
|
||||
__ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
call_runtime.Branch(not_equal);
|
||||
__ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset));
|
||||
__ and_(answer.reg(), HeapNumber::kExponentMask);
|
||||
__ cmp(Operand(answer.reg()), Immediate(HeapNumber::kExponentMask));
|
||||
// base is NaN or +/-Infinity
|
||||
call_runtime.Branch(greater_equal);
|
||||
__ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset));
|
||||
|
||||
// base is in xmm0 and exponent is in xmm1.
|
||||
__ bind(&handle_special_cases);
|
||||
Label not_minus_half;
|
||||
// Test for -0.5.
|
||||
// Load xmm2 with -0.5.
|
||||
__ mov(answer.reg(), Immediate(0xBF000000));
|
||||
__ movd(xmm2, Operand(answer.reg()));
|
||||
__ cvtss2sd(xmm2, xmm2);
|
||||
// xmm2 now has -0.5.
|
||||
__ ucomisd(xmm2, xmm1);
|
||||
__ j(not_equal, ¬_minus_half);
|
||||
|
||||
// Calculates reciprocal of square root.
|
||||
// Note that 1/sqrt(x) = sqrt(1/x))
|
||||
__ divsd(xmm3, xmm0);
|
||||
__ movsd(xmm1, xmm3);
|
||||
__ sqrtsd(xmm1, xmm1);
|
||||
__ jmp(&allocate_return);
|
||||
|
||||
// Test for 0.5.
|
||||
__ bind(¬_minus_half);
|
||||
// Load xmm2 with 0.5.
|
||||
// Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3.
|
||||
__ addsd(xmm2, xmm3);
|
||||
// xmm2 now has 0.5.
|
||||
__ comisd(xmm2, xmm1);
|
||||
call_runtime.Branch(not_equal);
|
||||
// Calculates square root.
|
||||
__ movsd(xmm1, xmm0);
|
||||
__ sqrtsd(xmm1, xmm1);
|
||||
|
||||
JumpTarget done;
|
||||
Label failure, success;
|
||||
__ bind(&allocate_return);
|
||||
// Make a copy of the frame to enable us to handle allocation
|
||||
// failure after the JumpTarget jump.
|
||||
VirtualFrame* clone = new VirtualFrame(frame());
|
||||
__ AllocateHeapNumber(answer.reg(), exponent.reg(),
|
||||
base.reg(), &failure);
|
||||
__ movdbl(FieldOperand(answer.reg(), HeapNumber::kValueOffset), xmm1);
|
||||
// Remove the two original values from the frame - we only need those
|
||||
// in the case where we branch to runtime.
|
||||
frame()->Drop(2);
|
||||
exponent.Unuse();
|
||||
base.Unuse();
|
||||
done.Jump(&answer);
|
||||
// Use the copy of the original frame as our current frame.
|
||||
RegisterFile empty_regs;
|
||||
SetFrame(clone, &empty_regs);
|
||||
// If we experience an allocation failure we branch to runtime.
|
||||
__ bind(&failure);
|
||||
call_runtime.Bind();
|
||||
answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2);
|
||||
|
||||
done.Bind(&answer);
|
||||
frame()->Push(&answer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
|
||||
ASSERT_EQ(args->length(), 1);
|
||||
Load(args->at(0));
|
||||
@ -6227,6 +6239,63 @@ void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
// Generates the Math.sqrt method. Please note - this function assumes that
|
||||
// the callsite has executed ToNumber on the argument.
|
||||
void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
|
||||
ASSERT_EQ(args->length(), 1);
|
||||
Load(args->at(0));
|
||||
|
||||
if (!CpuFeatures::IsSupported(SSE2)) {
|
||||
Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1);
|
||||
frame()->Push(&result);
|
||||
} else {
|
||||
CpuFeatures::Scope use_sse2(SSE2);
|
||||
// Leave original value on the frame if we need to call runtime.
|
||||
frame()->Dup();
|
||||
Result result = frame()->Pop();
|
||||
result.ToRegister();
|
||||
frame()->Spill(result.reg());
|
||||
Label runtime;
|
||||
Label non_smi;
|
||||
Label load_done;
|
||||
JumpTarget end;
|
||||
|
||||
__ test(result.reg(), Immediate(kSmiTagMask));
|
||||
__ j(not_zero, &non_smi);
|
||||
__ SmiUntag(result.reg());
|
||||
__ cvtsi2sd(xmm0, Operand(result.reg()));
|
||||
__ jmp(&load_done);
|
||||
__ bind(&non_smi);
|
||||
__ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset),
|
||||
Factory::heap_number_map());
|
||||
__ j(not_equal, &runtime);
|
||||
__ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset));
|
||||
|
||||
__ bind(&load_done);
|
||||
__ sqrtsd(xmm0, xmm0);
|
||||
// A copy of the virtual frame to allow us to go to runtime after the
|
||||
// JumpTarget jump.
|
||||
Result scratch = allocator()->Allocate();
|
||||
VirtualFrame* clone = new VirtualFrame(frame());
|
||||
__ AllocateHeapNumber(result.reg(), scratch.reg(), no_reg, &runtime);
|
||||
|
||||
__ movdbl(FieldOperand(result.reg(), HeapNumber::kValueOffset), xmm0);
|
||||
frame()->Drop(1);
|
||||
scratch.Unuse();
|
||||
end.Jump(&result);
|
||||
// We only branch to runtime if we have an allocation error.
|
||||
// Use the copy of the original frame as our current frame.
|
||||
RegisterFile empty_regs;
|
||||
SetFrame(clone, &empty_regs);
|
||||
__ bind(&runtime);
|
||||
result = frame()->CallRuntime(Runtime::kMath_sqrt, 1);
|
||||
|
||||
end.Bind(&result);
|
||||
frame()->Push(&result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
||||
if (CheckForInlineRuntimeCall(node)) {
|
||||
return;
|
||||
|
@ -594,12 +594,15 @@ class CodeGenerator: public AstVisitor {
|
||||
void GenerateNumberToString(ZoneList<Expression*>* args);
|
||||
|
||||
// Fast support for Math.pow().
|
||||
void GeneratePow(ZoneList<Expression*>* args);
|
||||
void GenerateMathPow(ZoneList<Expression*>* args);
|
||||
|
||||
// Fast call to transcendental functions.
|
||||
void GenerateMathSin(ZoneList<Expression*>* args);
|
||||
void GenerateMathCos(ZoneList<Expression*>* args);
|
||||
|
||||
// Fast case for sqrt
|
||||
void GenerateMathSqrt(ZoneList<Expression*>* args);
|
||||
|
||||
// Simple condition analysis.
|
||||
enum ConditionAnalysis {
|
||||
ALWAYS_TRUE,
|
||||
|
@ -159,7 +159,7 @@ function MathMin(arg1, arg2) { // length == 2
|
||||
function MathPow(x, y) {
|
||||
if (!IS_NUMBER(x)) x = ToNumber(x);
|
||||
if (!IS_NUMBER(y)) y = ToNumber(y);
|
||||
return %_Pow(x, y);
|
||||
return %_Math_pow(x, y);
|
||||
}
|
||||
|
||||
// ECMA 262 - 15.8.2.14
|
||||
@ -182,7 +182,7 @@ function MathSin(x) {
|
||||
// ECMA 262 - 15.8.2.17
|
||||
function MathSqrt(x) {
|
||||
if (!IS_NUMBER(x)) x = ToNumber(x);
|
||||
return %Math_sqrt(x);
|
||||
return %_Math_sqrt(x);
|
||||
}
|
||||
|
||||
// ECMA 262 - 15.8.2.18
|
||||
|
44
test/mjsunit/math-sqrt.js
Normal file
44
test/mjsunit/math-sqrt.js
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Tests the special cases specified by ES 15.8.2.17
|
||||
|
||||
// Simple sanity check
|
||||
assertEquals(2, Math.sqrt(4));
|
||||
assertEquals(0.1, Math.sqrt(0.01));
|
||||
|
||||
// Spec tests
|
||||
assertEquals(NaN, Math.sqrt(NaN));
|
||||
assertEquals(NaN, Math.sqrt(-1));
|
||||
assertEquals(+0, Math.sqrt(+0));
|
||||
assertEquals(-0, Math.sqrt(-0));
|
||||
assertEquals(Infinity, Math.sqrt(Infinity));
|
||||
// -Infinity is smaller than 0 so it should return NaN
|
||||
assertEquals(NaN, Math.sqrt(-Infinity));
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user