1 /* -----------------------------------------------------------------------------
3 * (c) The University of Glasgow, 1998-2004
5 * Canned "Standard Form" Thunks
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.
11 * ---------------------------------------------------------------------------*/
16 /* -----------------------------------------------------------------------------
17 The code for a thunk that simply extracts a field from a
18 single-constructor datatype depends only on the offset of the field
21 Here we define some canned "selector" thunks that do just that; any
22 selector thunk appearing in a program will refer to one of these
23 instead of being compiled independently.
25 The garbage collector spots selector thunks and reduces them if
26 possible, in order to avoid space leaks resulting from lazy pattern
28 -------------------------------------------------------------------------- */
31 #define SAVE_CCS W_ saved_ccs; saved_ccs = CCCS;
32 #define RESTORE_CCS CCCS = saved_ccs;
34 #define SAVE_CCS /* nothing */
35 #define RESTORE_CCS /* nothing */
39 * TODO: On return, we can use a more efficient
40 * untagging (we know the constructor tag).
42 * When entering stg_sel_#_upd, we know R1 points to its closure,
44 * The payload might be a thunk or a constructor,
47 * When returning, we know for sure it is a constructor,
48 * so we untag it before accessing the field.
52 /* When profiling, we cannot shortcut by checking the tag,
53 * because LDV profiling relies on entering closures to mark them as
56 * Note [untag for prof]: when we enter a closure, the convention is
57 * that the closure pointer passed in the first argument is
58 * *untagged*. Without profiling we don't have to worry about this,
59 * because we never enter a tagged pointer.
61 #define NEED_EVAL(__x__) 1
63 #define NEED_EVAL(__x__) GETTAG(__x__) == 0
66 #define SELECTOR_CODE_UPD(offset) \
67 INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
70 P_ selectee, field, dest; \
73 UPD_BH_UPDATABLE(node); \
75 selectee = StgThunk_payload(node,0); \
76 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info,CCCS,0,node)) { \
77 ENTER_CCS_THUNK(node); \
78 if (NEED_EVAL(selectee)) { \
80 dest = UNTAG_IF_PROF(selectee); /* Note [untag for prof] */ \
81 (P_ constr) = call %GET_ENTRY(dest) (dest); \
85 field = StgClosure_payload(UNTAG(selectee),offset); \
86 jump stg_ap_0_fast(field); \
89 /* NOTE: no need to ENTER() here, we know the closure cannot
90 evaluate to a function, because we're going to do a field
91 selection on the result. */
103 SELECTOR_CODE_UPD(10)
104 SELECTOR_CODE_UPD(11)
105 SELECTOR_CODE_UPD(12)
106 SELECTOR_CODE_UPD(13)
107 SELECTOR_CODE_UPD(14)
108 SELECTOR_CODE_UPD(15)
111 #define SELECTOR_CODE_NOUPD(offset) \
112 INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd") \
115 P_ selectee, field, dest; \
116 TICK_ENT_DYN_THK(); \
118 UPD_BH_UPDATABLE(node); \
120 selectee = StgThunk_payload(node,0); \
121 ENTER_CCS_THUNK(node); \
122 if (NEED_EVAL(selectee)) { \
124 dest = UNTAG_IF_PROF(selectee); /* Note [untag for prof] */ \
125 (P_ constr) = call %GET_ENTRY(dest) (dest); \
129 field = StgClosure_payload(UNTAG(selectee),offset); \
130 jump stg_ap_0_fast(field); \
134 SELECTOR_CODE_NOUPD(0)
135 SELECTOR_CODE_NOUPD(1)
136 SELECTOR_CODE_NOUPD(2)
137 SELECTOR_CODE_NOUPD(3)
138 SELECTOR_CODE_NOUPD(4)
139 SELECTOR_CODE_NOUPD(5)
140 SELECTOR_CODE_NOUPD(6)
141 SELECTOR_CODE_NOUPD(7)
142 SELECTOR_CODE_NOUPD(8)
143 SELECTOR_CODE_NOUPD(9)
144 SELECTOR_CODE_NOUPD(10)
145 SELECTOR_CODE_NOUPD(11)
146 SELECTOR_CODE_NOUPD(12)
147 SELECTOR_CODE_NOUPD(13)
148 SELECTOR_CODE_NOUPD(14)
149 SELECTOR_CODE_NOUPD(15)
151 /* -----------------------------------------------------------------------------
154 An apply thunk is a thunk of the form
156 let z = [x1...xn] \u x1...xn
159 We pre-compile some of these because the code is always the same.
161 These have to be independent of the update frame size, so the code
162 works when profiling etc.
163 -------------------------------------------------------------------------- */
165 /* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
166 * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
169 INFO_TABLE(stg_ap_1_upd,1,0,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
174 UPD_BH_UPDATABLE(node);
176 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
177 ENTER_CCS_THUNK(node);
179 (StgThunk_payload(node,0));
183 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
188 UPD_BH_UPDATABLE(node);
190 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
191 ENTER_CCS_THUNK(node);
193 (StgThunk_payload(node,0),
194 StgThunk_payload(node,1));
198 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
203 UPD_BH_UPDATABLE(node);
205 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
206 ENTER_CCS_THUNK(node);
208 (StgThunk_payload(node,0),
209 StgThunk_payload(node,1),
210 StgThunk_payload(node,2));
214 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
219 UPD_BH_UPDATABLE(node);
221 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
222 ENTER_CCS_THUNK(node);
224 (StgThunk_payload(node,0),
225 StgThunk_payload(node,1),
226 StgThunk_payload(node,2),
227 StgThunk_payload(node,3));
231 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
236 UPD_BH_UPDATABLE(node);
238 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
239 ENTER_CCS_THUNK(node);
240 jump stg_ap_pppp_fast
241 (StgThunk_payload(node,0),
242 StgThunk_payload(node,1),
243 StgThunk_payload(node,2),
244 StgThunk_payload(node,3),
245 StgThunk_payload(node,4));
249 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
254 UPD_BH_UPDATABLE(node);
256 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
257 ENTER_CCS_THUNK(node);
258 jump stg_ap_ppppp_fast
259 (StgThunk_payload(node,0),
260 StgThunk_payload(node,1),
261 StgThunk_payload(node,2),
262 StgThunk_payload(node,3),
263 StgThunk_payload(node,4),
264 StgThunk_payload(node,5));
268 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
273 UPD_BH_UPDATABLE(node);
275 push (UPDATE_FRAME_FIELDS(,,stg_upd_frame_info, CCCS, 0, node)) {
276 ENTER_CCS_THUNK(node);
277 jump stg_ap_pppppp_fast
278 (StgThunk_payload(node,0),
279 StgThunk_payload(node,1),
280 StgThunk_payload(node,2),
281 StgThunk_payload(node,3),
282 StgThunk_payload(node,4),
283 StgThunk_payload(node,5),
284 StgThunk_payload(node,6));