assert HpAlloc == 0
[ghc.git] / rts / StgStartup.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2012
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(HpAlloc == 0);                               \
30     ASSERT(Sp != 0);                                    \
31     ASSERT(SpLim != 0);                                 \
32     ASSERT(SpLim - WDS(RESERVED_STACK_WORDS) <= Sp);
33
34 /* -----------------------------------------------------------------------------
35    Returning from the STG world.
36    -------------------------------------------------------------------------- */
37
38 INFO_TABLE_RET(stg_stop_thread, STOP_FRAME,
39                W_ info_ptr,
40                PROF_HDR_FIELDS(W_,p1,p2))
41 /* no return list: explicit stack layout */
42 {
43     /* 
44        The final exit.
45       
46        The top-top-level closures (e.g., "main") are of type "IO a".
47        When entered, they perform an IO action and return an 'a' in R1.
48       
49        We save R1 on top of the stack where the scheduler can find it,
50        tidy up the registers and return to the scheduler.
51       
52        We Leave the stack looking like this:
53       
54                 +----------------+
55                 |      -------------------> return value
56                 +----------------+
57                 | stg_enter_info |
58                 +----------------+
59       
60        The stg_enter_info is just a dummy info table so that the
61        garbage collector can understand the stack (there must always
62        be an info table on top of the stack).
63     */
64
65     Sp = Sp + SIZEOF_StgStopFrame - WDS(2);
66     Sp(1) = R1;
67     Sp(0) = stg_enter_info;
68
69     StgTSO_what_next(CurrentTSO) = ThreadComplete::I16;
70
71     SAVE_THREAD_STATE();
72
73     /* The return code goes in BaseReg->rRet, and BaseReg is returned in R1 */
74     StgRegTable_rRet(BaseReg) = ThreadFinished;
75     R1 = BaseReg;
76
77     jump StgReturn [R1];
78 }
79
80 /* -----------------------------------------------------------------------------
81    Start a thread from the scheduler by returning to the address on
82    the top of the stack.  This is used for all entries to STG code
83    from C land.
84
85    On the way back, we (usually) pass through stg_returnToSched which saves
86    the thread's state away nicely.
87    -------------------------------------------------------------------------- */
88
89 stg_returnToStackTop /* no args: explicit stack layout */
90 {
91   LOAD_THREAD_STATE();
92   CHECK_SENSIBLE_REGS();
93   jump %ENTRY_CODE(Sp(0)) [];
94 }
95
96 stg_returnToSched /* no args: explicit stack layout */
97 {
98   W_ r1;
99   r1 = R1; // foreign calls may clobber R1
100   SAVE_THREAD_STATE();
101   foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO);
102   R1 = r1;
103   jump StgReturn [R1];
104 }
105
106 // A variant of stg_returnToSched 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 /* no args: explicit stack layout */
111 {
112   SAVE_THREAD_STATE();
113   jump StgReturn [R1];
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 /* no args: explicit stack layout */
121 {
122   W_ r1, r2, r3;
123   r1 = R1;
124   r2 = R2;
125   r3 = R3;
126   SAVE_THREAD_STATE();
127   // foreign calls may clobber R1/R2/.., so we save them above
128   foreign "C" threadPaused(MyCapability() "ptr", CurrentTSO);
129   R1 = r1;
130   R2 = r2;
131   R3 = r3;
132   jump R2 [R1,R3];
133 }
134
135 stg_threadFinished /* no args: explicit stack layout */
136 {
137   StgRegTable_rRet(BaseReg) = ThreadFinished;
138   R1 = BaseReg;
139   jump StgReturn [R1];
140 }  
141
142 /* -----------------------------------------------------------------------------
143     Strict IO application - performing an IO action and entering its result.
144     
145     rts_evalIO() lets you perform Haskell IO actions from outside of
146     Haskell-land, returning back to you their result. Want this result
147     to be evaluated to WHNF by that time, so that we can easily get at
148     the int/char/whatever using the various get{Ty} functions provided
149     by the RTS API.
150
151     stg_forceIO takes care of this, performing the IO action and entering
152     the results that comes back.
153
154     ------------------------------------------------------------------------- */
155
156 INFO_TABLE_RET(stg_forceIO, RET_SMALL, P_ info_ptr)
157     return (P_ ret)
158 {
159     ENTER(ret);
160 }
161
162 /* -----------------------------------------------------------------------------
163    Special STG entry points for module registration.
164    -------------------------------------------------------------------------- */
165
166 stg_init_finish /* no args: explicit stack layout */
167 {
168   jump StgReturn [];
169 }
170
171 /* On entry to stg_init:
172  *    init_stack[0] = &stg_init_ret;
173  *    init_stack[1] = __stginit_Something;
174  */
175 stg_init /* no args: explicit stack layout */
176 {
177   W_ next;
178   Sp = W_[BaseReg + OFFSET_StgRegTable_rSp];
179   next = W_[Sp];
180   Sp_adj(1);
181   jump next [];
182 }