Add several new record features
[ghc-hetmet.git] / 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 - WDS(RESERVED_STACK_WORDS) <= Sp); \
33     ASSERT(HpLim >= Hp);
34
35 /* -----------------------------------------------------------------------------
36    Returning from the STG world.
37    -------------------------------------------------------------------------- */
38
39 #if defined(PROFILING)
40 #define STOP_THREAD_BITMAP 3
41 #define STOP_THREAD_WORDS  2
42 #else
43 #define STOP_THREAD_BITMAP 0
44 #define STOP_THREAD_WORDS  0
45 #endif
46
47 INFO_TABLE_RET( stg_stop_thread, STOP_THREAD_WORDS, STOP_THREAD_BITMAP,
48                 STOP_FRAME)
49 {
50     /* 
51        The final exit.
52       
53        The top-top-level closures (e.g., "main") are of type "IO a".
54        When entered, they perform an IO action and return an 'a' in R1.
55       
56        We save R1 on top of the stack where the scheduler can find it,
57        tidy up the registers and return to the scheduler.
58       
59        We Leave the stack looking like this:
60       
61                 +----------------+
62                 |      -------------------> return value
63                 +----------------+
64                 | stg_enter_info |
65                 +----------------+
66       
67        The stg_enter_info is just a dummy info table so that the
68        garbage collector can understand the stack (there must always
69        be an info table on top of the stack).
70     */
71
72     Sp = Sp + SIZEOF_StgStopFrame - WDS(2);
73     Sp(1) = R1;
74     Sp(0) = stg_enter_info;
75
76     StgTSO_what_next(CurrentTSO) = ThreadComplete::I16;
77
78     SAVE_THREAD_STATE();
79
80     /* The return code goes in BaseReg->rRet, and BaseReg is returned in R1 */
81     StgRegTable_rRet(BaseReg) = ThreadFinished;
82     R1 = BaseReg;
83
84     jump StgReturn;
85 }
86
87 /* -----------------------------------------------------------------------------
88    Start a thread from the scheduler by returning to the address on
89    the top of the stack.  This is used for all entries to STG code
90    from C land.
91
92    On the way back, we (usually) pass through stg_returnToSched which saves
93    the thread's state away nicely.
94    -------------------------------------------------------------------------- */
95
96 stg_returnToStackTop
97 {
98   LOAD_THREAD_STATE();
99   CHECK_SENSIBLE_REGS();
100   jump %ENTRY_CODE(Sp(0));
101 }
102
103 stg_returnToSched
104 {
105   SAVE_THREAD_STATE();
106   foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO);
107   jump StgReturn;
108 }
109
110 // A variant of stg_returntToSched that doesn't call threadPaused() on the
111 // current thread.  This is used for switching from compiled execution to the
112 // interpreter, where calling threadPaused() on every switch would be too
113 // expensive.
114 stg_returnToSchedNotPaused
115 {
116   SAVE_THREAD_STATE();
117   jump StgReturn;
118 }
119
120 // A variant of stg_returnToSched, but instead of returning directly to the
121 // scheduler, we jump to the code fragment pointed to by R2.  This lets us
122 // perform some final actions after making the thread safe, such as unlocking
123 // the MVar on which we are about to block in SMP mode.
124 stg_returnToSchedButFirst
125 {
126   SAVE_THREAD_STATE();
127   foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO);
128   jump R2;
129 }
130
131 stg_threadFinished
132 {
133   StgRegTable_rRet(BaseReg) = ThreadFinished;
134   R1 = BaseReg;
135   jump StgReturn;
136 }  
137
138 /* -----------------------------------------------------------------------------
139     Strict IO application - performing an IO action and entering its result.
140     
141     rts_evalIO() lets you perform Haskell IO actions from outside of
142     Haskell-land, returning back to you their result. Want this result
143     to be evaluated to WHNF by that time, so that we can easily get at
144     the int/char/whatever using the various get{Ty} functions provided
145     by the RTS API.
146
147     forceIO takes care of this, performing the IO action and entering the
148     results that comes back.
149     ------------------------------------------------------------------------- */
150
151 INFO_TABLE_RET( stg_forceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL)
152
153 #ifdef REG_R1
154 {
155   Sp_adj(1);
156   ENTER();
157 }
158 #else
159 {
160   R1 = Sp(0);
161   Sp_adj(2);
162   ENTER();
163 }
164 #endif
165
166 /* -----------------------------------------------------------------------------
167     Non-strict IO application.
168
169     This stack frame works like stg_forceIO_info except that it
170     doesn't evaluate the return value.  We need the layer because the
171     return convention for an IO action differs depending on whether R1
172     is a register or not.
173     ------------------------------------------------------------------------- */
174
175 INFO_TABLE_RET( stg_noforceIO, 0/*size*/, 0/*bitmap*/, RET_SMALL )
176
177 #ifdef REG_R1
178 {
179   Sp_adj(1);
180   jump %ENTRY_CODE(Sp(0));
181 }
182 #else
183 {
184   R1 = Sp(0);
185   Sp_adj(2);
186   jump %ENTRY_CODE(Sp(0));
187 }
188 #endif
189
190 /* -----------------------------------------------------------------------------
191    Special STG entry points for module registration.
192    -------------------------------------------------------------------------- */
193
194 stg_init_finish
195 {
196   jump StgReturn;
197 }
198
199 /* On entry to stg_init:
200  *    init_stack[0] = &stg_init_ret;
201  *    init_stack[1] = __stginit_Something;
202  */
203 stg_init
204 {
205   W_ next;
206   Sp = W_[BaseReg + OFFSET_StgRegTable_rSp];
207   next = W_[Sp];
208   Sp_adj(1);
209   jump next;
210 }