Chromium Code Reviews| Index: src/x64/codegen-x64.cc |
| diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc |
| index d72257e96f007c32de8378436b2b35344d2cfdd8..8e4a8ca7bd83f4ccb88227bfc4302d15c215ba31 100644 |
| --- a/src/x64/codegen-x64.cc |
| +++ b/src/x64/codegen-x64.cc |
| @@ -219,12 +219,19 @@ class FloatingPointHelper : public AllStatic { |
| // Input values must be either smi or heap number objects (fp values). |
| // Requirements: |
| // Register version: operands in registers lhs and rhs. |
| + // Version without scratch memory pushes and pops the stack to get a |
| + // memory cell, the version with scratch memory uses 8 bytes (64 bits) |
| + // at that location. |
| // Stack version: operands on TOS+1 and TOS+2. |
| // Returns operands as floating point numbers on fp stack. |
| static void LoadFloatOperands(MacroAssembler* masm); |
| static void LoadFloatOperands(MacroAssembler* masm, |
| Register lhs, |
| Register rhs); |
| + static void LoadFloatOperands(MacroAssembler* masm, |
| + Register lhs, |
| + Register rhs, |
| + const Operand& scratch_memory); |
| // Code pattern for loading a floating point value and converting it |
| // to a 32 bit integer. Input value must be either a smi or a heap number |
| @@ -4004,6 +4011,112 @@ void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) { |
| } |
|
William Hesse
2009/10/20 14:50:51
Could this function be documented more, explaining
|
| +void CodeGenerator::GenerateNumberMod(ZoneList<Expression*>* args) { |
| + ASSERT_EQ(2, args->length()); |
| +#ifdef _WIN64 |
| + Load(args->at(0)); |
| + Load(args->at(1)); |
| + // Allocate rax for using fnstsw_ax. |
| + Result tmp = allocator_->Allocate(rax); |
| + // Allocate callee save register, for storing value while calling runtime. |
| + Result callee_save_result = allocator_->Allocate(r15); |
| + Result divisor_result = frame_->Pop(); |
| + Result dividend_result = frame_->Pop(); |
| + divisor_result.ToRegister(); |
| + dividend_result.ToRegister(); |
| + { |
| + // Code uses the physical stack, so it must be in sync. |
| + VirtualFrame::SpilledScope scope; |
| + Register dividend = dividend_result.reg(); |
| + Register divisor = divisor_result.reg(); |
| + Register callee_save = callee_save_result.reg(); |
| + |
| + Label done; |
| + // Make room on stack for temporary value. |
| + __ subq(rsp, Immediate(kPointerSize)); |
| + |
| + // Load operands onto FPU stack. |
| + // Divisor must go first on stack, so order of operands is really rhs, lhs. |
| + FloatingPointHelper::LoadFloatOperands(masm_, |
| + divisor, |
| + dividend, |
| + Operand(rsp, 0)); |
| + |
| + // Compute the remainder. |
| + { |
| + Label partial_remainder_loop; |
| + __ bind(&partial_remainder_loop); |
| + __ fprem(); |
| + __ fwait(); |
| + __ fnstsw_ax(); |
| + __ testl(rax, Immediate(kCondition2)); |
| + __ j(not_zero, &partial_remainder_loop); |
| + } |
| + |
| + // Result is in ST(0), garbage in ST(1), and original value |
| + // of dividend in ST(2). Return ST(0) unless a division by zero or |
| + // invalid operation exception has been raised. Status word is in rax. |
| + |
| + Label valid_result; |
| + Label allocate_result; |
| + // Test for InvalidOperation or division by zero. |
| + // In those cases, discard the result and use NaN instead. |
| + __ testb(rax, Immediate(kInvalidOperandException | kZeroDivideException)); |
| + __ j(zero, &valid_result); |
| + |
| + __ fstp(0); // Pop (garbage) result |
| + __ addq(rsp, Immediate(kPointerSize)); // Free stack cell. |
| + int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); |
| + // Move NaN to (callee save) register for later storing into new HeapNumber. |
| + __ movq(callee_save, kNaNValue, RelocInfo::NONE); |
| + __ jmp(&allocate_result); |
| + |
| + // Allocate new space for a HeapNumber (is branched back to if direct heap |
| + // allocation fails in the following code). |
| + Label gc_req; |
| + Label heap_number_allocated; |
| + __ bind(&gc_req); |
| + // Garbage collection required before allocating a heap number. |
| + // Call runtime to do the allocation, and handle the allocation failure. |
| + __ CallRuntime(Runtime::kAllocateHeapNumber, 0); |
| + __ jmp(&heap_number_allocated); |
| + |
| + __ bind(&valid_result); |
| + |
| + // Result in ST(0), garbage in ST(1) and ST(2). |
| + // Pop result and free stack cell. |
| + __ fstp_d(Operand(rsp, 0)); |
| + __ pop(callee_save); |
| + |
| + __ bind(&allocate_result); |
| + // Free FPU stack and clear pending FPU exceptions (e.g., Denormal). |
| + __ fstp(0); |
| + Label no_exceptions_set; |
| + __ testb(rax, Immediate(kAnyExceptionMask)); |
| + __ j(zero, &no_exceptions_set); |
| + __ fnclex(); |
| + __ bind(&no_exceptions_set); |
| + |
| + FloatingPointHelper::AllocateHeapNumber(masm_, &gc_req, dividend, rax); |
| + __ bind(&heap_number_allocated); // Return point for gc_req branch. |
| + __ movq(FieldOperand(rax, HeapNumber::kValueOffset), callee_save); |
| + |
| + __ bind(&done); |
| + } |
| + frame_->Push(&tmp); |
| + |
| +#else |
| + // Simply call the runtime function. Arguments must be numbers. |
| + ASSERT(args->length() == 2); |
| + Load(args->at(0)); |
| + Load(args->at(1)); |
| + |
| + Result answer = frame_->CallRuntime(Runtime::kNumberMod, 2); |
| + frame_->Push(&answer); |
| +#endif |
| +} |
| + |
| + |
| void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { |
| ASSERT(args->length() == 1); |
| JumpTarget leave, null, function, non_function_constructor; |
| @@ -7324,17 +7437,41 @@ void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| __ jmp(&done); |
| __ bind(&load_smi_lhs); |
| - __ SmiToInteger64(kScratchRegister, lhs); |
| - __ push(kScratchRegister); |
| - __ fild_d(Operand(rsp, 0)); |
| - __ pop(kScratchRegister); |
| + __ push(lhs); |
| + __ FLoadSmi(Operand(rsp, 0)); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| __ jmp(&done_load_lhs); |
| __ bind(&load_smi_rhs); |
| - __ SmiToInteger64(kScratchRegister, rhs); |
| - __ push(kScratchRegister); |
| - __ fild_d(Operand(rsp, 0)); |
| - __ pop(kScratchRegister); |
| + __ push(rhs); |
| + __ FLoadSmi(Operand(rsp, 0)); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + |
| + __ bind(&done); |
| +} |
| + |
| + |
| +void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
| + Register lhs, |
| + Register rhs, |
| + const Operand& scratch_memory) { |
| + Label load_smi_lhs, load_smi_rhs, done_load_lhs, done; |
| + __ JumpIfSmi(lhs, &load_smi_lhs); |
| + __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset)); |
| + __ bind(&done_load_lhs); |
| + |
| + __ JumpIfSmi(rhs, &load_smi_rhs); |
| + __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); |
| + __ jmp(&done); |
| + |
| + __ bind(&load_smi_lhs); |
| + __ movq(scratch_memory, lhs); |
| + __ FLoadSmi(scratch_memory); |
| + __ jmp(&done_load_lhs); |
| + |
| + __ bind(&load_smi_rhs); |
| + __ movq(scratch_memory, rhs); |
| + __ FLoadSmi(scratch_memory); |
| __ bind(&done); |
| } |