summaryrefslogtreecommitdiff
path: root/rts/StgStartup.cmm
diff options
context:
space:
mode:
Diffstat (limited to 'rts/StgStartup.cmm')
-rw-r--r--rts/StgStartup.cmm218
1 files changed, 218 insertions, 0 deletions
diff --git a/rts/StgStartup.cmm b/rts/StgStartup.cmm
new file mode 100644
index 0000000000..2f2a759c81
--- /dev/null
+++ b/rts/StgStartup.cmm
@@ -0,0 +1,218 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1998-2004
+ *
+ * Code for starting, stopping and restarting threads.
+ *
+ * This file is written in a subset of C--, extended with various
+ * features specific to GHC. It is compiled by GHC directly. For the
+ * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "Cmm.h"
+
+/*
+ * This module contains the two entry points and the final exit point
+ * to/from the Haskell world. We can enter either by:
+ *
+ * a) returning to the address on the top of the stack, or
+ * b) entering the closure on the top of the stack
+ *
+ * the function stg_stop_thread_entry is the final exit for a
+ * thread: it is the last return address on the stack. It returns
+ * to the scheduler marking the thread as finished.
+ */
+
+#define CHECK_SENSIBLE_REGS() \
+ ASSERT(Hp != 0); \
+ ASSERT(Sp != 0); \
+ ASSERT(SpLim != 0); \
+ ASSERT(HpLim != 0); \
+ ASSERT(SpLim - WDS(RESERVED_STACK_WORDS) <= Sp); \
+ ASSERT(HpLim >= Hp);
+
+/* -----------------------------------------------------------------------------
+ Returning from the STG world.
+
+ This is a polymorphic return address, meaning that any old constructor
+ can be returned, we don't care (actually, it's probably going to be
+ an IOok constructor, which will indirect through the vector table
+ slot 0).
+ -------------------------------------------------------------------------- */
+
+#if defined(PROFILING)
+#define STOP_THREAD_BITMAP 3
+#define STOP_THREAD_WORDS 2
+#else
+#define STOP_THREAD_BITMAP 0
+#define STOP_THREAD_WORDS 0
+#endif
+
+/* A polymorhpic return address, where all the vector slots point to the
+ direct entry point. */
+INFO_TABLE_RET( stg_stop_thread, STOP_THREAD_WORDS, STOP_THREAD_BITMAP,
+ STOP_FRAME,
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread),
+ RET_LBL(stg_stop_thread) )
+{
+ /*
+ The final exit.
+
+ The top-top-level closures (e.g., "main") are of type "IO a".
+ When entered, they perform an IO action and return an 'a' in R1.
+
+ We save R1 on top of the stack where the scheduler can find it,
+ tidy up the registers and return to the scheduler.
+
+ We Leave the stack looking like this:
+
+ +----------------+
+ | -------------------> return value
+ +----------------+
+ | stg_enter_info |
+ +----------------+
+
+ The stg_enter_info is just a dummy info table so that the
+ garbage collector can understand the stack (there must always
+ be an info table on top of the stack).
+ */
+
+ Sp = Sp + SIZEOF_StgStopFrame - WDS(2);
+ Sp(1) = R1;
+ Sp(0) = stg_enter_info;
+
+ StgTSO_what_next(CurrentTSO) = ThreadComplete::I16;
+
+ SAVE_THREAD_STATE();
+
+ /* The return code goes in BaseReg->rRet, and BaseReg is returned in R1 */
+ StgRegTable_rRet(BaseReg) = ThreadFinished;
+ R1 = BaseReg;
+
+ jump StgReturn;
+}
+
+/* -----------------------------------------------------------------------------
+ Start a thread from the scheduler by returning to the address on
+ the top of the stack. This is used for all entries to STG code
+ from C land.
+
+ On the way back, we (usually) pass through stg_returnToSched which saves
+ the thread's state away nicely.
+ -------------------------------------------------------------------------- */
+
+stg_returnToStackTop
+{
+ LOAD_THREAD_STATE();
+ CHECK_SENSIBLE_REGS();
+ jump %ENTRY_CODE(Sp(0));
+}
+
+stg_returnToSched
+{
+ SAVE_THREAD_STATE();
+ foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO);
+ jump StgReturn;
+}
+
+// A variant of stg_returntToSched that doesn't call threadPaused() on the
+// current thread. This is used for switching from compiled execution to the
+// interpreter, where calling threadPaused() on every switch would be too
+// expensive.
+stg_returnToSchedNotPaused
+{
+ SAVE_THREAD_STATE();
+ jump StgReturn;
+}
+
+// A variant of stg_returnToSched, but instead of returning directly to the
+// scheduler, we jump to the code fragment pointed to by R2. This lets us
+// perform some final actions after making the thread safe, such as unlocking
+// the MVar on which we are about to block in SMP mode.
+stg_returnToSchedButFirst
+{
+ SAVE_THREAD_STATE();
+ foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO);
+ jump R2;
+}
+
+/* -----------------------------------------------------------------------------
+ Strict IO application - performing an IO action and entering its result.
+
+ rts_evalIO() lets you perform Haskell IO actions from outside of
+ Haskell-land, returning back to you their result. Want this result
+ to be evaluated to WHNF by that time, so that we can easily get at
+ the int/char/whatever using the various get{Ty} functions provided
+ by the RTS API.
+
+ forceIO takes care of this, performing the IO action and entering the
+ results that comes back.
+ ------------------------------------------------------------------------- */
+
+INFO_TABLE_RET( stg_forceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL)
+
+#ifdef REG_R1
+{
+ Sp_adj(1);
+ ENTER();
+}
+#else
+{
+ R1 = Sp(0);
+ Sp_adj(2);
+ ENTER();
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ Non-strict IO application.
+
+ This stack frame works like stg_forceIO_info except that it
+ doesn't evaluate the return value. We need the layer because the
+ return convention for an IO action differs depending on whether R1
+ is a register or not.
+ ------------------------------------------------------------------------- */
+
+INFO_TABLE_RET( stg_noforceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL )
+
+#ifdef REG_R1
+{
+ Sp_adj(1);
+ jump %ENTRY_CODE(Sp(0));
+}
+#else
+{
+ R1 = Sp(0);
+ Sp_adj(2);
+ jump %ENTRY_CODE(Sp(0));
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ Special STG entry points for module registration.
+ -------------------------------------------------------------------------- */
+
+stg_init_finish
+{
+ jump StgReturn;
+}
+
+/* On entry to stg_init:
+ * init_stack[0] = &stg_init_ret;
+ * init_stack[1] = __stginit_Something;
+ */
+stg_init
+{
+ W_ next;
+ Sp = W_[BaseReg + OFFSET_StgRegTable_rSp];
+ next = W_[Sp];
+ Sp_adj(1);
+ jump next;
+}