[project @ 2004-08-13 10:45:16 by simonmar]
[ghc-hetmet.git] / ghc / rts / StgStartup.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2004
4  *
5  * Code for starting, stopping and restarting threads.
6  *
7  * This file is written in a subset of C--, extended with various
8  * features specific to GHC.  It is compiled by GHC directly.  For the
9  * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
10  *
11  * ---------------------------------------------------------------------------*/
12
13 #include "Cmm.h"
14
15 /*
16  * This module contains the two entry points and the final exit point
17  * to/from the Haskell world.  We can enter either by:
18  *
19  *   a) returning to the address on the top of the stack, or
20  *   b) entering the closure on the top of the stack
21  *
22  * the function stg_stop_thread_entry is the final exit for a
23  * thread: it is the last return address on the stack.  It returns
24  * to the scheduler marking the thread as finished.
25  */
26
27 #define CHECK_SENSIBLE_REGS() \
28     ASSERT(Hp != 0);                    \
29     ASSERT(Sp != 0);                    \
30     ASSERT(SpLim != 0);                 \
31     ASSERT(HpLim != 0);                 \
32     ASSERT(SpLim - RESERVED_STACK_WORDS <= Sp); \
33     ASSERT(HpLim >= Hp);
34
35 /* -----------------------------------------------------------------------------
36    Returning from the STG world.
37
38    This is a polymorphic return address, meaning that any old constructor
39    can be returned, we don't care (actually, it's probably going to be
40    an IOok constructor, which will indirect through the vector table
41    slot 0).
42    -------------------------------------------------------------------------- */
43
44 #if defined(PROFILING)
45 #define STOP_THREAD_BITMAP 3
46 #define STOP_THREAD_WORDS  2
47 #else
48 #define STOP_THREAD_BITMAP 0
49 #define STOP_THREAD_WORDS  0
50 #endif
51
52 /* A polymorhpic return address, where all the vector slots point to the
53    direct entry point. */
54 INFO_TABLE_RET( stg_stop_thread, STOP_THREAD_WORDS, STOP_THREAD_BITMAP,
55                 STOP_FRAME, 
56                 RET_LBL(stg_stop_thread),
57                 RET_LBL(stg_stop_thread),
58                 RET_LBL(stg_stop_thread),
59                 RET_LBL(stg_stop_thread),
60                 RET_LBL(stg_stop_thread),
61                 RET_LBL(stg_stop_thread),
62                 RET_LBL(stg_stop_thread),
63                 RET_LBL(stg_stop_thread) )
64 {
65     /* 
66        The final exit.
67       
68        The top-top-level closures (e.g., "main") are of type "IO a".
69        When entered, they perform an IO action and return an 'a' in R1.
70       
71        We save R1 on top of the stack where the scheduler can find it,
72        tidy up the registers and return to the scheduler.
73       
74        We Leave the stack looking like this:
75       
76                 +----------------+
77                 |      -------------------> return value
78                 +----------------+
79                 | stg_enter_info |
80                 +----------------+
81       
82        The stg_enter_info is just a dummy info table so that the
83        garbage collector can understand the stack (there must always
84        be an info table on top of the stack).
85     */
86
87     Sp = Sp + SIZEOF_StgStopFrame - WDS(2);
88     Sp(1) = R1;
89     Sp(0) = stg_enter_info;
90
91     StgTSO_what_next(CurrentTSO) = ThreadComplete::I16;
92
93     SAVE_THREAD_STATE();
94
95     /* R1 contains the return value of the thread */
96     R1 = ThreadFinished;
97
98     jump StgReturn;
99 }
100
101 /* -----------------------------------------------------------------------------
102    Start a thread from the scheduler by returning to the address on
103    the top of the stack.  This is used for all entries to STG code
104    from C land.
105    -------------------------------------------------------------------------- */
106
107 stg_returnToStackTop
108 {
109   LOAD_THREAD_STATE();
110   CHECK_SENSIBLE_REGS();
111   jump %ENTRY_CODE(Sp(0));
112 }
113
114 /* -----------------------------------------------------------------------------
115     Strict IO application - performing an IO action and entering its result.
116     
117     rts_evalIO() lets you perform Haskell IO actions from outside of
118     Haskell-land, returning back to you their result. Want this result
119     to be evaluated to WHNF by that time, so that we can easily get at
120     the int/char/whatever using the various get{Ty} functions provided
121     by the RTS API.
122
123     forceIO takes care of this, performing the IO action and entering the
124     results that comes back.
125     ------------------------------------------------------------------------- */
126
127 INFO_TABLE_RET( stg_forceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL)
128
129 #ifdef REG_R1
130 {
131   Sp_adj(1);
132   ENTER();
133 }
134 #else
135 {
136   R1 = Sp(0);
137   Sp_adj(2);
138   ENTER();
139 }
140 #endif
141
142 /* -----------------------------------------------------------------------------
143     Non-strict IO application.
144
145     This stack frame works like stg_forceIO_info except that it
146     doesn't evaluate the return value.  We need the layer because the
147     return convention for an IO action differs depending on whether R1
148     is a register or not.
149     ------------------------------------------------------------------------- */
150
151 INFO_TABLE_RET( stg_noforceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL )
152
153 #ifdef REG_R1
154 {
155   Sp_adj(1);
156   jump %ENTRY_CODE(Sp(0));
157 }
158 #else
159 {
160   R1 = Sp(0);
161   Sp_adj(2);
162   jump %ENTRY_CODE(Sp(0));
163 }
164 #endif
165
166 /* -----------------------------------------------------------------------------
167    Special STG entry points for module registration.
168    -------------------------------------------------------------------------- */
169
170 stg_init_finish
171 {
172   jump StgReturn;
173 }
174
175 /* On entry to stg_init:
176  *    init_stack[0] = &stg_init_ret;
177  *    init_stack[1] = __stginit_Something;
178  */
179 stg_init
180 {
181   W_ next;
182   Sp = W_[MainCapability + OFFSET_Capability_r + OFFSET_StgRegTable_rSp];
183   next = W_[Sp];
184   Sp_adj(1);
185   jump next;
186 }