diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-11-24 09:59:51 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@digia.com> | 2012-11-24 16:22:07 +0100 |
commit | 889ac44c014e8634dc8a3b3dff987481062b6cc5 (patch) | |
tree | 65e6b296bc9fa468c110814531604ed651c28733 /qv4isel_masm.cpp | |
parent | 7ec56d373d0c843ce19cfe03cc3ef0b0cb48a23b (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.cpp | 24 |
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(); |