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