pass arguments to unknown function calls in registers
[ghc-hetmet.git] / ghc / 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(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 {
62   W_ Words;
63   W_ pap;
64     
65   pap = R1;
66
67   Words = TO_W_(StgPAP_n_args(pap));
68
69   //
70   // Check for stack overflow and bump the stack pointer.
71   // We have a hand-rolled stack check fragment here, because none of
72   // the canned ones suit this situation.
73   //
74   if ((Sp - WDS(Words)) < SpLim) {
75       // there is a return address in R2 in the event of a
76       // stack check failure.  The various stg_apply functions arrange
77       // this before calling stg_PAP_entry.
78       Sp_adj(-1); 
79       Sp(0) = R2;
80       jump stg_gc_unpt_r1;
81   }
82   Sp_adj(-Words);
83
84   // profiling
85   TICK_ENT_PAP();
86   LDV_ENTER(pap);
87   // Enter PAP cost centre 
88   ENTER_CCS_PAP_CL(pap);
89
90   R1 = StgPAP_fun(pap);
91
92   // Reload the stack 
93   W_ i;
94   W_ p;
95   p = pap + SIZEOF_StgHeader + OFFSET_StgPAP_payload;
96   i = 0;
97 for:
98   if (i < Words) {
99     Sp(i) = W_[p];
100     p = p + WDS(1);
101     i = i + 1;
102     goto for;
103   }
104
105   // Off we go! 
106   TICK_ENT_VIA_NODE();
107
108 #ifdef NO_ARG_REGS
109   jump %GET_ENTRY(R1);
110 #else
111       W_ info;
112       info = %GET_FUN_INFO(R1);
113       W_ type;
114       type = TO_W_(StgFunInfoExtra_fun_type(info));
115       if (type == ARG_GEN) {
116           jump StgFunInfoExtra_slow_apply(info);
117       }
118       if (type == ARG_GEN_BIG) {
119           jump StgFunInfoExtra_slow_apply(info);
120       }
121       if (type == ARG_BCO) {
122           Sp_adj(-2);
123           Sp(1) = R1;
124           Sp(0) = stg_apply_interp_info;
125           jump stg_yield_to_interpreter;
126       }
127       jump W_[stg_ap_stack_entries + 
128                 WDS(TO_W_(StgFunInfoExtra_fun_type(info)))];
129 #endif
130 }
131
132 /* -----------------------------------------------------------------------------
133    Entry Code for an AP (a PAP with arity zero).
134
135    The entry code is very similar to a PAP, except there are no
136    further arguments on the stack to worry about, so the stack check
137    is simpler.  We must also push an update frame on the stack before
138    applying the function.
139    -------------------------------------------------------------------------- */
140
141 INFO_TABLE(stg_AP,/*special layout*/0,0,AP,"AP","AP")
142 {
143   W_ Words;
144   W_ ap;
145     
146   ap = R1;
147   
148   Words = TO_W_(StgAP_n_args(ap));
149
150   /* 
151    * Check for stack overflow.  IMPORTANT: use a _NP check here,
152    * because if the check fails, we might end up blackholing this very
153    * closure, in which case we must enter the blackhole on return rather
154    * than continuing to evaluate the now-defunct closure.
155    */
156   STK_CHK_NP(WDS(Words) + SIZEOF_StgUpdateFrame);
157
158   PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);
159   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(Words);
160
161   TICK_ENT_AP();
162   LDV_ENTER(ap);
163
164   // Enter PAP cost centre
165   ENTER_CCS_PAP_CL(ap);   // ToDo: ENTER_CC_AP_CL 
166
167   R1 = StgAP_fun(ap);
168
169   // Reload the stack 
170   W_ i;
171   W_ p;
172   p = ap + SIZEOF_StgHeader + OFFSET_StgAP_payload;
173   i = 0;
174 for:
175   if (i < Words) {
176     Sp(i) = W_[p];
177     p = p + WDS(1);
178     i = i + 1;
179     goto for;
180   }
181
182   // Off we go! 
183   TICK_ENT_VIA_NODE();
184
185 #ifdef NO_ARG_REGS
186   jump %GET_ENTRY(R1);
187 #else
188       W_ info;
189       info = %GET_FUN_INFO(R1);
190       W_ type;
191       type = TO_W_(StgFunInfoExtra_fun_type(info));
192       if (type == ARG_GEN) {
193           jump StgFunInfoExtra_slow_apply(info);
194       }
195       if (type == ARG_GEN_BIG) {
196           jump StgFunInfoExtra_slow_apply(info);
197       }
198       if (type == ARG_BCO) {
199           Sp_adj(-2);
200           Sp(1) = R1;
201           Sp(0) = stg_apply_interp_info;
202           jump stg_yield_to_interpreter;
203       }
204       jump W_[stg_ap_stack_entries + 
205                 WDS(TO_W_(StgFunInfoExtra_fun_type(info)))];
206 #endif
207 }
208
209 /* -----------------------------------------------------------------------------
210    Entry Code for an AP_STACK.
211
212    Very similar to a PAP and AP.  The layout is the same as PAP
213    and AP, except that the payload is a chunk of stack instead of
214    being described by the function's info table.  Like an AP,
215    there are no further arguments on the stack to worry about.
216    However, the function closure (ap->fun) does not necessarily point
217    directly to a function, so we have to enter it using stg_ap_0.
218    -------------------------------------------------------------------------- */
219
220 INFO_TABLE(stg_AP_STACK,/*special layout*/0,0,AP_STACK,"AP_STACK","AP_STACK")
221 {
222   W_ Words;
223   W_ ap;
224
225   ap = R1;
226   
227   Words = StgAP_STACK_size(ap);
228
229   /* 
230    * Check for stack overflow.  IMPORTANT: use a _NP check here,
231    * because if the check fails, we might end up blackholing this very
232    * closure, in which case we must enter the blackhole on return rather
233    * than continuing to evaluate the now-defunct closure.
234    */
235   STK_CHK_NP(WDS(Words) + SIZEOF_StgUpdateFrame);
236
237   PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1);
238   Sp = Sp - SIZEOF_StgUpdateFrame - WDS(Words);
239
240   TICK_ENT_AP();
241   LDV_ENTER(ap);
242
243   // Enter PAP cost centre
244   ENTER_CCS_PAP_CL(ap);   // ToDo: ENTER_CC_AP_CL 
245
246   R1 = StgAP_STACK_fun(ap);
247
248   // Reload the stack
249   W_ i;
250   W_ p;
251   p = ap + SIZEOF_StgHeader + OFFSET_StgAP_STACK_payload;
252   i = 0;
253 for:
254   if (i < Words) {
255     Sp(i) = W_[p];
256     p = p + WDS(1);
257     i = i + 1;
258     goto for;
259   }
260
261   // Off we go!
262   TICK_ENT_VIA_NODE();
263
264   ENTER();
265 }