| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 25 matching lines...) Expand all Loading... |
| 36 #include "regexp-macro-assembler.h" | 36 #include "regexp-macro-assembler.h" |
| 37 #include "register-allocator-inl.h" | 37 #include "register-allocator-inl.h" |
| 38 #include "scopes.h" | 38 #include "scopes.h" |
| 39 #include "virtual-frame-inl.h" | 39 #include "virtual-frame-inl.h" |
| 40 | 40 |
| 41 namespace v8 { | 41 namespace v8 { |
| 42 namespace internal { | 42 namespace internal { |
| 43 | 43 |
| 44 #define __ ACCESS_MASM(masm_) | 44 #define __ ACCESS_MASM(masm_) |
| 45 | 45 |
| 46 static int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); | |
| 47 | |
| 48 // ------------------------------------------------------------------------- | 46 // ------------------------------------------------------------------------- |
| 49 // Platform-specific DeferredCode functions. | 47 // Platform-specific DeferredCode functions. |
| 50 | 48 |
| 51 void DeferredCode::SaveRegisters() { | 49 void DeferredCode::SaveRegisters() { |
| 52 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { | 50 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
| 53 int action = registers_[i]; | 51 int action = registers_[i]; |
| 54 if (action == kPush) { | 52 if (action == kPush) { |
| 55 __ push(RegisterAllocator::ToRegister(i)); | 53 __ push(RegisterAllocator::ToRegister(i)); |
| 56 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { | 54 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { |
| 57 __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); | 55 __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); |
| (...skipping 7492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7550 Label cache_miss; | 7548 Label cache_miss; |
| 7551 __ cmpq(rbx, Operand(rcx, 0)); | 7549 __ cmpq(rbx, Operand(rcx, 0)); |
| 7552 __ j(not_equal, &cache_miss); | 7550 __ j(not_equal, &cache_miss); |
| 7553 // Cache hit! | 7551 // Cache hit! |
| 7554 __ movq(rax, Operand(rcx, 2 * kIntSize)); | 7552 __ movq(rax, Operand(rcx, 2 * kIntSize)); |
| 7555 __ fstp(0); // Clear FPU stack. | 7553 __ fstp(0); // Clear FPU stack. |
| 7556 __ ret(kPointerSize); | 7554 __ ret(kPointerSize); |
| 7557 | 7555 |
| 7558 __ bind(&cache_miss); | 7556 __ bind(&cache_miss); |
| 7559 // Update cache with new value. | 7557 // Update cache with new value. |
| 7558 Label nan_result; |
| 7559 GenerateOperation(masm, &nan_result); |
| 7560 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); | 7560 __ AllocateHeapNumber(rax, rdi, &runtime_call_clear_stack); |
| 7561 GenerateOperation(masm); | |
| 7562 __ movq(Operand(rcx, 0), rbx); | 7561 __ movq(Operand(rcx, 0), rbx); |
| 7563 __ movq(Operand(rcx, 2 * kIntSize), rax); | 7562 __ movq(Operand(rcx, 2 * kIntSize), rax); |
| 7564 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | 7563 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); |
| 7565 __ ret(kPointerSize); | 7564 __ ret(kPointerSize); |
| 7566 | 7565 |
| 7567 __ bind(&runtime_call_clear_stack); | 7566 __ bind(&runtime_call_clear_stack); |
| 7568 __ fstp(0); | 7567 __ fstp(0); |
| 7569 __ bind(&runtime_call); | 7568 __ bind(&runtime_call); |
| 7570 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); | 7569 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| 7570 |
| 7571 __ bind(&nan_result); |
| 7572 __ fstp(0); // Remove argument from FPU stack. |
| 7573 __ LoadRoot(rax, Heap::kNanValueRootIndex); |
| 7574 __ movq(Operand(rcx, 0), rbx); |
| 7575 __ movq(Operand(rcx, 2 * kIntSize), rax); |
| 7576 __ ret(kPointerSize); |
| 7571 } | 7577 } |
| 7572 | 7578 |
| 7573 | 7579 |
| 7574 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 7580 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
| 7575 switch (type_) { | 7581 switch (type_) { |
| 7576 // Add more cases when necessary. | 7582 // Add more cases when necessary. |
| 7577 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 7583 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
| 7578 case TranscendentalCache::COS: return Runtime::kMath_cos; | 7584 case TranscendentalCache::COS: return Runtime::kMath_cos; |
| 7579 default: | 7585 default: |
| 7580 UNIMPLEMENTED(); | 7586 UNIMPLEMENTED(); |
| 7581 return Runtime::kAbort; | 7587 return Runtime::kAbort; |
| 7582 } | 7588 } |
| 7583 } | 7589 } |
| 7584 | 7590 |
| 7585 | 7591 |
| 7586 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { | 7592 void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, |
| 7587 // Only free register is rdi. | 7593 Label* on_nan_result) { |
| 7594 // Registers: |
| 7595 // rbx: Bits of input double. Must be preserved. |
| 7596 // rcx: Pointer to cache entry. Must be preserved. |
| 7597 // st(0): Input double |
| 7588 Label done; | 7598 Label done; |
| 7589 ASSERT(type_ == TranscendentalCache::SIN || | 7599 ASSERT(type_ == TranscendentalCache::SIN || |
| 7590 type_ == TranscendentalCache::COS); | 7600 type_ == TranscendentalCache::COS); |
| 7591 // More transcendental types can be added later. | 7601 // More transcendental types can be added later. |
| 7592 | 7602 |
| 7593 // Both fsin and fcos require arguments in the range +/-2^63 and | 7603 // Both fsin and fcos require arguments in the range +/-2^63 and |
| 7594 // return NaN for infinities and NaN. They can share all code except | 7604 // return NaN for infinities and NaN. They can share all code except |
| 7595 // the actual fsin/fcos operation. | 7605 // the actual fsin/fcos operation. |
| 7596 Label in_range; | 7606 Label in_range; |
| 7597 // If argument is outside the range -2^63..2^63, fsin/cos doesn't | 7607 // If argument is outside the range -2^63..2^63, fsin/cos doesn't |
| 7598 // work. We must reduce it to the appropriate range. | 7608 // work. We must reduce it to the appropriate range. |
| 7599 __ movq(rdi, rbx); | 7609 __ movq(rdi, rbx); |
| 7600 // Move exponent and sign bits to low bits. | 7610 // Move exponent and sign bits to low bits. |
| 7601 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); | 7611 __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); |
| 7602 // Remove sign bit. | 7612 // Remove sign bit. |
| 7603 __ andl(rdi, Immediate((1 << HeapNumber::KExponentBits) - 1)); | 7613 __ andl(rdi, Immediate((1 << HeapNumber::KExponentBits) - 1)); |
| 7604 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); | 7614 int supported_exponent_limit = (63 + HeapNumber::kExponentBias); |
| 7605 __ cmpl(rdi, Immediate(supported_exponent_limit)); | 7615 __ cmpl(rdi, Immediate(supported_exponent_limit)); |
| 7606 __ j(below, &in_range); | 7616 __ j(below, &in_range); |
| 7607 // Check for infinity and NaN. Both return NaN for sin. | 7617 // Check for infinity and NaN. Both return NaN for sin. |
| 7608 __ cmpl(rdi, Immediate(0x7ff)); | 7618 __ cmpl(rdi, Immediate(0x7ff)); |
| 7609 Label non_nan_result; | 7619 __ j(equal, on_nan_result); |
| 7610 __ j(not_equal, &non_nan_result); | |
| 7611 // Input is +/-Infinity or NaN. Result is NaN. | |
| 7612 __ fstp(0); // Clear fpu stack. | |
| 7613 // NaN is represented by 0x7ff8000000000000. | |
| 7614 __ movq(rdi, kNaNValue, RelocInfo::NONE); | |
| 7615 __ push(rdi); | |
| 7616 __ fld_d(Operand(rsp, 0)); | |
| 7617 __ addq(rsp, Immediate(kPointerSize)); | |
| 7618 __ jmp(&done); | |
| 7619 | |
| 7620 __ bind(&non_nan_result); | |
| 7621 | 7620 |
| 7622 // Use fpmod to restrict argument to the range +/-2*PI. | 7621 // Use fpmod to restrict argument to the range +/-2*PI. |
| 7623 __ movq(rdi, rax); // Save rax before using fnstsw_ax. | |
| 7624 __ fldpi(); | 7622 __ fldpi(); |
| 7625 __ fadd(0); | 7623 __ fadd(0); |
| 7626 __ fld(1); | 7624 __ fld(1); |
| 7627 // FPU Stack: input, 2*pi, input. | 7625 // FPU Stack: input, 2*pi, input. |
| 7628 { | 7626 { |
| 7629 Label no_exceptions; | 7627 Label no_exceptions; |
| 7630 __ fwait(); | 7628 __ fwait(); |
| 7631 __ fnstsw_ax(); | 7629 __ fnstsw_ax(); |
| 7632 // Clear if Illegal Operand or Zero Division exceptions are set. | 7630 // Clear if Illegal Operand or Zero Division exceptions are set. |
| 7633 __ testl(rax, Immediate(5)); | 7631 __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. |
| 7634 __ j(zero, &no_exceptions); | 7632 __ j(zero, &no_exceptions); |
| 7635 __ fnclex(); | 7633 __ fnclex(); |
| 7636 __ bind(&no_exceptions); | 7634 __ bind(&no_exceptions); |
| 7637 } | 7635 } |
| 7638 | 7636 |
| 7639 // Compute st(0) % st(1) | 7637 // Compute st(0) % st(1) |
| 7640 { | 7638 { |
| 7641 Label partial_remainder_loop; | 7639 Label partial_remainder_loop; |
| 7642 __ bind(&partial_remainder_loop); | 7640 __ bind(&partial_remainder_loop); |
| 7643 __ fprem1(); | 7641 __ fprem1(); |
| 7644 __ fwait(); | 7642 __ fwait(); |
| 7645 __ fnstsw_ax(); | 7643 __ fnstsw_ax(); |
| 7646 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. | 7644 __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. |
| 7647 // If C2 is set, computation only has partial result. Loop to | 7645 // If C2 is set, computation only has partial result. Loop to |
| 7648 // continue computation. | 7646 // continue computation. |
| 7649 __ j(not_zero, &partial_remainder_loop); | 7647 __ j(not_zero, &partial_remainder_loop); |
| 7650 } | 7648 } |
| 7651 // FPU Stack: input, 2*pi, input % 2*pi | 7649 // FPU Stack: input, 2*pi, input % 2*pi |
| 7652 __ fstp(2); | 7650 __ fstp(2); |
| 7653 // FPU Stack: input % 2*pi, 2*pi, | 7651 // FPU Stack: input % 2*pi, 2*pi, |
| 7654 __ fstp(0); | 7652 __ fstp(0); |
| 7655 // FPU Stack: input % 2*pi | 7653 // FPU Stack: input % 2*pi |
| 7656 __ movq(rax, rdi); // Restore rax (allocated HeapNumber pointer). | |
| 7657 | |
| 7658 // FPU Stack: input % 2*pi | |
| 7659 __ bind(&in_range); | 7654 __ bind(&in_range); |
| 7660 switch (type_) { | 7655 switch (type_) { |
| 7661 case TranscendentalCache::SIN: | 7656 case TranscendentalCache::SIN: |
| 7662 __ fsin(); | 7657 __ fsin(); |
| 7663 break; | 7658 break; |
| 7664 case TranscendentalCache::COS: | 7659 case TranscendentalCache::COS: |
| 7665 __ fcos(); | 7660 __ fcos(); |
| 7666 break; | 7661 break; |
| 7667 default: | 7662 default: |
| 7668 UNREACHABLE(); | 7663 UNREACHABLE(); |
| (...skipping 3531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11200 __ j(not_zero, &partial_remainder_loop); | 11195 __ j(not_zero, &partial_remainder_loop); |
| 11201 } | 11196 } |
| 11202 | 11197 |
| 11203 Label valid_result; | 11198 Label valid_result; |
| 11204 Label return_result; | 11199 Label return_result; |
| 11205 // If Invalid Operand or Zero Division exceptions are set, | 11200 // If Invalid Operand or Zero Division exceptions are set, |
| 11206 // return NaN. | 11201 // return NaN. |
| 11207 __ testb(rax, Immediate(5)); | 11202 __ testb(rax, Immediate(5)); |
| 11208 __ j(zero, &valid_result); | 11203 __ j(zero, &valid_result); |
| 11209 __ fstp(0); // Drop result in st(0). | 11204 __ fstp(0); // Drop result in st(0). |
| 11205 int64_t kNaNValue = V8_INT64_C(0x7ff8000000000000); |
| 11210 __ movq(rcx, kNaNValue, RelocInfo::NONE); | 11206 __ movq(rcx, kNaNValue, RelocInfo::NONE); |
| 11211 __ movq(Operand(rsp, kPointerSize), rcx); | 11207 __ movq(Operand(rsp, kPointerSize), rcx); |
| 11212 __ movsd(xmm0, Operand(rsp, kPointerSize)); | 11208 __ movsd(xmm0, Operand(rsp, kPointerSize)); |
| 11213 __ jmp(&return_result); | 11209 __ jmp(&return_result); |
| 11214 | 11210 |
| 11215 // If result is valid, return that. | 11211 // If result is valid, return that. |
| 11216 __ bind(&valid_result); | 11212 __ bind(&valid_result); |
| 11217 __ fstp_d(Operand(rsp, kPointerSize)); | 11213 __ fstp_d(Operand(rsp, kPointerSize)); |
| 11218 __ movsd(xmm0, Operand(rsp, kPointerSize)); | 11214 __ movsd(xmm0, Operand(rsp, kPointerSize)); |
| 11219 | 11215 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 11234 // Call the function from C++. | 11230 // Call the function from C++. |
| 11235 return FUNCTION_CAST<ModuloFunction>(buffer); | 11231 return FUNCTION_CAST<ModuloFunction>(buffer); |
| 11236 } | 11232 } |
| 11237 | 11233 |
| 11238 #endif | 11234 #endif |
| 11239 | 11235 |
| 11240 | 11236 |
| 11241 #undef __ | 11237 #undef __ |
| 11242 | 11238 |
| 11243 } } // namespace v8::internal | 11239 } } // namespace v8::internal |
| OLD | NEW |