Commit 5ce562cd authored by yangguo@chromium.org's avatar yangguo@chromium.org

Reland r10908 (Ensure consistent result of transcendental function0.)

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9583037

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10915 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4279f873
......@@ -37,6 +37,19 @@ namespace internal {
#define __ ACCESS_MASM(masm)
TranscendentalFunction CreateTranscendentalFunction(
TranscendentalCache::Type type) {
switch (type) {
case TranscendentalCache::SIN: return &sin;
case TranscendentalCache::COS: return &cos;
case TranscendentalCache::TAN: return &tan;
case TranscendentalCache::LOG: return &log;
default: UNIMPLEMENTED();
}
return NULL;
}
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
......
......@@ -1170,7 +1170,7 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
if (op == kMathLog || op == kMathSin || op == kMathCos) {
if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* input = UseFixedDouble(instr->value(), d2);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
return MarkAsCall(DefineFixedDouble(result, d2), instr);
......
......@@ -84,6 +84,15 @@ enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
namespace v8 {
namespace internal {
// Results of the library implementation of transcendental functions may differ
// from the one we use in our generated code. Therefore we use the same
// generated code both in runtime and compiled code.
typedef double (*TranscendentalFunction)(double x);
TranscendentalFunction CreateTranscendentalFunction(
TranscendentalCache::Type type);
class ElementsTransitionGenerator : public AllStatic {
public:
static void GenerateSmiOnlyToObject(MacroAssembler* masm);
......
......@@ -32,6 +32,7 @@
#include "isolate.h"
#include "list-inl.h"
#include "objects.h"
#include "platform.h"
#include "v8-counters.h"
#include "store-buffer.h"
#include "store-buffer-inl.h"
......@@ -658,15 +659,15 @@ double TranscendentalCache::SubCache::Calculate(double input) {
case ATAN:
return atan(input);
case COS:
return cos(input);
return fast_cos(input);
case EXP:
return exp(input);
case LOG:
return log(input);
return fast_log(input);
case SIN:
return sin(input);
return fast_sin(input);
case TAN:
return tan(input);
return fast_tan(input);
default:
return 0.0; // Never happens.
}
......
......@@ -1886,6 +1886,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
case kMathLog:
case kMathSin:
case kMathCos:
case kMathTan:
set_representation(Representation::Double());
break;
default:
......@@ -1916,6 +1917,7 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
case kMathLog:
case kMathSin:
case kMathCos:
case kMathTan:
return Representation::Double();
case kMathAbs:
return representation();
......
......@@ -5420,6 +5420,7 @@ bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) {
case kMathLog:
case kMathSin:
case kMathCos:
case kMathTan:
if (expr->arguments()->length() == 1) {
HValue* argument = Pop();
HValue* context = environment()->LookupContext();
......@@ -5480,6 +5481,7 @@ bool HGraphBuilder::TryInlineBuiltinMethodCall(Call* expr,
case kMathLog:
case kMathSin:
case kMathCos:
case kMathTan:
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* argument = Pop();
......
......@@ -2510,7 +2510,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ fld_d(Operand(esp, 0));
__ add(esp, Immediate(kDoubleSize));
}
GenerateOperation(masm);
GenerateOperation(masm, type_);
__ mov(Operand(ecx, 0), ebx);
__ mov(Operand(ecx, kIntSize), edx);
__ mov(Operand(ecx, 2 * kIntSize), eax);
......@@ -2526,7 +2526,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ sub(esp, Immediate(kDoubleSize));
__ movdbl(Operand(esp, 0), xmm1);
__ fld_d(Operand(esp, 0));
GenerateOperation(masm);
GenerateOperation(masm, type_);
__ fstp_d(Operand(esp, 0));
__ movdbl(xmm1, Operand(esp, 0));
__ add(esp, Immediate(kDoubleSize));
......@@ -2578,14 +2578,15 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
}
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
void TranscendentalCacheStub::GenerateOperation(
MacroAssembler* masm, TranscendentalCache::Type type) {
// Only free register is edi.
// Input value is on FP stack, and also in ebx/edx.
// Input value is possibly in xmm1.
// Address of result (a newly allocated HeapNumber) may be in eax.
if (type_ == TranscendentalCache::SIN ||
type_ == TranscendentalCache::COS ||
type_ == TranscendentalCache::TAN) {
if (type == TranscendentalCache::SIN ||
type == TranscendentalCache::COS ||
type == TranscendentalCache::TAN) {
// Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation.
......@@ -2649,7 +2650,7 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
// FPU Stack: input % 2*pi
__ bind(&in_range);
switch (type_) {
switch (type) {
case TranscendentalCache::SIN:
__ fsin();
break;
......@@ -2667,7 +2668,7 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
}
__ bind(&done);
} else {
ASSERT(type_ == TranscendentalCache::LOG);
ASSERT(type == TranscendentalCache::LOG);
__ fldln2();
__ fxch();
__ fyl2x();
......
......@@ -49,6 +49,8 @@ class TranscendentalCacheStub: public CodeStub {
ArgumentType argument_type)
: type_(type), argument_type_(argument_type) {}
void Generate(MacroAssembler* masm);
static void GenerateOperation(MacroAssembler* masm,
TranscendentalCache::Type type);
private:
TranscendentalCache::Type type_;
ArgumentType argument_type_;
......@@ -56,7 +58,6 @@ class TranscendentalCacheStub: public CodeStub {
Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_ | argument_type_; }
Runtime::FunctionId RuntimeFunction();
void GenerateOperation(MacroAssembler* masm);
};
......
......@@ -30,6 +30,7 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "codegen.h"
#include "heap.h"
#include "macro-assembler.h"
namespace v8 {
......@@ -55,6 +56,53 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
#define __ masm.
TranscendentalFunction CreateTranscendentalFunction(
TranscendentalCache::Type type) {
size_t actual_size;
// Allocate buffer in executable space.
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
&actual_size,
true));
if (buffer == NULL) {
// Fallback to library function if function cannot be created.
switch (type) {
case TranscendentalCache::SIN: return &sin;
case TranscendentalCache::COS: return &cos;
case TranscendentalCache::TAN: return &tan;
case TranscendentalCache::LOG: return &log;
default: UNIMPLEMENTED();
}
}
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
// esp[1 * kPointerSize]: raw double input
// esp[0 * kPointerSize]: return address
// Move double input into registers.
__ push(ebx);
__ push(edx);
__ push(edi);
__ fld_d(Operand(esp, 4 * kPointerSize));
__ mov(ebx, Operand(esp, 4 * kPointerSize));
__ mov(edx, Operand(esp, 5 * kPointerSize));
TranscendentalCacheStub::GenerateOperation(&masm, type);
// The return value is expected to be on ST(0) of the FPU stack.
__ pop(edi);
__ pop(edx);
__ pop(ebx);
__ Ret();
CodeDesc desc;
masm.GetCode(&desc);
ASSERT(desc.reloc_size == 0);
CPU::FlushICache(buffer, actual_size);
OS::ProtectCode(buffer, actual_size);
return FUNCTION_CAST<TranscendentalFunction>(buffer);
}
static void MemCopyWrapper(void* dest, const void* src, size_t size) {
memcpy(dest, src, size);
}
......
......@@ -1195,7 +1195,7 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
input);
return DefineSameAsFirst(result);
} else if (op == kMathSin || op == kMathCos) {
} else if (op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
......
......@@ -37,6 +37,19 @@ namespace internal {
#define __ ACCESS_MASM(masm)
TranscendentalFunction CreateTranscendentalFunction(
TranscendentalCache::Type type) {
switch (type) {
case TranscendentalCache::SIN: return &sin;
case TranscendentalCache::COS: return &cos;
case TranscendentalCache::TAN: return &tan;
case TranscendentalCache::LOG: return &log;
default: UNIMPLEMENTED();
}
return NULL;
}
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
......
......@@ -1169,7 +1169,7 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
if (op == kMathLog || op == kMathSin || op == kMathCos) {
if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* input = UseFixedDouble(instr->value(), f4);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
return MarkAsCall(DefineFixedDouble(result, f4), instr);
......
......@@ -55,6 +55,30 @@ double modulo(double x, double y) {
}
double fast_sin(double x) {
UNIMPLEMENTED();
return 0;
}
double fast_cos(double x) {
UNIMPLEMENTED();
return 0;
}
double fast_tan(double x) {
UNIMPLEMENTED();
return 0;
}
double fast_log(double x) {
UNIMPLEMENTED();
return 0;
}
// Initialize OS class early in the V8 startup.
void OS::SetUp() {
// Seed the random number generator.
......
......@@ -53,6 +53,7 @@
#include "v8.h"
#include "codegen.h"
#include "platform.h"
namespace v8 {
......@@ -126,6 +127,29 @@ double modulo(double x, double y) {
}
static Mutex* transcendental_function_mutex = OS::CreateMutex();
#define TRANSCENDENTAL_FUNCTION(name, type) \
static TranscendentalFunction fast_##name##_function = NULL; \
double fast_##name(double x) { \
if (fast_##name##_function == NULL) { \
ScopedLock lock(transcendental_function_mutex); \
TranscendentalFunction temp = \
CreateTranscendentalFunction(type); \
MemoryBarrier(); \
fast_##name##_function = temp; \
} \
return (*fast_##name##_function)(x); \
}
TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN)
TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS)
TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN)
TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG)
#undef TRANSCENDENTAL_FUNCTION
double OS::nan_value() {
// NAN from math.h is defined in C99 and not in POSIX.
return NAN;
......
......@@ -32,6 +32,7 @@
#include "v8.h"
#include "codegen.h"
#include "platform.h"
#include "vm-state-inl.h"
......@@ -206,6 +207,30 @@ double modulo(double x, double y) {
#endif // _WIN64
static Mutex* transcendental_function_mutex = OS::CreateMutex();
#define TRANSCENDENTAL_FUNCTION(name, type) \
static TranscendentalFunction fast_##name##_function = NULL; \
double fast_##name(double x) { \
if (fast_##name##_function == NULL) { \
ScopedLock lock(transcendental_function_mutex); \
TranscendentalFunction temp = \
CreateTranscendentalFunction(type); \
MemoryBarrier(); \
fast_##name##_function = temp; \
} \
return (*fast_##name##_function)(x); \
}
TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN)
TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS)
TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN)
TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG)
#undef TRANSCENDENTAL_FUNCTION
// ----------------------------------------------------------------------------
// The Time class represents time on win32. A timestamp is represented as
// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
......
......@@ -96,6 +96,12 @@ class Mutex;
double ceiling(double x);
double modulo(double x, double y);
// Custom implementation of sin, cos, tan and log.
double fast_sin(double input);
double fast_cos(double input);
double fast_tan(double input);
double fast_log(double input);
// Forward declarations.
class Socket;
......
......@@ -1628,7 +1628,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm1);
__ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
}
GenerateOperation(masm);
GenerateOperation(masm, type_);
__ movq(Operand(rcx, 0), rbx);
__ movq(Operand(rcx, 2 * kIntSize), rax);
__ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
......@@ -1643,7 +1643,7 @@ void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
__ subq(rsp, Immediate(kDoubleSize));
__ movsd(Operand(rsp, 0), xmm1);
__ fld_d(Operand(rsp, 0));
GenerateOperation(masm);
GenerateOperation(masm, type_);
__ fstp_d(Operand(rsp, 0));
__ movsd(xmm1, Operand(rsp, 0));
__ addq(rsp, Immediate(kDoubleSize));
......@@ -1695,16 +1695,17 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
}
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
void TranscendentalCacheStub::GenerateOperation(
MacroAssembler* masm, TranscendentalCache::Type type) {
// Registers:
// rax: Newly allocated HeapNumber, which must be preserved.
// rbx: Bits of input double. Must be preserved.
// rcx: Pointer to cache entry. Must be preserved.
// st(0): Input double
Label done;
if (type_ == TranscendentalCache::SIN ||
type_ == TranscendentalCache::COS ||
type_ == TranscendentalCache::TAN) {
if (type == TranscendentalCache::SIN ||
type == TranscendentalCache::COS ||
type == TranscendentalCache::TAN) {
// Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation.
......@@ -1725,8 +1726,12 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
__ j(not_equal, &non_nan_result, Label::kNear);
// Input is +/-Infinity or NaN. Result is NaN.
__ fstp(0);
__ LoadRoot(kScratchRegister, Heap::kNanValueRootIndex);
__ fld_d(FieldOperand(kScratchRegister, HeapNumber::kValueOffset));
// NaN is represented by 0x7ff8000000000000.
__ subq(rsp, Immediate(kPointerSize));
__ movl(Operand(rsp, 4), Immediate(0x7ff80000));
__ movl(Operand(rsp, 0), Immediate(0x00000000));
__ fld_d(Operand(rsp, 0));
__ addq(rsp, Immediate(kPointerSize));
__ jmp(&done);
__ bind(&non_nan_result);
......@@ -1767,7 +1772,7 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
// FPU Stack: input % 2*pi
__ movq(rax, rdi); // Restore rax, pointer to the new HeapNumber.
__ bind(&in_range);
switch (type_) {
switch (type) {
case TranscendentalCache::SIN:
__ fsin();
break;
......@@ -1785,7 +1790,7 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
}
__ bind(&done);
} else {
ASSERT(type_ == TranscendentalCache::LOG);
ASSERT(type == TranscendentalCache::LOG);
__ fldln2();
__ fxch();
__ fyl2x();
......
......@@ -48,6 +48,8 @@ class TranscendentalCacheStub: public CodeStub {
ArgumentType argument_type)
: type_(type), argument_type_(argument_type) {}
void Generate(MacroAssembler* masm);
static void GenerateOperation(MacroAssembler* masm,
TranscendentalCache::Type type);
private:
TranscendentalCache::Type type_;
ArgumentType argument_type_;
......@@ -55,7 +57,6 @@ class TranscendentalCacheStub: public CodeStub {
Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_ | argument_type_; }
Runtime::FunctionId RuntimeFunction();
void GenerateOperation(MacroAssembler* masm);
};
......
......@@ -54,6 +54,52 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
#define __ masm.
TranscendentalFunction CreateTranscendentalFunction(
TranscendentalCache::Type type) {
size_t actual_size;
// Allocate buffer in executable space.
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
&actual_size,
true));
if (buffer == NULL) {
// Fallback to library function if function cannot be created.
switch (type) {
case TranscendentalCache::SIN: return &sin;
case TranscendentalCache::COS: return &cos;
case TranscendentalCache::TAN: return &tan;
case TranscendentalCache::LOG: return &log;
default: UNIMPLEMENTED();
}
}
MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
// xmm0: raw double input.
// Move double input into registers.
__ push(rbx);
__ push(rdi);
__ movq(rbx, xmm0);
__ push(rbx);
__ fld_d(Operand(rsp, 0));
TranscendentalCacheStub::GenerateOperation(&masm, type);
// The return value is expected to be in xmm0.
__ fstp_d(Operand(rsp, 0));
__ pop(rbx);
__ movq(xmm0, rbx);
__ pop(rdi);
__ pop(rbx);
__ Ret();
CodeDesc desc;
masm.GetCode(&desc);
ASSERT(desc.reloc_size == 0);
CPU::FlushICache(buffer, actual_size);
OS::ProtectCode(buffer, actual_size);
return FUNCTION_CAST<TranscendentalFunction>(buffer);
}
#ifdef _WIN64
typedef double (*ModuloFunction)(double, double);
// Define custom fmod implementation.
......
......@@ -1163,7 +1163,7 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
if (op == kMathLog || op == kMathSin || op == kMathCos) {
if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment