[masm] Fix writing of return value on arm
authorSimon Hausmann <simon.hausmann@digia.com>
Sun, 17 Feb 2013 20:44:05 +0000 (21:44 +0100)
committerErik Verbruggen <erik.verbruggen@digia.com>
Tue, 19 Feb 2013 10:12:03 +0000 (11:12 +0100)
On arm the pointer to the storage of the VM::Value to return is passed in r0.
The value in that register is destroyed soon after, so later when we want to
access it in visitRet() we'll get garbage.

To solve this we behave similar to gcc now, which upon function entry saves the
values of the registers used for parameter passing onto the stack. Except that
on arm we now do this before pushing the link register, which makes the stack
frame look identical to ia32. (old ebp / return address / arg 0 / arg 1 / ...)

With that we can theoretically access the pointer to the return value storage.
In practice we also need to change meaning of the addressForArgument() helper
function to only return the address of arguments on the stack. But that makes
sense since Address() is meaningless for values passed in registers.

Also tightened the #ifdef in visitRet() for determining whether to use the
return value register or not. That wasn't strictly necessary, but makes
the condition a bit clearer.

Change-Id: I6fbef6645275ebaa75484d666b4bbfd073f945a5
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
src/v4/qv4isel_masm.cpp
src/v4/qv4isel_masm_p.h

index 6010321..bf1d129 100644 (file)
@@ -1011,7 +1011,7 @@ void InstructionSelection::visitCJump(IR::CJump *s)
 void InstructionSelection::visitRet(IR::Ret *s)
 {
     if (IR::Temp *t = s->expr->asTemp()) {
-#ifdef VALUE_FITS_IN_REGISTER
+#if defined(ARGUMENTS_IN_REGISTERS) && defined(VALUE_FITS_IN_REGISTER)
         _as->copyValue(Assembler::ReturnValueRegister, t);
 #else
         _as->loadPtr(addressForArgument(0), Assembler::ReturnValueRegister);
index 821755c..c68ee91 100644 (file)
@@ -147,11 +147,22 @@ public:
     };
     inline void platformEnterStandardStackFrame()
     {
+        // Move the register arguments onto the stack as if they were
+        // pushed by the caller, just like on ia32. This gives us consistent
+        // access to the parameters if we need to.
+        push(JSC::ARMRegisters::r3);
+        push(JSC::ARMRegisters::r2);
+        push(JSC::ARMRegisters::r1);
+        push(JSC::ARMRegisters::r0);
         push(JSC::ARMRegisters::lr);
     }
     inline void platformLeaveStandardStackFrame()
     {
         pop(JSC::ARMRegisters::lr);
+        push(JSC::ARMRegisters::r0);
+        push(JSC::ARMRegisters::r1);
+        push(JSC::ARMRegisters::r2);
+        push(JSC::ARMRegisters::r3);
     }
 #else
 #error Argh.
@@ -775,13 +786,10 @@ protected:
 
     Address addressForArgument(int index) const
     {
-        if (index < Assembler::RegisterArgumentCount)
-            return Address(_as->registerForArgument(index), 0);
-
         // StackFrameRegister points to its old value on the stack, and above
         // it we have the return address, hence the need to step over two
         // values before reaching the first argument.
-        return Address(Assembler::StackFrameRegister, (index - Assembler::RegisterArgumentCount + 2) * sizeof(void*));
+        return Address(Assembler::StackFrameRegister, (index + 2) * sizeof(void*));
     }
 
     // Some run-time functions take (Value* args, int argc). This function is for populating