depth, and we RETURN.
This arrangement makes it simple to do f-i-dynamic since the Addr#
- value is the first arg anyway. It also has the virtue that the
- stack is GC-understandable at all times.
+ value is the first arg anyway.
The marshalling code is generated specifically for this
call site, and so knows exactly the (Haskell) stack
recordMallocBc addr_of_marshaller `thenBc_`
let
-- Offset of the next stack frame down the stack. The CCALL
- -- instruction will temporarily shift the stack pointer up by
- -- this much during the call, and shift it down again afterwards.
- -- This is so that we don't have to worry about constructing
- -- a bitmap to describe the stack layout of the call: the
- -- contents of this part of the stack are irrelevant anyway,
- -- it is only used to communicate the arguments to the
- -- marshalling code.
+ -- instruction needs to describe the chunk of stack containing
+ -- the ccall args to the GC, so it needs to know how large it
+ -- is. See comment in Interpreter.c with the CCALL instruction.
stk_offset = d_after_r - s
-- do the call
int o_itbl = BCO_NEXT;
void(*marshall_fn)(void*) = (void (*)(void*))BCO_LIT(o_itbl);
- // Shift the stack pointer down to the next relevant stack
- // frame during the call. See comment in ByteCodeGen.lhs.
- Sp += stk_offset;
+ // There are a bunch of non-ptr words on the stack (the
+ // ccall args, the ccall fun address and space for the
+ // result), which we need to cover with an info table
+ // since we might GC during this call.
+ //
+ // We know how many (non-ptr) words there are before the
+ // next valid stack frame: it is the stk_offset arg to the
+ // CCALL instruction. So we build a RET_DYN stack frame
+ // on the stack frame to describe this chunk of stack.
+ //
+ Sp -= RET_DYN_SIZE + sizeofW(StgRetDyn);
+ ((StgRetDyn *)Sp)->liveness = ALL_NON_PTRS | N_NONPTRS(stk_offset);
+ ((StgRetDyn *)Sp)->info = (StgInfoTable *)&stg_gc_gen_info;
+
SAVE_STACK_POINTERS;
tok = suspendThread(&cap->r,rtsFalse);
- marshall_fn ( (void*)(& Sp[-stk_offset] ) );
+
+ // Careful: suspendThread might have shifted the stack
+ // around (stack squeezing), so we have to grab the real
+ // Sp out of the TSO to find the ccall args again:
+ marshall_fn ( (void*)(cap->r.rCurrentTSO->sp + RET_DYN_SIZE
+ + sizeofW(StgRetDyn)) );
+
+ // And restart the thread again, popping the RET_DYN frame.
cap = (Capability *)((void *)resumeThread(tok,rtsFalse) - sizeof(StgFunTable));
LOAD_STACK_POINTERS;
- Sp -= stk_offset;
+ Sp += RET_DYN_SIZE + sizeofW(StgRetDyn);
goto nextInsn;
}