| 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);
|
| }
|
|
|
|
|
|
|