Ensure consistent result of transcendental functions.
BUG= TEST=regress-transcendental.js Review URL: https://chromiumcodereview.appspot.com/9572009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10908 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
21e43e14eb
commit
12f2099993
@ -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,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));
|
||||
// esp[1 * kPointerSize]: raw double input
|
||||
// esp[0 * kPointerSize]: return address
|
||||
// Move double input into registers.
|
||||
__ fld_d(Operand(esp, kPointerSize));
|
||||
__ push(ebx);
|
||||
__ push(edx);
|
||||
__ push(edi);
|
||||
__ mov(ebx, Operand(esp, kPointerSize));
|
||||
__ mov(edx, Operand(esp, 2* 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"
|
||||
|
||||
@ -201,6 +202,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.
|
||||
@ -1767,7 +1768,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 +1786,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);
|
||||
|
48
test/mjsunit/regress/regress-transcendental.js
Normal file
48
test/mjsunit/regress/regress-transcendental.js
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2012 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: --expose-gc
|
||||
|
||||
// Test whether the runtime implementation and generated code of
|
||||
// sine and tangens return the same results.
|
||||
|
||||
function test(f, x, name) {
|
||||
// Reset transcendental cache.
|
||||
gc();
|
||||
// Initializing cache leads to a runtime call.
|
||||
var runtime_result = f(x);
|
||||
// Flush transcendental cache.
|
||||
for (var i = 0; i < 100000; i++) f(i);
|
||||
// Calculate using generated code.
|
||||
var gencode_result = f(x);
|
||||
print(name + " runtime function: " + runtime_result);
|
||||
print(name + " generated code : " + gencode_result);
|
||||
assertEquals(gencode_result, runtime_result);
|
||||
}
|
||||
|
||||
test(Math.tan, -1.57079632679489660000, "Math.tan");
|
||||
test(Math.sin, 6.283185307179586, "Math.sin");
|
Loading…
Reference in New Issue
Block a user