[project @ 2002-12-11 15:36:20 by simonmar]
[ghc-hetmet.git] / ghc / rts / Apply.hc
1 // -----------------------------------------------------------------------------
2 // Apply.hc
3 //
4 // (c) The University of Glasgow 2002
5 //
6 // Application-related bits.
7 //
8 // -----------------------------------------------------------------------------
9
10 #include "Stg.h"
11 #include "Rts.h"
12 #include "RtsFlags.h"
13 #include "Storage.h"
14 #include "RtsUtils.h"
15 #include "Printer.h"
16 #include "Sanity.h"
17 #include "Apply.h"
18
19 #include <stdio.h>
20
21 // ----------------------------------------------------------------------------
22 // Evaluate a closure and return it.
23 //
24 //      stg_ap_0_info   <--- Sp
25 //
26 // NOTE: this needs to be a polymorphic return point, because we can't
27 // be sure that the thing being evaluated is not a function.
28
29 // These names are just to keep VEC_POLY_INFO_TABLE() happy - all the
30 // entry points in the polymorphic info table point to the same code.
31 #define stg_ap_0_0_ret stg_ap_0_ret
32 #define stg_ap_0_1_ret stg_ap_0_ret
33 #define stg_ap_0_2_ret stg_ap_0_ret
34 #define stg_ap_0_3_ret stg_ap_0_ret
35 #define stg_ap_0_4_ret stg_ap_0_ret
36 #define stg_ap_0_5_ret stg_ap_0_ret
37 #define stg_ap_0_6_ret stg_ap_0_ret
38 #define stg_ap_0_7_ret stg_ap_0_ret
39
40 VEC_POLY_INFO_TABLE(stg_ap_0,
41                MK_SMALL_BITMAP(0/*framsize*/, 0/*bitmap*/),
42                0,0,0,RET_SMALL,,EF_);
43 F_
44 stg_ap_0_ret(void)
45
46     // fn is in R1, no args on the stack
47     StgInfoTable *info;
48     nat arity;
49     FB_;
50
51     IF_DEBUG(apply,fprintf(stderr, "stg_ap_0_ret... "); printClosure(R1.cl));
52     IF_DEBUG(sanity,checkStackChunk(Sp+1,CurrentTSO->stack + CurrentTSO->stack_size));
53
54     Sp++;
55     ENTER();
56     FE_
57 }
58
59 /* -----------------------------------------------------------------------------
60    Entry Code for a PAP.
61
62    This entry code is *only* called by one of the stg_ap functions.
63    On entry: Sp points to the remaining arguments on the stack.  If
64    the stack check fails, we can just push the PAP on the stack and
65    return to the scheduler.
66
67    On entry: R1 points to the PAP.  The rest of the function's arguments
68    (*all* of 'em) are on the stack, starting at Sp[0].
69
70    The idea is to copy the chunk of stack from the PAP object onto the
71    stack / into registers, and enter the function.
72    -------------------------------------------------------------------------- */
73
74 INFO_TABLE(stg_PAP_info,stg_PAP_entry,/*special layout*/0,0,PAP,,EF_,"PAP","PAP");
75 STGFUN(stg_PAP_entry)
76 {
77   nat Words;
78   StgPtr p;
79   nat i;
80   StgPAP *pap;
81   FB_
82     
83   pap = (StgPAP *) R1.p;
84
85   Words = pap->n_args;
86
87   // Check for stack overflow and bump the stack pointer.
88   // We have a hand-rolled stack check fragment here, because none of
89   // the canned ones suit this situation.
90   if ((Sp - Words) < SpLim) {
91       // there is a return address on the stack in the event of a
92       // stack check failure.  The various stg_apply functions arrange
93       // this before calling stg_PAP_entry.
94       JMP_(stg_gc_unpt_r1);
95   }
96   // Sp is already pointing one word below the arguments...
97   Sp -= Words-1;
98
99   // profiling
100   TICK_ENT_PAP(pap);
101   LDV_ENTER(pap);
102   // Enter PAP cost centre -- lexical scoping only
103   ENTER_CCS_PAP_CL(pap);
104
105   R1.cl = pap->fun;
106   p = (P_)(pap->payload);
107
108   // Reload the stack
109   for (i=0; i<Words; i++) {
110       Sp[i] = (W_) *p++;
111   }
112
113   // Off we go!
114   TICK_ENT_VIA_NODE();
115
116 #ifdef NO_ARG_REGS
117   JMP_(GET_ENTRY(R1.cl));
118 #else
119   {
120       StgFunInfoTable *info;
121       info = get_fun_itbl(R1.cl);
122       if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
123           JMP_(info->slow_apply);
124       } else if (info->fun_type == ARG_BCO) {
125           Sp -= 2;
126           Sp[1] = R1.w;
127           Sp[0] = (W_)&stg_apply_interp_info;
128           JMP_(stg_yield_to_interpreter);
129       } else {
130           JMP_(stg_ap_stack_entries[info->fun_type]);
131       }
132   }
133 #endif
134   FE_
135 }
136
137 /* -----------------------------------------------------------------------------
138    Entry Code for an AP (a PAP with arity zero).
139
140    The entry code is very similar to a PAP, except there are no
141    further arguments on the stack to worry about, so the stack check
142    is simpler.  We must also push an update frame on the stack before
143    applying the function.
144    -------------------------------------------------------------------------- */
145
146 INFO_TABLE(stg_AP_info,stg_AP_entry,/*special layout*/0,0,AP,,EF_,"AP","AP");
147 STGFUN(stg_AP_entry)
148 {
149   nat Words;
150   P_ p;
151   nat i;
152   StgAP *ap;
153
154   FB_
155     
156   ap = (StgAP *) R1.p;
157   
158   Words = ap->n_args;
159
160   // Check for stack overflow.
161   STK_CHK_GEN(Words+sizeofW(StgUpdateFrame), R1_PTR, stg_AP_entry);
162
163   PUSH_UPD_FRAME(R1.p, 0);
164   Sp -= sizeofW(StgUpdateFrame) + Words;
165
166   TICK_ENT_AP(ap);
167   LDV_ENTER(ap);
168
169   // Enter PAP cost centre -- lexical scoping only
170   ENTER_CCS_PAP_CL(ap);   /* ToDo: ENTER_CC_AP_CL */
171
172   R1.cl = ap->fun;
173   p = (P_)(ap->payload);
174
175   // Reload the stack
176   for (i=0; i<Words; i++) Sp[i] = (W_) *p++;
177
178   // Off we go!
179   TICK_ENT_VIA_NODE();
180
181 #ifdef NO_ARG_REGS
182   JMP_(GET_ENTRY(R1.cl));
183 #else
184   {
185       StgFunInfoTable *info;
186       info = get_fun_itbl(R1.cl);
187       if (info->fun_type == ARG_GEN || info->fun_type == ARG_GEN_BIG) {
188           JMP_(info->slow_apply);
189       } else if (info->fun_type == ARG_BCO) {
190           Sp -= 2;
191           Sp[1] = R1.w;
192           Sp[0] = (W_)&stg_apply_interp_info;
193           JMP_(stg_yield_to_interpreter);
194       } else {
195           JMP_(stg_ap_stack_entries[info->fun_type]);
196       }
197   }
198 #endif
199   FE_
200 }
201
202 /* -----------------------------------------------------------------------------
203    Entry Code for an AP_STACK.
204
205    Very similar to a PAP and AP.  The layout is the same as PAP
206    and AP, except that the payload is a chunk of stack instead of
207    being described by the function's info table.  Like an AP,
208    there are no further arguments on the stack to worry about.
209    However, the function closure (ap->fun) does not necessarily point
210    directly to a function, so we have to enter it using stg_ap_0.
211    -------------------------------------------------------------------------- */
212
213 INFO_TABLE(stg_AP_STACK_info,stg_AP_STACK_entry,/*special layout*/0,0,AP_STACK,,EF_,"AP_STACK","AP_STACK");
214 STGFUN(stg_AP_STACK_entry)
215 {
216   nat Words;
217   P_ p;
218   nat i;
219   StgAP_STACK *ap;
220
221   FB_
222     
223   ap = (StgAP_STACK *) R1.p;
224   
225   Words = ap->size;
226
227   // Check for stack overflow.
228   STK_CHK_GEN(Words+sizeofW(StgUpdateFrame), R1_PTR, stg_AP_STACK_entry);
229
230   PUSH_UPD_FRAME(R1.p, 0);
231   Sp -= sizeofW(StgUpdateFrame) + Words;
232
233   TICK_ENT_AP(ap);
234   LDV_ENTER(ap);
235
236   // Enter PAP cost centre -- lexical scoping only */
237   ENTER_CCS_PAP_CL(ap);   /* ToDo: ENTER_CC_AP_STACK_CL */
238
239   R1.cl = ap->fun;
240   p = (P_)(ap->payload);
241
242   // Reload the stack
243   for (i=0; i<Words; i++) Sp[i] = (W_) *p++;
244
245   // Off we go!
246   TICK_ENT_VIA_NODE();
247   ENTER();
248   FE_
249 }