Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 4482) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -4040,22 +4040,231 @@ |
} |
-// Generates the Math.pow method - currently just calls runtime. |
+// Generates the Math.pow method. Only handles special cases and |
+// branches to the runtime system for everything else. Please note |
+// that this function assumes that the callsite has executed ToNumber |
+// on both arguments. |
void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 2); |
Load(args->at(0)); |
Load(args->at(1)); |
- Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); |
- frame_->Push(&res); |
+ |
+ Label allocate_return; |
+ // Load the two operands while leaving the values on the frame. |
+ frame()->Dup(); |
+ Result exponent = frame()->Pop(); |
+ exponent.ToRegister(); |
+ frame()->Spill(exponent.reg()); |
+ frame()->PushElementAt(1); |
+ Result base = frame()->Pop(); |
+ base.ToRegister(); |
+ frame()->Spill(base.reg()); |
+ |
+ Result answer = allocator()->Allocate(); |
+ ASSERT(answer.is_valid()); |
+ ASSERT(!exponent.reg().is(base.reg())); |
+ JumpTarget call_runtime; |
+ |
+ // Save 1 in xmm3 - we need this several times later on. |
+ __ movl(answer.reg(), Immediate(1)); |
+ __ cvtlsi2sd(xmm3, answer.reg()); |
+ |
+ Label exponent_nonsmi; |
+ Label base_nonsmi; |
+ // If the exponent is a heap number go to that specific case. |
+ __ JumpIfNotSmi(exponent.reg(), &exponent_nonsmi); |
+ __ JumpIfNotSmi(base.reg(), &base_nonsmi); |
+ |
+ // Optimized version when y is an integer. |
+ Label powi; |
+ __ SmiToInteger32(base.reg(), base.reg()); |
+ __ cvtlsi2sd(xmm0, base.reg()); |
+ __ jmp(&powi); |
+ // exponent is smi and base is a heapnumber. |
+ __ bind(&base_nonsmi); |
+ __ CompareRoot(FieldOperand(base.reg(), HeapObject::kMapOffset), |
+ Heap::kHeapNumberMapRootIndex); |
+ call_runtime.Branch(not_equal); |
+ |
+ __ movsd(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
+ |
+ // Optimized version of pow if y is an integer. |
+ __ bind(&powi); |
+ __ SmiToInteger32(exponent.reg(), exponent.reg()); |
+ |
+ // Save exponent in base as we need to check if exponent is negative later. |
+ // We know that base and exponent are in different registers. |
+ __ movl(base.reg(), exponent.reg()); |
+ |
+ // Get absolute value of exponent. |
+ Label no_neg; |
+ __ cmpl(exponent.reg(), Immediate(0)); |
+ __ j(greater_equal, &no_neg); |
+ __ negl(exponent.reg()); |
+ __ bind(&no_neg); |
+ |
+ // Load xmm1 with 1. |
+ __ movsd(xmm1, xmm3); |
+ Label while_true; |
+ Label no_multiply; |
+ |
+ __ bind(&while_true); |
+ __ shrl(exponent.reg(), Immediate(1)); |
+ __ j(not_carry, &no_multiply); |
+ __ mulsd(xmm1, xmm0); |
+ __ bind(&no_multiply); |
+ __ testl(exponent.reg(), exponent.reg()); |
+ __ mulsd(xmm0, xmm0); |
+ __ j(not_zero, &while_true); |
+ |
+ // x has the original value of y - if y is negative return 1/result. |
+ __ testl(base.reg(), base.reg()); |
+ __ j(positive, &allocate_return); |
+ // Special case if xmm1 has reached infinity. |
+ __ movl(answer.reg(), Immediate(0x7FB00000)); |
+ __ movd(xmm0, answer.reg()); |
+ __ cvtss2sd(xmm0, xmm0); |
+ __ ucomisd(xmm0, xmm1); |
+ call_runtime.Branch(equal); |
+ __ divsd(xmm3, xmm1); |
+ __ movsd(xmm1, xmm3); |
+ __ jmp(&allocate_return); |
+ |
+ // exponent (or both) is a heapnumber - no matter what we should now work |
+ // on doubles. |
+ __ bind(&exponent_nonsmi); |
+ __ CompareRoot(FieldOperand(exponent.reg(), HeapObject::kMapOffset), |
+ Heap::kHeapNumberMapRootIndex); |
+ call_runtime.Branch(not_equal); |
+ __ movsd(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset)); |
+ // Test if exponent is nan. |
+ __ ucomisd(xmm1, xmm1); |
+ call_runtime.Branch(parity_even); |
+ |
+ Label base_not_smi; |
+ Label handle_special_cases; |
+ __ testl(base.reg(), Immediate(kSmiTagMask)); |
+ __ j(not_zero, &base_not_smi); |
+ __ SmiToInteger32(base.reg(), base.reg()); |
+ __ cvtlsi2sd(xmm0, base.reg()); |
+ __ jmp(&handle_special_cases); |
+ __ bind(&base_not_smi); |
+ __ CompareRoot(FieldOperand(base.reg(), HeapObject::kMapOffset), |
+ Heap::kHeapNumberMapRootIndex); |
+ call_runtime.Branch(not_equal); |
+ __ movl(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset)); |
+ __ andl(answer.reg(), Immediate(HeapNumber::kExponentMask)); |
+ __ cmpl(answer.reg(), Immediate(HeapNumber::kExponentMask)); |
+ // base is NaN or +/-Infinity |
+ call_runtime.Branch(greater_equal); |
+ __ movsd(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
+ |
+ // base is in xmm0 and exponent is in xmm1. |
+ __ bind(&handle_special_cases); |
+ Label not_minus_half; |
+ // Test for -0.5. |
+ // Load xmm2 with -0.5. |
+ __ movl(answer.reg(), Immediate(0xBF000000)); |
+ __ movd(xmm2, answer.reg()); |
+ __ cvtss2sd(xmm2, xmm2); |
+ // xmm2 now has -0.5. |
+ __ ucomisd(xmm2, xmm1); |
+ __ j(not_equal, ¬_minus_half); |
+ |
+ // Calculates reciprocal of square root. |
+ // Note that 1/sqrt(x) = sqrt(1/x)) |
+ __ divsd(xmm3, xmm0); |
+ __ movsd(xmm1, xmm3); |
+ __ sqrtsd(xmm1, xmm1); |
+ __ jmp(&allocate_return); |
+ |
+ // Test for 0.5. |
+ __ bind(¬_minus_half); |
+ // Load xmm2 with 0.5. |
+ // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. |
+ __ addsd(xmm2, xmm3); |
+ // xmm2 now has 0.5. |
+ __ comisd(xmm2, xmm1); |
+ call_runtime.Branch(not_equal); |
+ |
+ // Calculates square root. |
+ __ movsd(xmm1, xmm0); |
+ __ sqrtsd(xmm1, xmm1); |
+ |
+ JumpTarget done; |
+ Label failure, success; |
+ __ bind(&allocate_return); |
+ // Make a copy of the frame to enable us to handle allocation |
+ // failure after the JumpTarget jump. |
+ VirtualFrame* clone = new VirtualFrame(frame()); |
+ __ AllocateHeapNumber(answer.reg(), exponent.reg(), &failure); |
+ __ movsd(FieldOperand(answer.reg(), HeapNumber::kValueOffset), xmm1); |
+ // Remove the two original values from the frame - we only need those |
+ // in the case where we branch to runtime. |
+ frame()->Drop(2); |
+ exponent.Unuse(); |
+ base.Unuse(); |
+ done.Jump(&answer); |
+ // Use the copy of the original frame as our current frame. |
+ RegisterFile empty_regs; |
+ SetFrame(clone, &empty_regs); |
+ // If we experience an allocation failure we branch to runtime. |
+ __ bind(&failure); |
+ call_runtime.Bind(); |
+ answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2); |
+ |
+ done.Bind(&answer); |
+ frame()->Push(&answer); |
} |
-// Generates the Math.sqrt method - currently just calls runtime. |
+// Generates the Math.sqrt method. Please note - this function assumes that |
+// the callsite has executed ToNumber on the argument. |
void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 1); |
Load(args->at(0)); |
- Result res = frame_->CallRuntime(Runtime::kMath_sqrt, 1); |
- frame_->Push(&res); |
+ |
+ // Leave original value on the frame if we need to call runtime. |
+ frame()->Dup(); |
+ Result result = frame()->Pop(); |
+ result.ToRegister(); |
+ frame()->Spill(result.reg()); |
+ Label runtime; |
+ Label non_smi; |
+ Label load_done; |
+ JumpTarget end; |
+ |
+ __ JumpIfNotSmi(result.reg(), &non_smi); |
+ __ SmiToInteger32(result.reg(), result.reg()); |
+ __ cvtlsi2sd(xmm0, result.reg()); |
+ __ jmp(&load_done); |
+ __ bind(&non_smi); |
+ __ CompareRoot(FieldOperand(result.reg(), HeapObject::kMapOffset), |
+ Heap::kHeapNumberMapRootIndex); |
+ __ j(not_equal, &runtime); |
+ __ movsd(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset)); |
+ |
+ __ bind(&load_done); |
+ __ sqrtsd(xmm0, xmm0); |
+ // A copy of the virtual frame to allow us to go to runtime after the |
+ // JumpTarget jump. |
+ Result scratch = allocator()->Allocate(); |
+ VirtualFrame* clone = new VirtualFrame(frame()); |
+ __ AllocateHeapNumber(result.reg(), scratch.reg(), &runtime); |
+ |
+ __ movsd(FieldOperand(result.reg(), HeapNumber::kValueOffset), xmm0); |
+ frame()->Drop(1); |
+ scratch.Unuse(); |
+ end.Jump(&result); |
+ // We only branch to runtime if we have an allocation error. |
+ // Use the copy of the original frame as our current frame. |
+ RegisterFile empty_regs; |
+ SetFrame(clone, &empty_regs); |
+ __ bind(&runtime); |
+ result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
+ |
+ end.Bind(&result); |
+ frame()->Push(&result); |
} |