Chromium Code Reviews| Index: src/ia32/stub-cache-ia32.cc |
| diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc |
| index 828e71a8fbbc839ac93c0d73ca4c4a9d235d864e..d40b51eee18c33e0209d0a7dd2071e4dd8f324dd 100644 |
| --- a/src/ia32/stub-cache-ia32.cc |
| +++ b/src/ia32/stub-cache-ia32.cc |
| @@ -1813,6 +1813,131 @@ Object* CallStubCompiler::CompileStringFromCharCodeCall( |
| } |
| +Object* CallStubCompiler::CompileMathFloorCall(Object* object, |
| + JSObject* holder, |
| + JSGlobalPropertyCell* cell, |
| + JSFunction* function, |
| + String* name) { |
| + // ----------- S t a t e ------------- |
| + // -- ecx : name |
| + // -- esp[0] : return address |
| + // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| + // -- ... |
| + // -- esp[(argc + 1) * 4] : receiver |
| + // ----------------------------------- |
| + |
| + if (!CpuFeatures::IsSupported(SSE2)) return Heap::undefined_value(); |
| + CpuFeatures::Scope use_sse2(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 Heap::undefined_value(); |
| + |
| + Label miss; |
| + GenerateNameCheck(name, &miss); |
| + |
| + if (cell == NULL) { |
| + __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| + |
| + STATIC_ASSERT(kSmiTag == 0); |
| + __ test(edx, Immediate(kSmiTagMask)); |
| + __ j(zero, &miss); |
| + |
| + CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, |
| + &miss); |
| + } else { |
| + ASSERT(cell->value() == function); |
| + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); |
| + GenerateLoadFunctionFromCell(cell, function, &miss); |
| + } |
| + |
| + // Load the (only) argument into eax. |
| + __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| + |
| + // Check if the argument is a smi. |
| + Label smi; |
| + STATIC_ASSERT(kSmiTag == 0); |
| + __ test(eax, Immediate(kSmiTagMask)); |
| + __ j(zero, &smi); |
| + |
| + // Check if the argument is a heap number and load its value into xmm0. |
| + Label slow; |
| + __ CheckMap(eax, Factory::heap_number_map(), &slow, true); |
| + __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| + |
| + // Check if the argument is strictly positive. Note this also |
| + // discards NaN. |
|
Erik Corry
2010/09/20 11:56:50
It might be nice to detect +- zero and pass it thr
Vitaly Repeshko
2010/09/21 12:54:49
I filed a bug to consider extending it.
|
| + __ xorpd(xmm1, xmm1); |
| + __ ucomisd(xmm0, xmm1); |
| + __ j(below_equal, &slow); |
| + |
| + // Do a truncating conversion. |
| + __ cvttsd2si(eax, Operand(xmm0)); |
| + |
| + // Check if the result fits into a smi. Note this also checks for |
| + // 0x80000000 which signals a failed conversion. |
| + Label wont_fit_into_smi; |
| + __ test(eax, Immediate(0xc0000000)); |
| + __ j(not_zero, &wont_fit_into_smi); |
| + |
| + // Smi tag and return. |
| + __ SmiTag(eax); |
| + __ bind(&smi); |
| + __ ret(2 * kPointerSize); |
| + |
| + // Check if the argument is < 2^kMantissaBits. |
| + Label already_round; |
| + __ bind(&wont_fit_into_smi); |
| + __ LoadPowerOf2(xmm1, ebx, HeapNumber::kMantissaBits); |
| + __ ucomisd(xmm0, xmm1); |
| + __ j(above_equal, &already_round); |
| + |
| + // Save a copy of the argument. |
| + __ movaps(xmm2, Operand(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. |
| + __ LoadPowerOf2(xmm1, ebx, 0); |
| + __ andpd(xmm1, Operand(xmm2)); |
| + __ subsd(xmm0, xmm1); |
| + |
| + // Return a new heap number. |
| + __ AllocateHeapNumber(eax, ebx, edx, &slow); |
| + __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| + __ ret(2 * kPointerSize); |
| + |
| + // Return the argument (when it's an already round heap number). |
| + __ bind(&already_round); |
| + __ mov(eax, Operand(esp, 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); |
| + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| + |
| + __ bind(&miss); |
| + // ecx: function name. |
| + Object* obj = GenerateMissBranch(); |
| + if (obj->IsFailure()) return obj; |
| + |
| + // Return the generated code. |
| + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); |
| +} |
| + |
| + |
| Object* CallStubCompiler::CompileCallConstant(Object* object, |
| JSObject* holder, |
| JSFunction* function, |