Index: src/x64/stub-cache-x64.cc |
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc |
index 58c76d697271159a3a5e458a929cae11def12268..6883d386f4ee922c2c75560dbe1b69a5c071c2bd 100644 |
--- a/src/x64/stub-cache-x64.cc |
+++ b/src/x64/stub-cache-x64.cc |
@@ -2200,8 +2200,130 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall( |
Handle<JSFunction> function, |
Handle<String> name, |
Code::StubType type) { |
- // TODO(872): implement this. |
- return Handle<Code>::null(); |
+ // ----------- S t a t e ------------- |
+ // -- rcx : name |
+ // -- rsp[0] : return address |
+ // -- rsp[(argc - n) * 4] : arg[n] (zero-based) |
+ // -- ... |
+ // -- rsp[(argc + 1) * 4] : receiver |
+ // ----------------------------------- |
+ |
+ if (!CpuFeatures::IsSupported(SSE2)) { |
+ return Handle<Code>::null(); |
+ } |
+ |
+ CpuFeatureScope use_sse2(masm(), SSE2); |
+ |
+ const int argc = arguments().immediate(); |
+ |
+ // If the object is not a JSObject or we got an unexpected number of |
+ // arguments, bail out to the regular call. |
+ if (!object->IsJSObject() || argc != 1) { |
+ return Handle<Code>::null(); |
+ } |
+ |
+ Label miss; |
+ GenerateNameCheck(name, &miss); |
+ |
+ if (cell.is_null()) { |
+ __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
+ |
+ STATIC_ASSERT(kSmiTag == 0); |
+ __ JumpIfSmi(rdx, &miss); |
+ |
+ CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi, |
+ name, &miss); |
+ } else { |
+ ASSERT(cell->value() == *function); |
+ GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name, |
+ &miss); |
+ GenerateLoadFunctionFromCell(cell, function, &miss); |
+ } |
+ |
+ // Load the (only) argument into rax. |
+ __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
+ |
+ // Check if the argument is a smi. |
+ Label smi; |
+ STATIC_ASSERT(kSmiTag == 0); |
+ __ JumpIfSmi(rax, &smi); |
+ |
+ // Check if the argument is a heap number and load its value into xmm0. |
+ Label slow; |
+ __ CheckMap(rax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); |
+ __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
+ |
+ // Check if the argument is strictly positive. Note this also discards NaN. |
+ __ xorpd(xmm1, xmm1); |
+ __ ucomisd(xmm0, xmm1); |
+ __ j(below_equal, &slow); |
+ |
+ // Do a truncating conversion. |
+ __ cvttsd2si(rax, xmm0); |
+ |
+ // Checks for 0x80000000 which signals a failed conversion. |
+ Label conversion_failure; |
+ __ cmpl(rax, Immediate(0x80000000)); |
+ __ j(equal, &conversion_failure); |
+ |
+ // Smi tag and return. |
+ __ Integer32ToSmi(rax, rax); |
+ __ bind(&smi); |
+ __ ret(2 * kPointerSize); |
+ |
+ // Check if the argument is < 2^kMantissaBits. |
+ Label already_round; |
+ __ bind(&conversion_failure); |
+ int64_t kTwoMantissaBits= V8_INT64_C(0x4330000000000000); |
+ __ movq(rbx, kTwoMantissaBits, RelocInfo::NONE64); |
+ __ movq(xmm1, rbx); |
+ __ ucomisd(xmm0, xmm1); |
+ __ j(above_equal, &already_round); |
+ |
+ // Save a copy of the argument. |
+ __ movaps(xmm2, xmm0); |
+ |
+ // Compute (argument + 2^kMantissaBits) - 2^kMantissaBits. |
+ __ addsd(xmm0, xmm1); |
+ __ subsd(xmm0, xmm1); |
+ |
+ // Compare the argument and the tentative result to get the right mask: |
+ // if xmm2 < xmm0: |
+ // xmm2 = 1...1 |
+ // else: |
+ // xmm2 = 0...0 |
+ __ cmpltsd(xmm2, xmm0); |
+ |
+ // Subtract 1 if the argument was less than the tentative result. |
+ int64_t kOne = V8_INT64_C(0x3ff0000000000000); |
+ __ movq(rbx, kOne, RelocInfo::NONE64); |
+ __ movq(xmm1, rbx); |
+ __ andpd(xmm1, xmm2); |
+ __ subsd(xmm0, xmm1); |
+ |
+ // Return a new heap number. |
+ __ AllocateHeapNumber(rax, rbx, &slow); |
+ __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); |
+ __ ret(2 * kPointerSize); |
+ |
+ // Return the argument (when it's an already round heap number). |
+ __ bind(&already_round); |
+ __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
+ __ ret(2 * kPointerSize); |
+ |
+ // Tail call the full function. We do not have to patch the receiver |
+ // because the function makes no use of it. |
+ __ bind(&slow); |
+ ParameterCount expected(function); |
+ __ InvokeFunction(function, expected, arguments(), |
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); |
+ |
+ __ bind(&miss); |
+ // rcx: function name. |
+ GenerateMissBranch(); |
+ |
+ // Return the generated code. |
+ return GetCode(type, name); |
} |