[project @ 2004-02-12 02:04:59 by mthomas]
[ghc-hetmet.git] / ghc / rts / StgStartup.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: StgStartup.hc,v 1.21 2003/05/14 09:14:00 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-2002
5  *
6  * Code for starting, stopping and restarting threads.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "Stg.h"
11 #include "Rts.h"
12 #include "StgRun.h" /* StgReturn */
13 #include "StgStartup.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 != (P_)0);                        \
29     ASSERT(Sp != (P_)0);                        \
30     ASSERT(SpLim != (P_)0);                     \
31     ASSERT(HpLim != (P_)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 EXTFUN(stg_stop_thread_ret);
45
46 #if defined(PROFILING)
47 #define STOP_THREAD_BITMAP 3
48 #define STOP_THREAD_WORDS  2
49 #else
50 #define STOP_THREAD_BITMAP 0
51 #define STOP_THREAD_WORDS  0
52 #endif
53
54 /* VEC_POLY_INFO expects to see these names - but they should all be the same. */
55 #define stg_stop_thread_0_ret stg_stop_thread_ret 
56 #define stg_stop_thread_1_ret stg_stop_thread_ret 
57 #define stg_stop_thread_2_ret stg_stop_thread_ret 
58 #define stg_stop_thread_3_ret stg_stop_thread_ret 
59 #define stg_stop_thread_4_ret stg_stop_thread_ret 
60 #define stg_stop_thread_5_ret stg_stop_thread_ret 
61 #define stg_stop_thread_6_ret stg_stop_thread_ret 
62 #define stg_stop_thread_7_ret stg_stop_thread_ret 
63
64 VEC_POLY_INFO_TABLE( stg_stop_thread,
65                      MK_SMALL_BITMAP(STOP_THREAD_WORDS, STOP_THREAD_BITMAP),
66                      0,0,0,STOP_FRAME,,EF_);
67
68 STGFUN(stg_stop_thread_ret)
69 {
70     FB_
71     // 
72     // The final exit.
73     //
74     // The top-top-level closures (e.g., "main") are of type "IO a".
75     // When entered, they perform an IO action and return an 'a' in R1.
76     //
77     // We save R1 on top of the stack where the scheduler can find it,
78     // tidy up the registers and return to the scheduler.
79     //
80     // We Leave the stack looking like this:
81     //
82     //          +----------------+
83     //          |      -------------------> return value
84     //          +----------------+
85     //          | stg_enter_info |
86     //          +----------------+
87     //
88     // The stg_enter_info is just a dummy info table so that the
89     // garbage collector can understand the stack (there must always
90     // be an info table on top of the stack).
91     //
92
93     Sp += sizeofW(StgStopFrame) - 2;
94     Sp[1] = R1.w;
95     Sp[0] = (W_)&stg_enter_info;
96
97     CurrentTSO->what_next = ThreadComplete;
98
99     SaveThreadState();  // inline!
100
101     // R1 contains the return value of the thread
102     R1.i = ThreadFinished;
103
104     JMP_(StgReturn);
105     FE_
106 }
107
108 /* -----------------------------------------------------------------------------
109    Start a thread from the scheduler by returning to the address on
110    the top of the stack.  This is used for all entries to STG code
111    from C land.
112    -------------------------------------------------------------------------- */
113
114 STGFUN(stg_returnToStackTop)
115 {
116   FB_
117   LoadThreadState();
118   CHECK_SENSIBLE_REGS();
119   JMP_(ENTRY_CODE(Sp[0]));
120   FE_
121 }
122
123 /* -----------------------------------------------------------------------------
124     Strict IO application - performing an IO action and entering its result.
125     
126     rts_evalIO() lets you perform Haskell IO actions from outside of
127     Haskell-land, returning back to you their result. Want this result
128     to be evaluated to WHNF by that time, so that we can easily get at
129     the int/char/whatever using the various get{Ty} functions provided
130     by the RTS API.
131
132     forceIO takes care of this, performing the IO action and entering the
133     results that comes back.
134     ------------------------------------------------------------------------- */
135
136 INFO_TABLE_RET( stg_forceIO_info,stg_forceIO_ret,
137                 MK_SMALL_BITMAP(0/*size*/, 0/*BITMAP*/),
138                 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
139                 RET_SMALL,, EF_, 0, 0);
140
141 #ifdef REG_R1
142 STGFUN(stg_forceIO_ret)
143 {
144   FB_
145   Sp++;
146   ENTER();
147   FE_
148 }
149 #else
150 STGFUN(stg_forceIO_ret)
151 {
152   FB_
153   R1.w = Sp[0];
154   Sp += 2;
155   ENTER();
156   FE_
157 }
158 #endif
159
160 /* -----------------------------------------------------------------------------
161     Non-strict IO application.
162
163     This stack frame works like stg_forceIO_info except that it
164     doesn't evaluate the return value.  We need the layer because the
165     return convention for an IO action differs depending on whether R1
166     is a register or not.
167     ------------------------------------------------------------------------- */
168
169 INFO_TABLE_RET( stg_noforceIO_info,stg_noforceIO_ret,
170                 MK_SMALL_BITMAP(0/*size*/, 0/*BITMAP*/),
171                 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_BITMAP*/, 
172                 RET_SMALL,, EF_, 0, 0);
173
174 #ifdef REG_R1
175 STGFUN(stg_noforceIO_ret)
176 {
177   FB_
178   Sp++;
179   JMP_(ENTRY_CODE(Sp[0]));
180   FE_
181 }
182 #else
183 STGFUN(stg_noforceIO_ret)
184 {
185   FB_
186   R1.w = Sp[0];
187   Sp += 2;
188   JMP_(ENTRY_CODE(Sp[0]));
189   FE_
190 }
191 #endif
192
193 /* -----------------------------------------------------------------------------
194    Special STG entry points for module registration.
195    -------------------------------------------------------------------------- */
196
197 extern F_ *init_stack;
198
199 STGFUN(stg_init_ret)
200 {
201   FB_
202   JMP_(StgReturn);
203   FE_
204 }
205
206 /* On entry to stg_init:
207  *    init_stack[0] = &stg_init_ret;
208  *    init_stack[1] = __stginit_Something;
209  */
210 STGFUN(stg_init)
211 {
212   FB_
213   Sp = BaseReg->rSp;
214   JMP_(POP_INIT_STACK());
215   FE_
216 }