Chromium Code Reviews| Index: src/arm/stub-cache-arm.cc |
| =================================================================== |
| --- src/arm/stub-cache-arm.cc (revision 5791) |
| +++ src/arm/stub-cache-arm.cc (working copy) |
| @@ -1676,8 +1676,165 @@ |
| JSGlobalPropertyCell* cell, |
| JSFunction* function, |
| String* name) { |
| - // TODO(872): implement this. |
| - return Heap::undefined_value(); |
| + // ----------- S t a t e ------------- |
| + // -- r2 : function name |
| + // -- lr : return address |
| + // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) |
| + // -- ... |
| + // -- sp[argc * 4] : receiver |
| + // ----------------------------------- |
| + |
| + 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, slow; |
| + GenerateNameCheck(name, &miss); |
| + |
| + if (cell == NULL) { |
| + __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); |
| + |
| + STATIC_ASSERT(kSmiTag == 0); |
| + __ BranchOnNotSmi(r1, &miss); |
|
m.m.capewell
2010/11/16 15:05:17
Fixed this - should be BranchOnSmi().
|
| + |
| + CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name, |
| + &miss); |
| + } else { |
| + ASSERT(cell->value() == function); |
| + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); |
| + GenerateLoadFunctionFromCell(cell, function, &miss); |
| + } |
| + |
| + // Load the (only) argument into r0. |
| + __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); |
| + |
| + // If the argument is a smi, just return. |
| + STATIC_ASSERT(kSmiTag == 0); |
| + __ tst(r0, Operand(kSmiTagMask)); |
| + __ Drop(argc + 1, eq); |
| + __ Ret(eq); |
| + |
| + __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true); |
| + |
| + if (CpuFeatures::IsSupported(VFP3)) { |
| + CpuFeatures::Scope scope_vfp3(VFP3); |
| + |
| + Label wont_fit_smi, no_vfp_exception, restore_fpscr_and_return; |
| + |
| + // If vfp3 is enabled, we use the fpu rounding with the RM (round towards |
| + // minus infinity) mode. |
| + |
| + // Load the HeapNumber value. |
| + // We will need access to the value in the core registers, so we load it |
| + // with ldrd and move it to the fpu. It also spares a sub instruction for |
| + // updating the HeapNumber value address, as vldr expects a multiple |
| + // of 4 offset. |
| + __ Ldrd(r4, r5, MemOperand(r0, HeapNumber::kValueOffset - kHeapObjectTag)); |
|
Erik Corry
2010/11/10 13:57:19
Use FieldMemOperand for this.
m.m.capewell
2010/11/16 15:05:17
Done.
|
| + __ vmov(d1, r4, r5); |
| + |
| + // Backup FPSCR. |
| + __ vmrs(r3); |
| + // Set custom FPCSR: |
| + // - Set rounding mode to "Round towards Minus Infinity |
| + // (ie bits [23:22] = 0b10). |
| + // - Clear vfp cumulative exception flags (bits [3:0]). |
| + // - Make sure Flush-to-zero mode control bit is unset (bit 22). |
| + __ bic(r9, r3, Operand((1 << 22) | 0xf | (1 << 24))); |
|
Erik Corry
2010/11/10 13:57:19
This should be with named constants. For example
m.m.capewell
2010/11/16 15:05:17
Done.
|
| + __ orr(r9, r9, Operand(1 << 23)); |
| + __ vmsr(r9); |
| + |
| + // Convert the argument to an integer. |
| + __ vcvt_s32_f64(s0, d1, Assembler::FPSCRRounding, al); |
| + |
| + // Use vcvt latency to start checking for special cases. |
| + // Get the argument exponent and clear the sign bit. |
| + __ bic(r6, r5, Operand(HeapNumber::kSignMask)); |
| + __ mov(r6, Operand(r6, LSR, HeapNumber::kMantissaBitsInTopWord)); |
| + |
| + // Retrieve FCPSR and check for vfp exceptions. |
| + __ vmrs(r9); |
| + __ tst(r9, Operand(0xf)); |
|
Erik Corry
2010/11/10 13:57:19
Named constant here too.
m.m.capewell
2010/11/16 15:05:17
Done.
|
| + __ b(&no_vfp_exception, eq); |
| + |
| + // Check for NaN, Infinity, and -Infinity. |
| + // They are invariant through a Math.Floor call, so just |
| + // return the original argument. |
| + __ sub(r7, r6, Operand(HeapNumber::kExponentMask |
| + >> HeapNumber::kMantissaBitsInTopWord), SetCC); |
| + __ b(&restore_fpscr_and_return, eq); |
| + // We had an overflow or underflow in the conversion. Check if we |
| + // have a big exponent. |
| + __ cmp(r7, Operand(HeapNumber::kMantissaBits)); |
| + // If greater or equal, the argument is already round and in r0. |
| + __ b(&restore_fpscr_and_return, ge); |
| + __ b(&slow); |
| + |
| + __ bind(&no_vfp_exception); |
| + // Move the result back to general purpose register r0. |
| + __ vmov(r0, s0); |
| + // Check if the result fits into a smi. |
| + __ add(r1, r0, Operand(0x40000000), SetCC); |
| + __ b(&wont_fit_smi, mi); |
| + // Tag the result. |
| + STATIC_ASSERT(kSmiTag == 0); |
| + __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| + |
| + // Check for -0. |
| + __ cmp(r0, Operand(0)); |
| + __ b(&restore_fpscr_and_return, ne); |
| + // r5 already holds the HeapNumber exponent. |
| + __ tst(r5, Operand(HeapNumber::kSignMask)); |
| + // If our HeapNumber is negative it was -0, so load its address and return. |
| + // Else r0 is loaded with 0, so we can also just return. |
| + __ ldr(r0, MemOperand(sp, 0 * kPointerSize), ne); |
| + |
| + __ bind(&restore_fpscr_and_return); |
| + // Restore FPSCR and return. |
| + __ vmsr(r3); |
| + __ Drop(argc + 1); |
| + __ Ret(); |
| + |
| + __ bind(&wont_fit_smi); |
| + __ bind(&slow); |
| + // Restore FPCSR and fall to slow case. |
| + __ vmsr(r3); |
| + } else { |
| + Label return_; |
| + |
|
Erik Corry
2010/11/10 13:57:19
This non-VFP code makes testing difficult and it o
m.m.capewell
2010/11/16 15:05:17
Done.
|
| + __ Ldrd(r4, r5, MemOperand(r0, HeapNumber::kValueOffset - kHeapObjectTag)); |
| + // Get the argument exponent and clear the sign bit. |
| + __ mov(r6, Operand(r5, LSR, HeapNumber::kMantissaBitsInTopWord)); |
| + __ bic(r6, r6, Operand(1 << (HeapNumber::kNonMantissaBitsInTopWord - 1))); |
| + // Check for NaN, Infinity, and -Infinity. |
| + // They are invariant through a Math.Floor call, so just |
| + // return the original argument. |
| + __ sub(r7, r6, Operand((1 << HeapNumber::kExponentBits) -1), SetCC); |
| + __ b(&return_, eq); |
| + // Check for a high exponent, which implies an already round value. |
| + __ cmp(r7, Operand(HeapNumber::kMantissaBits)); |
| + __ b(&slow, lt); |
| + |
| + // Return. |
| + __ bind(&return_); |
| + __ Drop(argc + 1); |
| + __ Ret(); |
| + |
| + __ bind(&slow); |
| + } |
| + |
| + // Tail call the full function. We do not have to patch the receiver |
| + // because the function makes no use of it. |
| + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| + |
| + __ bind(&miss); |
| + // r2: function name. |
| + MaybeObject* obj = GenerateMissBranch(); |
| + if (obj->IsFailure()) return obj; |
| + |
| + // Return the generated code. |
| + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); |
| } |