Commit 11b5ce55 authored by Simon Marlow's avatar Simon Marlow

Remove use of R9, and fix associated bugs

We were passing the function address to stg_gc_prim_p in R9, which was
wrong because the call was a high-level call and didn't declare R9 as
a parameter.  Passing R9 as an argument is the right way, but
unfortunately that exposed another bug: we were using the same macro
in some low-level Cmm, where it is illegal to call functions with
arguments (see Note [syntax of cmm files]).  So we now have low-level
variants of STK_CHK() and STK_CHK_P() for use in low-level Cmm code.
parent 56084d76
......@@ -439,20 +439,32 @@
if (0) { goto __L__; }
#define GC_PRIM(fun) \
R9 = fun; \
jump stg_gc_prim();
jump stg_gc_prim(fun);
// Version of GC_PRIM for use in low-level Cmm. We can call
// stg_gc_prim, because it takes one argument and therefore has a
// platform-independent calling convention (Note [Syntax of .cmm
// files] in CmmParse.y).
#define GC_PRIM_LL(fun) \
R1 = fun; \
jump stg_gc_prim [R1];
// We pass the fun as the second argument, because the arg is
// usually already in the first argument position (R1), so this
// avoids moving it to a different register / stack slot.
#define GC_PRIM_N(fun,arg) \
R9 = fun; \
jump stg_gc_prim_n(arg);
jump stg_gc_prim_n(arg,fun);
#define GC_PRIM_P(fun,arg) \
R9 = fun; \
jump stg_gc_prim_p(arg);
jump stg_gc_prim_p(arg,fun);
#define GC_PRIM_P_LL(fun,arg) \
R1 = arg; \
R2 = fun; \
jump stg_gc_prim_p_ll [R1,R2];
#define GC_PRIM_PP(fun,arg1,arg2) \
R9 = fun; \
jump stg_gc_prim_pp(arg1,arg2);
jump stg_gc_prim_pp(arg1,arg2,fun);
#define MAYBE_GC_(fun) \
if (CHECK_GC()) { \
......@@ -478,23 +490,26 @@
GC_PRIM_PP(fun,arg1,arg2) \
}
#define STK_CHK(n, fun) \
#define STK_CHK_LL(n, fun) \
TICK_BUMP(STK_CHK_ctr); \
if (Sp - (n) < SpLim) { \
GC_PRIM(fun) \
GC_PRIM_LL(fun) \
}
#define STK_CHK_P(n, fun, arg) \
#define STK_CHK_P_LL(n, fun, arg) \
TICK_BUMP(STK_CHK_ctr); \
if (Sp - (n) < SpLim) { \
GC_PRIM_P(fun,arg) \
GC_PRIM_P_LL(fun,arg) \
}
#define STK_CHK_PP(n, fun, arg1, arg2) \
TICK_BUMP(STK_CHK_ctr); \
if (Sp - (n) < SpLim) { \
GC_PRIM_PP(fun,arg1,arg2) \
}
#define STK_CHK_ENTER(n, closure) \
TICK_BUMP(STK_CHK_ctr); \
if (Sp - (n) < SpLim) { \
jump __stg_gc_enter_1(closure); \
}
......
......@@ -276,6 +276,9 @@ RTS_FUN_DECL(stg_gc_prim_p);
RTS_FUN_DECL(stg_gc_prim_pp);
RTS_FUN_DECL(stg_gc_prim_n);
RTS_RET(stg_gc_prim_p_ll_ret);
RTS_FUN_DECL(stg_gc_prim_p_ll);
RTS_RET(stg_enter);
RTS_FUN_DECL(__stg_gc_enter_1);
......
......@@ -64,7 +64,7 @@ INFO_TABLE_RET(stg_unmaskAsyncExceptionszh_ret, RET_SMALL, W_ info_ptr)
/* Eagerly raise a blocked exception, if there is one */
if (StgTSO_blocked_exceptions(CurrentTSO) != END_TSO_QUEUE) {
STK_CHK_P (WDS(2), stg_unmaskAsyncExceptionszh_ret_info, R1);
STK_CHK_P_LL (WDS(2), stg_unmaskAsyncExceptionszh_ret_info, R1);
/*
* We have to be very careful here, as in killThread#, since
* we are about to raise an async exception in the current
......@@ -129,7 +129,7 @@ INFO_TABLE_RET(stg_maskUninterruptiblezh_ret, RET_SMALL, W_ info_ptr)
stg_maskAsyncExceptionszh /* explicit stack */
{
/* Args: R1 :: IO a */
STK_CHK_P( WDS(1)/* worst case */, stg_maskAsyncExceptionszh, R1);
STK_CHK_P_LL (WDS(1)/* worst case */, stg_maskAsyncExceptionszh, R1);
if ((TO_W_(StgTSO_flags(CurrentTSO)) & TSO_BLOCKEX) == 0) {
/* avoid growing the stack unnecessarily */
......@@ -157,7 +157,7 @@ stg_maskAsyncExceptionszh /* explicit stack */
stg_maskUninterruptiblezh /* explicit stack */
{
/* Args: R1 :: IO a */
STK_CHK_P( WDS(1)/* worst case */, stg_maskAsyncExceptionszh, R1);
STK_CHK_P_LL (WDS(1)/* worst case */, stg_maskAsyncExceptionszh, R1);
if ((TO_W_(StgTSO_flags(CurrentTSO)) & TSO_BLOCKEX) == 0) {
/* avoid growing the stack unnecessarily */
......@@ -191,7 +191,7 @@ stg_unmaskAsyncExceptionszh /* explicit stack */
P_ io;
io = R1;
STK_CHK_P (WDS(4), stg_unmaskAsyncExceptionszh, io);
STK_CHK_P_LL (WDS(4), stg_unmaskAsyncExceptionszh, io);
/* 4 words: one for the unblock frame, 3 for setting up the
* stack to call maybePerformBlockedException() below.
*/
......
......@@ -172,38 +172,54 @@ __stg_gc_enter_1 (P_ node)
code in a few common cases.
-------------------------------------------------------------------------- */
stg_gc_prim ()
stg_gc_prim (W_ fun)
{
W_ fun;
fun = R9;
call stg_gc_noregs ();
jump fun();
}
stg_gc_prim_p (P_ arg)
stg_gc_prim_p (P_ arg, W_ fun)
{
W_ fun;
fun = R9;
call stg_gc_noregs ();
jump fun(arg);
}
stg_gc_prim_pp (P_ arg1, P_ arg2)
stg_gc_prim_pp (P_ arg1, P_ arg2, W_ fun)
{
W_ fun;
fun = R9;
call stg_gc_noregs ();
jump fun(arg1,arg2);
}
stg_gc_prim_n (W_ arg)
stg_gc_prim_n (W_ arg, W_ fun)
{
W_ fun;
fun = R9;
call stg_gc_noregs ();
jump fun(arg);
}
stg_gc_prim_p_ll_ret
{
W_ fun;
P_ arg;
fun = Sp(2);
arg = Sp(1);
Sp_adj(3);
R1 = arg;
jump fun [R1];
}
stg_gc_prim_p_ll
{
W_ fun;
P_ arg;
fun = R2;
arg = R1;
Sp_adj(-3);
Sp(2) = fun;
Sp(1) = arg;
Sp(0) = stg_gc_prim_p_ll_ret;
jump stg_gc_noregs [];
}
/* -----------------------------------------------------------------------------
stg_enter_checkbh is just like stg_enter, except that we also call
checkBlockingQueues(). The point of this is that the GC can
......
......@@ -2069,7 +2069,7 @@ stg_noDuplicatezh /* no arg list: explicit stack layout */
jump %ENTRY_CODE(Sp(0)) [];
}
STK_CHK(WDS(1), stg_noDuplicatezh);
STK_CHK_LL (WDS(1), stg_noDuplicatezh);
// leave noDuplicate frame in case the current
// computation is suspended and restarted (see above).
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment