OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3448 } | 3448 } |
3449 } | 3449 } |
3450 | 3450 |
3451 | 3451 |
3452 void StackCheckStub::Generate(MacroAssembler* masm) { | 3452 void StackCheckStub::Generate(MacroAssembler* masm) { |
3453 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); | 3453 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); |
3454 } | 3454 } |
3455 | 3455 |
3456 | 3456 |
3457 void MathPowStub::Generate(MacroAssembler* masm) { | 3457 void MathPowStub::Generate(MacroAssembler* masm) { |
3458 Label call_runtime; | 3458 CpuFeatures::Scope vfp3_scope(VFP3); |
| 3459 const Register base = r1; |
| 3460 const Register exponent = r2; |
| 3461 const Register heapnumbermap = r5; |
| 3462 const Register heapnumber = r0; |
| 3463 const DoubleRegister double_base = d1; |
| 3464 const DoubleRegister double_exponent = d2; |
| 3465 const DoubleRegister double_result = d3; |
| 3466 const DoubleRegister double_scratch = d0; |
| 3467 const SwVfpRegister single_scratch = s0; |
| 3468 const Register scratch = r9; |
| 3469 const Register scratch2 = r7; |
3459 | 3470 |
3460 if (CpuFeatures::IsSupported(VFP3)) { | 3471 Label call_runtime, done, exponent_not_smi, int_exponent; |
3461 CpuFeatures::Scope scope(VFP3); | 3472 if (exponent_type_ == ON_STACK) { |
3462 | 3473 Label base_is_smi, unpack_exponent; |
3463 Label base_not_smi; | 3474 // The exponent and base are supplied as arguments on the stack. |
3464 Label exponent_not_smi; | 3475 // This can only happen if the stub is called from non-optimized code. |
3465 Label convert_exponent; | 3476 // Load input parameters from stack to double registers. |
3466 | |
3467 const Register base = r0; | |
3468 const Register exponent = r1; | |
3469 const Register heapnumbermap = r5; | |
3470 const Register heapnumber = r6; | |
3471 const DoubleRegister double_base = d0; | |
3472 const DoubleRegister double_exponent = d1; | |
3473 const DoubleRegister double_result = d2; | |
3474 const SwVfpRegister single_scratch = s0; | |
3475 const Register scratch = r9; | |
3476 const Register scratch2 = r7; | |
3477 | |
3478 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); | |
3479 __ ldr(base, MemOperand(sp, 1 * kPointerSize)); | 3477 __ ldr(base, MemOperand(sp, 1 * kPointerSize)); |
3480 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize)); | 3478 __ ldr(exponent, MemOperand(sp, 0 * kPointerSize)); |
3481 | 3479 |
3482 // Convert base to double value and store it in d0. | 3480 __ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex); |
3483 __ JumpIfNotSmi(base, &base_not_smi); | 3481 |
3484 // Base is a Smi. Untag and convert it. | 3482 __ JumpIfSmi(base, &base_is_smi); |
| 3483 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset)); |
| 3484 __ cmp(scratch, heapnumbermap); |
| 3485 __ b(ne, &call_runtime); |
| 3486 |
| 3487 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); |
| 3488 __ jmp(&unpack_exponent); |
| 3489 |
| 3490 __ bind(&base_is_smi); |
3485 __ SmiUntag(base); | 3491 __ SmiUntag(base); |
3486 __ vmov(single_scratch, base); | 3492 __ vmov(single_scratch, base); |
3487 __ vcvt_f64_s32(double_base, single_scratch); | 3493 __ vcvt_f64_s32(double_base, single_scratch); |
3488 __ b(&convert_exponent); | 3494 __ bind(&unpack_exponent); |
3489 | 3495 |
3490 __ bind(&base_not_smi); | |
3491 __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset)); | |
3492 __ cmp(scratch, heapnumbermap); | |
3493 __ b(ne, &call_runtime); | |
3494 // Base is a heapnumber. Load it into double register. | |
3495 __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset)); | |
3496 | |
3497 __ bind(&convert_exponent); | |
3498 __ JumpIfNotSmi(exponent, &exponent_not_smi); | 3496 __ JumpIfNotSmi(exponent, &exponent_not_smi); |
3499 __ SmiUntag(exponent); | 3497 __ SmiUntag(exponent); |
3500 | 3498 __ jmp(&int_exponent); |
3501 // The base is in a double register and the exponent is | |
3502 // an untagged smi. Allocate a heap number and call a | |
3503 // C function for integer exponents. The register containing | |
3504 // the heap number is callee-saved. | |
3505 __ AllocateHeapNumber(heapnumber, | |
3506 scratch, | |
3507 scratch2, | |
3508 heapnumbermap, | |
3509 &call_runtime); | |
3510 __ push(lr); | |
3511 __ PrepareCallCFunction(1, 1, scratch); | |
3512 __ SetCallCDoubleArguments(double_base, exponent); | |
3513 { | |
3514 AllowExternalCallThatCantCauseGC scope(masm); | |
3515 __ CallCFunction( | |
3516 ExternalReference::power_double_int_function(masm->isolate()), | |
3517 1, 1); | |
3518 __ pop(lr); | |
3519 __ GetCFunctionDoubleResult(double_result); | |
3520 } | |
3521 __ vstr(double_result, | |
3522 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); | |
3523 __ mov(r0, heapnumber); | |
3524 __ Ret(2 * kPointerSize); | |
3525 | 3499 |
3526 __ bind(&exponent_not_smi); | 3500 __ bind(&exponent_not_smi); |
3527 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); | 3501 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); |
3528 __ cmp(scratch, heapnumbermap); | 3502 __ cmp(scratch, heapnumbermap); |
3529 __ b(ne, &call_runtime); | 3503 __ b(ne, &call_runtime); |
3530 // Exponent is a heapnumber. Load it into double register. | |
3531 __ vldr(double_exponent, | 3504 __ vldr(double_exponent, |
3532 FieldMemOperand(exponent, HeapNumber::kValueOffset)); | 3505 FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
| 3506 } else if (exponent_type_ == TAGGED) { |
| 3507 // Base is already in double_base. |
| 3508 __ JumpIfNotSmi(exponent, &exponent_not_smi); |
| 3509 __ SmiUntag(exponent); |
| 3510 __ jmp(&int_exponent); |
3533 | 3511 |
3534 // The base and the exponent are in double registers. | 3512 __ bind(&exponent_not_smi); |
3535 // Allocate a heap number and call a C function for | 3513 __ vldr(double_exponent, |
3536 // double exponents. The register containing | 3514 FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
3537 // the heap number is callee-saved. | 3515 } |
3538 __ AllocateHeapNumber(heapnumber, | 3516 |
3539 scratch, | 3517 if (exponent_type_ != INTEGER) { |
3540 scratch2, | 3518 // Detect integer exponents stored as double. |
3541 heapnumbermap, | 3519 __ vcvt_u32_f64(single_scratch, double_exponent); |
3542 &call_runtime); | 3520 // We do not check for NaN or Infinity here because comparing numbers on |
| 3521 // ARM correctly distinguishes NaNs. We end up calling the built-in. |
| 3522 __ vcvt_f64_u32(double_scratch, single_scratch); |
| 3523 __ VFPCompareAndSetFlags(double_scratch, double_exponent); |
| 3524 __ vmov(exponent, single_scratch, eq); |
| 3525 __ b(eq, &int_exponent); |
| 3526 |
| 3527 if (exponent_type_ == ON_STACK) { |
| 3528 // Detect square root case. Crankshaft detects constant +/-0.5 at |
| 3529 // compile time and uses DoMathPowHalf instead. We then skip this check |
| 3530 // for non-constant cases of +/-0.5 as these hardly occur. |
| 3531 Label not_plus_half; |
| 3532 |
| 3533 // Test for 0.5. |
| 3534 __ vmov(double_scratch, 0.5); |
| 3535 __ VFPCompareAndSetFlags(double_exponent, double_scratch); |
| 3536 __ b(ne, ¬_plus_half); |
| 3537 |
| 3538 // Calculates square root of base. Check for the special case of |
| 3539 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). |
| 3540 __ vmov(double_scratch, -V8_INFINITY); |
| 3541 __ VFPCompareAndSetFlags(double_base, double_scratch); |
| 3542 __ vneg(double_result, double_scratch, eq); |
| 3543 __ b(eq, &done); |
| 3544 |
| 3545 // Add +0 to convert -0 to +0. |
| 3546 __ vadd(double_scratch, double_base, kDoubleRegZero); |
| 3547 __ vsqrt(double_result, double_scratch); |
| 3548 __ jmp(&done); |
| 3549 |
| 3550 __ bind(¬_plus_half); |
| 3551 __ vmov(double_scratch, -0.5); |
| 3552 __ VFPCompareAndSetFlags(double_exponent, double_scratch); |
| 3553 __ b(ne, &call_runtime); |
| 3554 |
| 3555 // Calculates square root of base. Check for the special case of |
| 3556 // Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). |
| 3557 __ vmov(double_scratch, -V8_INFINITY); |
| 3558 __ VFPCompareAndSetFlags(double_base, double_scratch); |
| 3559 __ vmov(double_result, kDoubleRegZero, eq); |
| 3560 __ b(eq, &done); |
| 3561 |
| 3562 // Add +0 to convert -0 to +0. |
| 3563 __ vadd(double_scratch, double_base, kDoubleRegZero); |
| 3564 __ vmov(double_result, 1); |
| 3565 __ vsqrt(double_scratch, double_scratch); |
| 3566 __ vdiv(double_result, double_result, double_scratch); |
| 3567 __ jmp(&done); |
| 3568 } |
| 3569 |
3543 __ push(lr); | 3570 __ push(lr); |
3544 __ PrepareCallCFunction(0, 2, scratch); | |
3545 __ SetCallCDoubleArguments(double_base, double_exponent); | |
3546 { | 3571 { |
3547 AllowExternalCallThatCantCauseGC scope(masm); | 3572 AllowExternalCallThatCantCauseGC scope(masm); |
| 3573 __ PrepareCallCFunction(0, 2, scratch); |
| 3574 __ SetCallCDoubleArguments(double_base, double_exponent); |
3548 __ CallCFunction( | 3575 __ CallCFunction( |
3549 ExternalReference::power_double_double_function(masm->isolate()), | 3576 ExternalReference::power_double_double_function(masm->isolate()), |
3550 0, 2); | 3577 0, 2); |
3551 __ pop(lr); | |
3552 __ GetCFunctionDoubleResult(double_result); | |
3553 } | 3578 } |
| 3579 __ pop(lr); |
| 3580 __ GetCFunctionDoubleResult(double_result); |
| 3581 __ jmp(&done); |
| 3582 } |
| 3583 |
| 3584 // Calculate power with integer exponent. |
| 3585 __ bind(&int_exponent); |
| 3586 |
| 3587 __ mov(scratch, exponent); // Back up exponent. |
| 3588 __ vmov(double_scratch, double_base); // Back up base. |
| 3589 __ vmov(double_result, 1.0); |
| 3590 |
| 3591 // Get absolute value of exponent. |
| 3592 __ cmp(scratch, Operand(0)); |
| 3593 __ mov(scratch2, Operand(0), LeaveCC, mi); |
| 3594 __ sub(scratch, scratch2, scratch, LeaveCC, mi); |
| 3595 |
| 3596 Label while_true; |
| 3597 __ bind(&while_true); |
| 3598 __ mov(scratch, Operand(scratch, ASR, 1), SetCC); |
| 3599 __ vmul(double_result, double_result, double_scratch, cs); |
| 3600 __ vmul(double_scratch, double_scratch, double_scratch, ne); |
| 3601 __ b(ne, &while_true); |
| 3602 |
| 3603 __ cmp(exponent, Operand(0)); |
| 3604 __ b(ge, &done); |
| 3605 __ vmov(double_scratch, 1.0); |
| 3606 __ vdiv(double_result, double_scratch, double_result); |
| 3607 // Test whether result is zero. Bail out to check for subnormal result. |
| 3608 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. |
| 3609 __ VFPCompareAndSetFlags(double_result, 0.0); |
| 3610 __ b(ne, &done); |
| 3611 |
| 3612 __ vmov(single_scratch, exponent); |
| 3613 __ vcvt_f64_s32(double_exponent, single_scratch); |
| 3614 |
| 3615 // Returning or bailing out. |
| 3616 Counters* counters = masm->isolate()->counters(); |
| 3617 if (exponent_type_ == ON_STACK) { |
| 3618 // The arguments are still on the stack. |
| 3619 __ bind(&call_runtime); |
| 3620 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); |
| 3621 |
| 3622 // The stub is called from non-optimized code, which expects the result |
| 3623 // as heap number in exponent. |
| 3624 __ bind(&done); |
| 3625 __ AllocateHeapNumber( |
| 3626 heapnumber, scratch, scratch2, heapnumbermap, &call_runtime); |
3554 __ vstr(double_result, | 3627 __ vstr(double_result, |
3555 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); | 3628 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); |
3556 __ mov(r0, heapnumber); | 3629 ASSERT(heapnumber.is(r0)); |
| 3630 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); |
3557 __ Ret(2 * kPointerSize); | 3631 __ Ret(2 * kPointerSize); |
| 3632 } else { |
| 3633 __ bind(&done); |
| 3634 __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2); |
| 3635 __ Ret(); |
3558 } | 3636 } |
3559 | |
3560 __ bind(&call_runtime); | |
3561 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); | |
3562 } | 3637 } |
3563 | 3638 |
3564 | 3639 |
3565 bool CEntryStub::NeedsImmovableCode() { | 3640 bool CEntryStub::NeedsImmovableCode() { |
3566 return true; | 3641 return true; |
3567 } | 3642 } |
3568 | 3643 |
3569 | 3644 |
3570 bool CEntryStub::IsPregenerated() { | 3645 bool CEntryStub::IsPregenerated() { |
3571 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && | 3646 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && |
(...skipping 3676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7248 __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10, | 7323 __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10, |
7249 &slow_elements); | 7324 &slow_elements); |
7250 __ Ret(); | 7325 __ Ret(); |
7251 } | 7326 } |
7252 | 7327 |
7253 #undef __ | 7328 #undef __ |
7254 | 7329 |
7255 } } // namespace v8::internal | 7330 } } // namespace v8::internal |
7256 | 7331 |
7257 #endif // V8_TARGET_ARCH_ARM | 7332 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |