f4e5683110b9ce2c558ce5da0e9bad497e9bfc32
[ghc-hetmet.git] / ghc / rts / StgStartup.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: StgStartup.hc,v 1.14 2001/02/09 13:09:16 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Code for starting, stopping and restarting threads.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "Rts.h"
11 #include "StgRun.h" /* StgReturn */
12 #include "StgStartup.h"
13
14 /*
15  * This module contains the two entry points and the final exit point
16  * to/from the Haskell world.  We can enter either by:
17  *
18  *   a) returning to the address on the top of the stack, or
19  *   b) entering the closure on the top of the stack
20  *
21  * the function stg_stop_thread_entry is the final exit for a
22  * thread: it is the last return address on the stack.  It returns
23  * to the scheduler marking the thread as finished.
24  */
25
26 #define CHECK_SENSIBLE_REGS() \
27     ASSERT(Hp != (P_)0);                        \
28     ASSERT(Sp != (P_)0);                        \
29     ASSERT(Su != (StgUpdateFrame *)0);          \
30     ASSERT(SpLim != (P_)0);                     \
31     ASSERT(HpLim != (P_)0);                     \
32     ASSERT(Sp <= (P_)Su);                       \
33     ASSERT(SpLim - RESERVED_STACK_WORDS <= Sp); \
34     ASSERT(HpLim >= Hp);
35
36 /* -----------------------------------------------------------------------------
37    Returning from the STG world.
38
39    This is a polymorphic return address, meaning that any old constructor
40    can be returned, we don't care (actually, it's probably going to be
41    an IOok constructor, which will indirect through the vector table
42    slot 0).
43    -------------------------------------------------------------------------- */
44
45 EXTFUN(stg_stop_thread_entry);
46
47 #ifdef PROFILING
48 #define STOP_THREAD_BITMAP 1
49 #else
50 #define STOP_THREAD_BITMAP 0
51 #endif
52
53 /* VEC_POLY_INFO expects to see these names - but they should all be the same. */
54 #define stg_stop_thread_0_entry stg_stop_thread_entry 
55 #define stg_stop_thread_1_entry stg_stop_thread_entry 
56 #define stg_stop_thread_2_entry stg_stop_thread_entry 
57 #define stg_stop_thread_3_entry stg_stop_thread_entry 
58 #define stg_stop_thread_4_entry stg_stop_thread_entry 
59 #define stg_stop_thread_5_entry stg_stop_thread_entry 
60 #define stg_stop_thread_6_entry stg_stop_thread_entry 
61 #define stg_stop_thread_7_entry stg_stop_thread_entry 
62
63 VEC_POLY_INFO_TABLE(stg_stop_thread,STOP_THREAD_BITMAP,0,0,0,STOP_FRAME,,EF_);
64
65 STGFUN(stg_stop_thread_entry)
66 {
67     FB_
68
69     /* 
70      * The final exit.
71      *
72      * The top-top-level closures (e.g., "main") are of type "IO a".
73      * When entered, they perform an IO action and return an 'a' in R1.
74      *
75      * We save R1 on top of the stack where the scheduler can find it,
76      * tidy up the registers and return to the scheduler.
77     */
78
79     /* Move Sp to the last word on the stack, and Su to just past the end
80      * of the stack.  We then place the return value at the top of the stack.
81      */
82     Sp += sizeofW(StgStopFrame) - 1;
83     Su = (StgUpdateFrame *)(Sp+1);  
84     Sp[0] = R1.w;
85
86     CurrentTSO->what_next = ThreadComplete;
87
88     SaveThreadState();  /* inline! */
89
90     /* R1 contains the return value of the thread */
91     R1.p = (P_)ThreadFinished;
92
93     JMP_(StgReturn);
94     FE_
95 }
96
97 /* -----------------------------------------------------------------------------
98    Start a thread from the scheduler by returning to the address on
99    the top of the stack  (and popping the address).  This is used for
100    returning to the slow entry point of a function after a garbage collection
101    or re-schedule.  The slow entry point expects the stack to contain the
102    pending arguments only.
103    -------------------------------------------------------------------------- */
104
105 STGFUN(stg_returnToStackTop)
106 {
107   FB_
108   LoadThreadState();
109   CHECK_SENSIBLE_REGS();
110   Sp++;
111   JMP_(ENTRY_CODE(Sp[-1]));
112   FE_
113 }
114
115 /* -----------------------------------------------------------------------------
116    Start a thread from the scheduler by entering the closure pointed
117    to by the word on the top of the stack.
118    -------------------------------------------------------------------------- */
119
120 STGFUN(stg_enterStackTop)
121 {
122   FB_
123   LoadThreadState();
124   CHECK_SENSIBLE_REGS();
125   /* don't count this enter for ticky-ticky profiling */
126   R1.p = (P_)Sp[0];
127   Sp++;
128   JMP_(GET_ENTRY(R1.cl));
129   FE_
130 }
131
132   
133 /* -----------------------------------------------------------------------------
134    Special STG entry points for module registration.
135
136    This stuff is problematic for Hugs, because it introduces a
137    dependency between the RTS and the program (ie. __init_PrelMain).  So
138    we currently disable module initialisation for Hugs.
139    -------------------------------------------------------------------------- */
140
141 extern F_ *init_stack;
142
143 STGFUN(stg_init_ret)
144 {
145   FB_
146   JMP_(StgReturn);
147   FE_
148 }
149
150 /* On entry to stg_init:
151  *    init_stack[0] = &stg_init_ret;
152  *    init_stack[1] = __init_Something;
153  */
154 STGFUN(stg_init)
155 {
156   FB_
157   Sp = BaseReg->rSp;
158   JMP_(POP_INIT_STACK());
159   FE_
160 }
161
162 /* PrelGHC doesn't really exist... */
163
164 START_MOD_INIT(__init_PrelGHC);
165 END_MOD_INIT();