Index: src/x64/codegen-x64.cc |
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc |
index d72257e96f007c32de8378436b2b35344d2cfdd8..748c7be26df3f34fe1d885401819143aa5a39896 100644 |
--- a/src/x64/codegen-x64.cc |
+++ b/src/x64/codegen-x64.cc |
@@ -7695,6 +7695,95 @@ int CompareStub::MinorKey() { |
return (static_cast<unsigned>(cc_) << 1) | (strict_ ? 1 : 0); |
} |
+#undef __ |
+ |
+#define __ masm. |
+ |
+#ifdef _WIN64 |
+typedef double (*ModuloFunction)(double, double); |
+// Define custom fmod implementation. |
+ModuloFunction CreateModuloFunction() { |
+ size_t actual_size; |
+ byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize, |
+ &actual_size, |
+ true)); |
+ CHECK(buffer); |
+ Assembler masm(buffer, actual_size); |
+ |
William Hesse
2009/10/23 07:45:16
Put a comment in here that no relocatable addresse
|
+ // Windows 64 ABI passes double arguments in xmm0, xmm1 and |
+ // returns result in xmm0. |
+ // Argument backing space is allocated on the stack above |
+ // the return address. |
+ |
+ // Compute x mod y. |
+ // Load y and x (use argument backing store as temporary storage). |
+ __ movsd(Operand(rsp, kPointerSize * 2), xmm1); |
+ __ movsd(Operand(rsp, kPointerSize), xmm0); |
+ __ fld_d(Operand(rsp, kPointerSize * 2)); |
+ __ fld_d(Operand(rsp, kPointerSize)); |
+ |
+ // Clear exception flags before operation. |
+ { |
+ Label no_exceptions; |
+ __ fwait(); |
+ __ fnstsw_ax(); |
+ // Clear if Illegal Operand or Zero Division exceptions are set. |
+ __ testb(rax, Immediate(5)); |
+ __ j(zero, &no_exceptions); |
+ __ fnclex(); |
+ __ bind(&no_exceptions); |
+ } |
+ |
+ // Compute st(0) % st(1) |
+ { |
+ Label partial_remainder_loop; |
+ __ bind(&partial_remainder_loop); |
+ __ fprem(); |
+ __ fwait(); |
+ __ fnstsw_ax(); |
+ __ testl(rax, Immediate(0x400 /* C2 */)); |
+ // If C2 is set, computation only has partial result. Loop to |
+ // continue computation. |
+ __ j(not_zero, &partial_remainder_loop); |
+ } |
+ |
+ Label valid_result; |
+ Label return_result; |
+ // If Invalid Operand or Zero Division exceptions are set, |
+ // return NaN. |
+ __ testb(rax, Immediate(5)); |
+ __ j(zero, &valid_result); |
+ __ fstp(0); // Drop result in st(0). |
+ int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); |
+ __ movq(rcx, kNaNValue, RelocInfo::NONE); |
+ __ movq(Operand(rsp, kPointerSize), rcx); |
+ __ movsd(xmm0, Operand(rsp, kPointerSize)); |
+ __ jmp(&return_result); |
+ |
+ // If result is valid, return that. |
+ __ bind(&valid_result); |
+ __ fstp_d(Operand(rsp, kPointerSize)); |
+ __ movsd(xmm0, Operand(rsp, kPointerSize)); |
+ |
+ // Clean up FPU stack and exceptions and return xmm0 |
+ __ bind(&return_result); |
+ __ fstp(0); // Unload y. |
+ { |
+ Label no_exceptions; |
+ __ testb(rax, Immediate(0x3f /* Any Exception*/)); |
+ __ j(zero, &no_exceptions); |
+ __ fnclex(); |
+ __ bind(&no_exceptions); |
+ } |
+ __ ret(0); |
+ |
+ CodeDesc desc; |
+ masm.GetCode(&desc); |
+ // Call the function from C++. |
+ return FUNCTION_CAST<ModuloFunction>(buffer); |
+} |
+ |
+#endif |
#undef __ |