[project @ 2002-02-12 15:17:13 by simonmar]
[ghc-hetmet.git] / ghc / rts / StgStartup.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: StgStartup.hc,v 1.18 2002/02/12 15:17:23 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
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(Su != (StgUpdateFrame *)0);          \
31     ASSERT(SpLim != (P_)0);                     \
32     ASSERT(HpLim != (P_)0);                     \
33     ASSERT(Sp <= (P_)Su);                       \
34     ASSERT(SpLim - RESERVED_STACK_WORDS <= Sp); \
35     ASSERT(HpLim >= Hp);
36
37 /* -----------------------------------------------------------------------------
38    Returning from the STG world.
39
40    This is a polymorphic return address, meaning that any old constructor
41    can be returned, we don't care (actually, it's probably going to be
42    an IOok constructor, which will indirect through the vector table
43    slot 0).
44    -------------------------------------------------------------------------- */
45
46 EXTFUN(stg_stop_thread_entry);
47
48 #if defined(PROFILING)
49 #define STOP_THREAD_BITMAP 3
50 #else
51 #define STOP_THREAD_BITMAP 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_entry stg_stop_thread_entry 
56 #define stg_stop_thread_1_entry stg_stop_thread_entry 
57 #define stg_stop_thread_2_entry stg_stop_thread_entry 
58 #define stg_stop_thread_3_entry stg_stop_thread_entry 
59 #define stg_stop_thread_4_entry stg_stop_thread_entry 
60 #define stg_stop_thread_5_entry stg_stop_thread_entry 
61 #define stg_stop_thread_6_entry stg_stop_thread_entry 
62 #define stg_stop_thread_7_entry stg_stop_thread_entry 
63
64 VEC_POLY_INFO_TABLE(stg_stop_thread,STOP_THREAD_BITMAP,0,0,0,STOP_FRAME,,EF_);
65
66 STGFUN(stg_stop_thread_entry)
67 {
68     FB_
69
70     /* 
71      * The final exit.
72      *
73      * The top-top-level closures (e.g., "main") are of type "IO a".
74      * When entered, they perform an IO action and return an 'a' in R1.
75      *
76      * We save R1 on top of the stack where the scheduler can find it,
77      * tidy up the registers and return to the scheduler.
78     */
79
80     /* Move Sp to the last word on the stack, and Su to just past the end
81      * of the stack.  We then place the return value at the top of the stack.
82      */
83     Sp += sizeofW(StgStopFrame) - 1;
84     Su = (StgUpdateFrame *)(Sp+1);  
85     Sp[0] = R1.w;
86
87     CurrentTSO->what_next = ThreadComplete;
88
89     SaveThreadState();  /* inline! */
90
91     /* R1 contains the return value of the thread */
92     R1.p = (P_)ThreadFinished;
93
94     JMP_(StgReturn);
95     FE_
96 }
97
98 /* -----------------------------------------------------------------------------
99    Start a thread from the scheduler by returning to the address on
100    the top of the stack  (and popping the address).  This is used for
101    returning to the slow entry point of a function after a garbage collection
102    or re-schedule.  The slow entry point expects the stack to contain the
103    pending arguments only.
104    -------------------------------------------------------------------------- */
105
106 STGFUN(stg_returnToStackTop)
107 {
108   FB_
109   LoadThreadState();
110   CHECK_SENSIBLE_REGS();
111   Sp++;
112   JMP_(ENTRY_CODE(Sp[-1]));
113   FE_
114 }
115
116 /* -----------------------------------------------------------------------------
117    Start a thread from the scheduler by entering the closure pointed
118    to by the word on the top of the stack.
119    -------------------------------------------------------------------------- */
120
121 STGFUN(stg_enterStackTop)
122 {
123   FB_
124   LoadThreadState();
125   CHECK_SENSIBLE_REGS();
126   /* don't count this enter for ticky-ticky profiling */
127   R1.p = (P_)Sp[0];
128   Sp++;
129   JMP_(GET_ENTRY(R1.cl));
130   FE_
131 }
132
133   
134 /* -----------------------------------------------------------------------------
135    Special STG entry points for module registration.
136    -------------------------------------------------------------------------- */
137
138 extern F_ *init_stack;
139
140 STGFUN(stg_init_ret)
141 {
142   FB_
143   JMP_(StgReturn);
144   FE_
145 }
146
147 /* On entry to stg_init:
148  *    init_stack[0] = &stg_init_ret;
149  *    init_stack[1] = __stginit_Something;
150  */
151 STGFUN(stg_init)
152 {
153   FB_
154   Sp = BaseReg->rSp;
155   JMP_(POP_INIT_STACK());
156   FE_
157 }
158
159 /* GHC.Prim doesn't really exist... */
160
161 START_MOD_INIT(__stginit_GHCziPrim);
162 END_MOD_INIT();