Ensure consistent result of transcendental functions.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Mar 2012 14:33:15 +0000 (14:33 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 2 Mar 2012 14:33:15 +0000 (14:33 +0000)
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

21 files changed:
src/arm/codegen-arm.cc
src/arm/lithium-arm.cc
src/codegen.h
src/heap-inl.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/code-stubs-ia32.cc
src/ia32/code-stubs-ia32.h
src/ia32/codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/mips/codegen-mips.cc
src/mips/lithium-mips.cc
src/platform-nullos.cc
src/platform-posix.cc
src/platform-win32.cc
src/platform.h
src/x64/code-stubs-x64.cc
src/x64/code-stubs-x64.h
src/x64/codegen-x64.cc
src/x64/lithium-x64.cc
test/mjsunit/regress/regress-transcendental.js [new file with mode: 0644]

index 506f9b2d5dcdca0ba2de06d5cabf4ac429747fb9..6e1827778302b358a7ec96f5fa37d1b27e560594 100644 (file)
@@ -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.
 
index b747ab81558dd36a041a3d512396c1bb813be55c..108a6de6276f0eb57bab78a2be860c427a52b40b 100644 (file)
@@ -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);
index 5360d3ef3caae22c24ccbdda28488770a8823d97..28a3006e1cc2e198bd6ce0152dad89fac5632e96 100644 (file)
@@ -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);
index 81ed448a17f1185b3bd64d7577f29a001db0a42b..706d2886b9fbed4e107b1b501d8c09758201ae79 100644 (file)
@@ -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.
   }
index eb0e0fd7d54e98f1ace426cf02a20c42f4e4b11d..a05fc776f848875e561e14e7c982229602b0134a 100644 (file)
@@ -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();
index ccddd88690b19b4413ca14061cd4280a10d0ab68..9c83380492f6158b14d3c181c345980ddb44936d 100644 (file)
@@ -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();
index b89cc14c6611f7b9b90c1e325756e2817d643c1b..5b6f6873c264326d8b843343161e556a79103884 100644 (file)
@@ -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();
index 4d23c3a174cf88194a2b28cab77584204d1fc609..803a711de9694efeacc907db44d1f7342980d006 100644 (file)
@@ -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);
 };
 
 
index 3e085a245dc222ee9a9413419d446935fead0fdf..e1f689e19aaa5e917211977d9f3510dd41b70fe2 100644 (file)
@@ -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);
 }
index 6db041319d86f125b119209c226daf0687b402de..758701652049b7251446d473ef4064c741e2fca5 100644 (file)
@@ -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,
index d7bddaf1252f6b9b72ed9c7760ed1c2c4525cdd4..8cbb771952d87531a3f014da9d2f2993af27c522 100644 (file)
@@ -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.
 
index ae07c1e45601bcf55bffedeefe8678f5f16cd5d3..1c4e1da3fbca3d189ba7d8f14fa2fab4b361dae6 100644 (file)
@@ -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);
index 918327a983a3c2ab89c786d5224d121cbb7c45b4..e05345c80a3966aff84e8666c94482fb46d013ef 100644 (file)
@@ -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.
index 34fd5c4498507f678ea83a2bd33b8eb6a53e318f..4543a66e8c595c6926ed7081f6fbf02b7258506f 100644 (file)
@@ -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;
index e9e99246cb7924bbc7316aedf6701f8b88be96b6..224527addaecf46b843b1aa3fd94dd966a446301 100644 (file)
@@ -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
index 38e633a38081e155744d9e1942c9eee8fc73827f..ccb4109b22b500ae35ca8adf4c64601e8b23d716 100644 (file)
@@ -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;
 
index 982639e9a56094d863d53e3bbb8d123284a05a72..307ade433082901affc8994a9f09d2663291406e 100644 (file)
@@ -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();
index 30ef3e8c5333c1b0265df7829b6a1882eedff913..6a1a18f830a6c78f6b024b1e65b897a121835e7e 100644 (file)
@@ -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);
 };
 
 
index 8947f70055f64745333a35e1b840480e1c0a1796..2584889f087d56ff0fffd6f6521b47a7cf315326 100644 (file)
@@ -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.
index 19bb58ae645088b62c668dfb7768f01ff912b919..79ca5f59e7f663e9f06af2eadf10dd80eae314a1 100644 (file)
@@ -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);
diff --git a/test/mjsunit/regress/regress-transcendental.js b/test/mjsunit/regress/regress-transcendental.js
new file mode 100644 (file)
index 0000000..acaf11c
--- /dev/null
@@ -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");