aboutsummaryrefslogtreecommitdiffstats
path: root/qv4isel_masm.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2012-11-24 09:59:51 +0100
committerLars Knoll <lars.knoll@digia.com>2012-11-24 16:22:07 +0100
commit889ac44c014e8634dc8a3b3dff987481062b6cc5 (patch)
tree65e6b296bc9fa468c110814531604ed651c28733 /qv4isel_masm.cpp
parent7ec56d373d0c843ce19cfe03cc3ef0b0cb48a23b (diff)
Fix return from generated code when return value is passed on the stack
On ia32 the return VM value doesn't fit into a register. Instead the caller provides a pointer to where the return value can be stored as a first invisible argument. This is where we then copy the return value to. It is the callee's responsibility to remove that one invisible argument from the stack. Usually this is done using a "ret <n>" instruction, which however masm doesn't support, so we emulate it. That might not be any slower, since it's kind of replacing the CISC ret <n> instruction with RISC :) Change-Id: I4cb842e5a0a95a3d52867e66216dd711d627cf25 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'qv4isel_masm.cpp')
-rw-r--r--qv4isel_masm.cpp24
1 files changed, 22 insertions, 2 deletions
diff --git a/qv4isel_masm.cpp b/qv4isel_masm.cpp
index 2b5fe97d54..3bd4049547 100644
--- a/qv4isel_masm.cpp
+++ b/qv4isel_masm.cpp
@@ -95,10 +95,17 @@ void InstructionSelection::operator()(IR::Function *function)
locals = (locals + 1) & ~1;
enterStandardStackFrame(locals);
+ int contextPointer = 0;
+#ifndef VALUE_FITS_IN_REGISTER
+ // When the return VM value doesn't fit into a register, then
+ // the caller provides a pointer for storage as first argument.
+ // That shifts the index the context pointer argument by one.
+ contextPointer++;
+#endif
#if CPU(X86)
- loadPtr(addressForArgument(0), ContextRegister);
+ loadPtr(addressForArgument(contextPointer), ContextRegister);
#elif CPU(X86_64) || CPU(ARM)
- move(registerForArgument(0), ContextRegister);
+ move(registerForArgument(contextPointer), ContextRegister);
#else
assert(!"TODO");
#endif
@@ -112,6 +119,14 @@ void InstructionSelection::operator()(IR::Function *function)
}
leaveStandardStackFrame(locals);
+#ifndef VALUE_FITS_IN_REGISTER
+ // Emulate ret(n) instruction
+ // Pop off return address into scratch register ...
+ pop(ScratchRegister);
+ // ... and overwrite the invisible argument with
+ // the return address.
+ poke(ScratchRegister);
+#endif
ret();
QHashIterator<IR::BasicBlock *, QVector<Jump> > it(_patches);
@@ -704,7 +719,12 @@ void InstructionSelection::visitCJump(IR::CJump *s)
void InstructionSelection::visitRet(IR::Ret *s)
{
if (IR::Temp *t = s->expr->asTemp()) {
+#ifdef VALUE_FITS_IN_REGISTER
copyValue(ReturnValueRegister, t);
+#else
+ loadPtr(addressForArgument(0), ReturnValueRegister);
+ copyValue(Address(ReturnValueRegister, 0), t);
+#endif
return;
}
Q_UNIMPLEMENTED();