Reorganisation of the source tree
[ghc.git] / rts / Apply.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The University of Glasgow 2004
4  *
5  * Application-related bits.
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  * Evaluate a closure and return it.
17  *
18  * There isn't an info table / return address version of stg_ap_0, because
19  * everything being returned is guaranteed evaluated, so it would be a no-op.
20  */
21
22 STRING(stg_ap_0_ret_str,"stg_ap_0_ret... ")
23
24 stg_ap_0_fast
25
26     // fn is in R1, no args on the stack
27
28     IF_DEBUG(apply,
29         foreign "C" debugBelch(stg_ap_0_ret_str) [R1];
30         foreign "C" printClosure(R1 "ptr") [R1]);
31
32     IF_DEBUG(sanity,
33         foreign "C" checkStackChunk(Sp "ptr",
34                                     CurrentTSO + TSO_OFFSET_StgTSO_stack +
35                                     WDS(TO_W_(StgTSO_stack_size(CurrentTSO))) "ptr") [R1]);
36
37     ENTER();
38 }
39
40 /* -----------------------------------------------------------------------------
41    Entry Code for a PAP.
42
43    This entry code is *only* called by one of the stg_ap functions.
44    On entry: Sp points to the remaining arguments on the stack.  If
45    the stack check fails, we can just push the PAP on the stack and
46    return to the scheduler.
47
48    On entry: R1 points to the PAP.  The rest of the function's
49    arguments (apart from those that are already in the PAP) are on the
50    stack, starting at Sp(0).  R2 contains an info table which
51    describes these arguments, which is used in the event that the
52    stack check in the entry code below fails.  The info table is
53    currently one of the stg_ap_*_ret family, as this code is always
54    entered from those functions.
55
56    The idea is to copy the chunk of stack from the PAP object onto the
57    stack / into registers, and enter the function.
58    -------------------------------------------------------------------------- */
59
60 INFO_TABLE(stg_PAP,/*special layout*/0,0,PAP,"PAP","PAP")
61 {  foreign "C" barf("PAP object entered!"); }
62     
63 stg_PAP_apply
64 {
65   W_ Words;
66   W_ pap;
67     
68   pap = R1;
69
70   Words = TO_W_(StgPAP_n_args(pap));
71
72   //
73   // Check for stack overflow and bump the stack pointer.
74   // We have a hand-rolled stack check fragment here, because none of
75   // the canned ones suit this situation.
76   //
77   if ((Sp - WDS(Words)) < SpLim) {
78       // there is a return address in R2 in the event of a
79       // stack check failure.  The various stg_apply functions arrange
80       // this before calling stg_PAP_entry.
81       Sp_adj(-1); 
82       Sp(0) = R2;
83       jump stg_gc_unpt_r1;
84   }
85   Sp_adj(-Words);
86
87   // profiling
88   TICK_ENT_PAP();
89   LDV_ENTER(pap);
90   // Enter PAP cost centre 
91   ENTER_CCS_PAP_CL(pap);
92
93   R1 = StgPAP_fun(pap);
94
95   // Reload the stack 
96   W_ i;
97   W_ p;
98   p = pap + SIZEOF_StgHeader + OFFSET_StgPAP_payload;
99   i = 0;
100 for:
101   if (i < Words) {
102     Sp(i) = W_[p];
103     p = p + WDS(1);
104     i = i + 1;
105     goto for;
106   }
107
108   // Off we go! 
109   TICK_ENT_VIA_NODE();
110
111 #ifdef NO_ARG_REGS
112   jump %GET_ENTRY(R1);
113 #else
114       W_ info;
115       info = %GET_FUN_INFO(R1);
116       W_ type;
117       type = TO_W_(StgFunInfoExtra_fun_type(info));
118       if (type == ARG_GEN) {
119           jump StgFunInfoExtra_slow_apply(info);
120       }
121       if (type == ARG_GEN_BIG) {
122           jump StgFunInfoExtra_slow_apply(info);
123       }
124       if (type == ARG_BCO) {
125           Sp_adj(-2);
126           Sp(1) = R1;
127           Sp(0) = stg_apply_interp_info;
128           jump stg_yield_to_interpreter;
129       }
130       jump W_[stg_ap_stack_entries + 
131                 WDS(TO_W_(StgFunInfoExtra_fun_type(info)))];
132 #endif
133 }
134
135 /* -----------------------------------------------------------------------------
136    Entry Code for an AP (a PAP with arity zero).
137
138    The entry code is very similar to a PAP, except there are no
139    further arguments on the stack to worry about, so the stack check
140    is simpler.  We must also push an update frame on the stack before
141    applying the function.
142    -------------------------------------------------------------------------- */
143
144 INFO_TABLE(stg_AP,/*special layout*/0,0,AP,"AP","AP")
145 {
146   W_ Words;
147   W_ ap;
148     
149   ap = R1;
150   
151   Words = TO_W_(StgAP_n_args(ap));
152
153   /* 
154    * Check for stack overflow.  IMPORTANT: use a _NP check here,
155    * because if the check fails, we might end up blackholing this very
156    * closure, in which case we must enter the blackhole on return rather
157    * than continuing to evaluate the now-defunct closure.
158    */
159   STK_CHK_NP(WDS(Words) + SIZEOF_StgUpdateFrame);
160
161   PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);
162   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(Words);
163
164   TICK_ENT_AP();
165   LDV_ENTER(ap);
166
167   // Enter PAP cost centre
168   ENTER_CCS_PAP_CL(ap);   // ToDo: ENTER_CC_AP_CL 
169
170   R1 = StgAP_fun(ap);
171
172   // Reload the stack 
173   W_ i;
174   W_ p;
175   p = ap + SIZEOF_StgHeader + OFFSET_StgAP_payload;
176   i = 0;
177 for:
178   if (i < Words) {
179     Sp(i) = W_[p];
180     p = p + WDS(1);
181     i = i + 1;
182     goto for;
183   }
184
185   // Off we go! 
186   TICK_ENT_VIA_NODE();
187
188 #ifdef NO_ARG_REGS
189   jump %GET_ENTRY(R1);
190 #else
191       W_ info;
192       info = %GET_FUN_INFO(R1);
193       W_ type;
194       type = TO_W_(StgFunInfoExtra_fun_type(info));
195       if (type == ARG_GEN) {
196           jump StgFunInfoExtra_slow_apply(info);
197       }
198       if (type == ARG_GEN_BIG) {
199           jump StgFunInfoExtra_slow_apply(info);
200       }
201       if (type == ARG_BCO) {
202           Sp_adj(-2);
203           Sp(1) = R1;
204           Sp(0) = stg_apply_interp_info;
205           jump stg_yield_to_interpreter;
206       }
207       jump W_[stg_ap_stack_entries + 
208                 WDS(TO_W_(StgFunInfoExtra_fun_type(info)))];
209 #endif
210 }
211
212 /* -----------------------------------------------------------------------------
213    Entry Code for an AP_STACK.
214
215    Very similar to a PAP and AP.  The layout is the same as PAP
216    and AP, except that the payload is a chunk of stack instead of
217    being described by the function's info table.  Like an AP,
218    there are no further arguments on the stack to worry about.
219    However, the function closure (ap->fun) does not necessarily point
220    directly to a function, so we have to enter it using stg_ap_0.
221    -------------------------------------------------------------------------- */
222
223 INFO_TABLE(stg_AP_STACK,/*special layout*/0,0,AP_STACK,"AP_STACK","AP_STACK")
224 {
225   W_ Words;
226   W_ ap;
227
228   ap = R1;
229   
230   Words = StgAP_STACK_size(ap);
231
232   /* 
233    * Check for stack overflow.  IMPORTANT: use a _NP check here,
234    * because if the check fails, we might end up blackholing this very
235    * closure, in which case we must enter the blackhole on return rather
236    * than continuing to evaluate the now-defunct closure.
237    */
238   STK_CHK_NP(WDS(Words) + SIZEOF_StgUpdateFrame);
239
240   PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);
241   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(Words);
242
243   TICK_ENT_AP();
244   LDV_ENTER(ap);
245
246   // Enter PAP cost centre
247   ENTER_CCS_PAP_CL(ap);   // ToDo: ENTER_CC_AP_CL 
248
249   R1 = StgAP_STACK_fun(ap);
250
251   // Reload the stack
252   W_ i;
253   W_ p;
254   p = ap + SIZEOF_StgHeader + OFFSET_StgAP_STACK_payload;
255   i = 0;
256 for:
257   if (i < Words) {
258     Sp(i) = W_[p];
259     p = p + WDS(1);
260     i = i + 1;
261     goto for;
262   }
263
264   // Off we go!
265   TICK_ENT_VIA_NODE();
266
267   ENTER();
268 }