/* -----------------------------------------------------------------------------
- * $Id: HeapStackCheck.hc,v 1.2 1998/12/02 13:28:26 simonm Exp $
+ * $Id: HeapStackCheck.hc,v 1.16 2001/03/23 16:36:21 simonmar Exp $
+ *
+ * (c) The GHC Team, 1998-1999
*
* Canned Heap-Check and Stack-Check sequences.
*
* ---------------------------------------------------------------------------*/
+#include "Stg.h"
#include "Rts.h"
#include "Storage.h" /* for CurrentTSO */
#include "StgRun.h" /* for StgReturn and register saving */
*
* - If the context_switch flag is set, indicating that there are more
* threads waiting to run, we yield to the scheduler
- * (return ThreadYeilding).
+ * (return ThreadYielding).
*
* - If Hp > HpLim, we've had a heap check failure. This means we've
* come to the end of the current heap block, so we try to chain
R1.i = StackOverflow; \
} \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadRunGHC; \
+ CurrentTSO->what_next = ThreadRunGHC; \
JMP_(StgReturn);
#define GC_ENTER \
R1.i = StackOverflow; \
} \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadEnterGHC; \
+ CurrentTSO->what_next = ThreadEnterGHC; \
JMP_(StgReturn);
#define HP_GENERIC \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadRunGHC; \
+ CurrentTSO->what_next = ThreadRunGHC; \
R1.i = HeapOverflow; \
JMP_(StgReturn);
#define STK_GENERIC \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadRunGHC; \
+ CurrentTSO->what_next = ThreadRunGHC; \
R1.i = StackOverflow; \
JMP_(StgReturn);
#define YIELD_GENERIC \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadRunGHC; \
+ CurrentTSO->what_next = ThreadRunGHC; \
R1.i = ThreadYielding; \
JMP_(StgReturn);
-#define YIELD_TO_HUGS \
+#define YIELD_TO_INTERPRETER \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadEnterHugs; \
+ CurrentTSO->what_next = ThreadEnterInterp; \
R1.i = ThreadYielding; \
JMP_(StgReturn);
#define BLOCK_GENERIC \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadRunGHC; \
+ CurrentTSO->what_next = ThreadRunGHC; \
R1.i = ThreadBlocked; \
JMP_(StgReturn);
#define BLOCK_ENTER \
SaveThreadState(); \
- CurrentTSO->whatNext = ThreadEnterGHC;\
+ CurrentTSO->what_next = ThreadEnterGHC;\
R1.i = ThreadBlocked; \
JMP_(StgReturn);
+
/* -----------------------------------------------------------------------------
Heap Checks
-------------------------------------------------------------------------- */
FE_
}
+EXTFUN(stg_gc_enter_1_hponly)
+{
+ FB_
+ Sp -= 1;
+ Sp[0] = R1.w;
+ R1.i = HeapOverflow;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ JMP_(StgReturn);
+ FE_
+}
+
/*- 2 Regs--------------------------------------------------------------------*/
EXTFUN(stg_gc_enter_2)
FE_
}
+#if defined(GRAN)
+/*
+ ToDo: merge the block and yield macros, calling something like BLOCK(N)
+ at the end;
+*/
+
+/*
+ Should we actually ever do a yield in such a case?? -- HWL
+*/
+EXTFUN(gran_yield_0)
+{
+ FB_
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+EXTFUN(gran_yield_1)
+{
+ FB_
+ Sp -= 1;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 2 Regs--------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_2)
+{
+ FB_
+ Sp -= 2;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 3 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_3)
+{
+ FB_
+ Sp -= 3;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 4 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_4)
+{
+ FB_
+ Sp -= 4;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 5 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_5)
+{
+ FB_
+ Sp -= 5;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 6 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_6)
+{
+ FB_
+ Sp -= 6;
+ Sp[5] = R6.w;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 7 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_7)
+{
+ FB_
+ Sp -= 7;
+ Sp[6] = R7.w;
+ Sp[5] = R6.w;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 8 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_yield_8)
+{
+ FB_
+ Sp -= 8;
+ Sp[7] = R8.w;
+ Sp[6] = R7.w;
+ Sp[5] = R6.w;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadYielding;
+ JMP_(StgReturn);
+ FE_
+}
+
+// the same routines but with a block rather than a yield
+
+EXTFUN(gran_block_1)
+{
+ FB_
+ Sp -= 1;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 2 Regs--------------------------------------------------------------------*/
+
+EXTFUN(gran_block_2)
+{
+ FB_
+ Sp -= 2;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 3 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_block_3)
+{
+ FB_
+ Sp -= 3;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 4 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_block_4)
+{
+ FB_
+ Sp -= 4;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 5 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_block_5)
+{
+ FB_
+ Sp -= 5;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 6 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_block_6)
+{
+ FB_
+ Sp -= 6;
+ Sp[5] = R6.w;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 7 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_block_7)
+{
+ FB_
+ Sp -= 7;
+ Sp[6] = R7.w;
+ Sp[5] = R6.w;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+/*- 8 Regs -------------------------------------------------------------------*/
+
+EXTFUN(gran_block_8)
+{
+ FB_
+ Sp -= 8;
+ Sp[7] = R8.w;
+ Sp[6] = R7.w;
+ Sp[5] = R6.w;
+ Sp[4] = R5.w;
+ Sp[3] = R4.w;
+ Sp[2] = R3.w;
+ Sp[1] = R2.w;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+#endif
+
+#if 0 && defined(PAR)
+
+/*
+ Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the
+ saving of the thread state from the actual jump via an StgReturn.
+ We need this separation because we call RTS routines in blocking entry codes
+ before jumping back into the RTS (see parallel/FetchMe.hc).
+*/
+
+EXTFUN(par_block_1_no_jump)
+{
+ FB_
+ Sp -= 1;
+ Sp[0] = R1.w;
+ SaveThreadState();
+ FE_
+}
+
+EXTFUN(par_jump)
+{
+ FB_
+ CurrentTSO->what_next = ThreadEnterGHC;
+ R1.i = ThreadBlocked;
+ JMP_(StgReturn);
+ FE_
+}
+
+#endif
+
/* -----------------------------------------------------------------------------
For a case expression on a polymorphic or function-typed object, if
the default branch (there can only be one branch) of the case fails
cases are covered below.
-------------------------------------------------------------------------- */
-/*-- No regsiters live, return address already on the stack: ---------------- */
+/*-- No regsiters live (probably a void return) ----------------------------- */
+
+/* If we change the policy for thread startup to *not* remove the
+ * return address from the stack, we can get rid of this little
+ * function/info table...
+ */
+INFO_TABLE_SRT_BITMAP(stg_gc_noregs_ret_info, stg_gc_noregs_ret, 0/*BITMAP*/,
+ 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
+ RET_SMALL,, EF_, 0, 0);
+
+EXTFUN(stg_gc_noregs_ret)
+{
+ FB_
+ JMP_(ENTRY_CODE(Sp[0]));
+ FE_
+}
EXTFUN(stg_gc_noregs)
{
FB_
+ Sp -= 1;
+ Sp[0] = (W_)&stg_gc_noregs_ret_info;
GC_GENERIC
FE_
}
INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_entry, 0/*BITMAP*/,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_SMALL, const, EF_, 0, 0);
+ RET_SMALL,, EF_, 0, 0);
EXTFUN(stg_gc_unpt_r1_entry)
{
INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_entry, 1/*BITMAP*/,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_SMALL, const, EF_, 0, 0);
+ RET_SMALL,, EF_, 0, 0);
/* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
EXTFUN(stg_gc_unbx_r1_entry)
INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_entry, 1/*BITMAP*/,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_SMALL, const, EF_, 0, 0);
+ RET_SMALL,, EF_, 0, 0);
EXTFUN(stg_gc_f1_entry)
{
INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_entry, DBL_BITMAP,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_SMALL, const, EF_, 0, 0);
+ RET_SMALL,, EF_, 0, 0);
EXTFUN(stg_gc_d1_entry)
{
INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_entry, 1/*BITMAP*/,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_SMALL, const, EF_, 0, 0);
+ RET_SMALL,, EF_, 0, 0);
EXTFUN(stg_gc_ut_1_0_entry)
{
FB_
R1.w = Sp[1];
Sp += 2;
- JMP_(Sp[-2]);
+ JMP_(ENTRY_CODE(Sp[-2]));
FE_
}
INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_entry, 3/*BITMAP*/,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_SMALL, const, EF_, 0, 0);
+ RET_SMALL,, EF_, 0, 0);
EXTFUN(stg_gc_ut_0_1_entry)
{
FB_
R1.w = Sp[1];
Sp += 2;
- JMP_(Sp[-2]);
+ JMP_(ENTRY_CODE(Sp[-2]));
FE_
}
INFO_TABLE_SRT_BITMAP(stg_gen_chk_info, stg_gen_chk_ret, 0,
0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/,
- RET_DYN, const, EF_, 0, 0);
+ RET_DYN,, EF_, 0, 0);
/* bitmap in the above info table is unused, the real one is on the stack.
*/
{
FB_
RESTORE_EVERYTHING;
- JMP_(Sp[RET_OFFSET]);
+ JMP_(Sp[RET_OFFSET]); /* NO ENTRY_CODE() - this is a direct ret address */
FE_
}
FE_
}
+/* -----------------------------------------------------------------------------
+ Yields
+ -------------------------------------------------------------------------- */
+
FN_(stg_gen_yield)
{
FB_
FE_
}
-FN_(stg_yield_to_Hugs)
+FN_(stg_yield_noregs)
+{
+ FB_
+ Sp--;
+ Sp[0] = (W_)&stg_gc_noregs_ret_info;
+ YIELD_GENERIC;
+ FE_
+}
+
+FN_(stg_yield_to_interpreter)
{
FB_
/* No need to save everything - no live registers */
- YIELD_TO_HUGS
+ YIELD_TO_INTERPRETER
FE_
}
+/* -----------------------------------------------------------------------------
+ Blocks
+ -------------------------------------------------------------------------- */
+
FN_(stg_gen_block)
{
FB_
FE_
}
+FN_(stg_block_noregs)
+{
+ FB_
+ Sp--;
+ Sp[0] = (W_)&stg_gc_noregs_ret_info;
+ BLOCK_GENERIC;
+ FE_
+}
+
FN_(stg_block_1)
{
FB_