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 * ---------------------------------------------------------------------------*/
15 /* -----------------------------------------------------------------------------
16 The code for a thunk that simply extracts a field from a
17 single-constructor datatype depends only on the offset of the field
20 Here we define some canned "selector" thunks that do just that; any
21 selector thunk appearing in a program will refer to one of these
22 instead of being compiled independently.
24 The garbage collector spots selector thunks and reduces them if
25 possible, in order to avoid space leaks resulting from lazy pattern
27 -------------------------------------------------------------------------- */
29 #define WITHUPD_FRAME_SIZE (SIZEOF_StgUpdateFrame + SIZEOF_StgHeader)
30 #define NOUPD_FRAME_SIZE (SIZEOF_StgHeader)
33 #define SAVE_CCCS(fs) StgHeader_ccs(Sp-fs) = W_[CCCS]
34 #define GET_SAVED_CCCS W_[CCCS] = StgHeader_ccs(Sp)
35 #define RET_PARAMS W_ unused1, W_ unused2
37 #define SAVE_CCCS(fs) /* empty */
38 #define GET_SAVED_CCCS /* empty */
43 * TODO: On return, we can use a more efficient
44 * untagging (we know the constructor tag).
46 * When entering stg_sel_#_upd, we know R1 points to its closure,
48 * The payload might be a thunk or a constructor,
51 * When returning, we know for sure it is a constructor,
52 * so we untag it before accessing the field.
55 #define SELECTOR_CODE_UPD(offset) \
56 INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_SMALL, RET_PARAMS) \
58 R1 = StgClosure_payload(UNTAG(R1),offset); \
60 Sp = Sp + SIZEOF_StgHeader; \
64 INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
67 STK_CHK_NP(WITHUPD_FRAME_SIZE); \
70 PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1); \
71 ENTER_CCS_THUNK(R1); \
72 SAVE_CCCS(WITHUPD_FRAME_SIZE); \
73 W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info; \
74 Sp = Sp - WITHUPD_FRAME_SIZE; \
75 R1 = StgThunk_payload(R1,0); \
76 if (GETTAG(R1) != 0) { \
77 jump RET_LBL(stg_sel_ret_##offset##_upd); \
79 jump %GET_ENTRY(R1); \
81 /* NOTE: no need to ENTER() here, we know the closure cannot evaluate to a function,
82 because we're going to do a field selection on the result. */
101 #define SELECTOR_CODE_NOUPD(offset) \
102 INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_SMALL, RET_PARAMS) \
104 R1 = StgClosure_payload(UNTAG(R1),offset); \
106 Sp = Sp + SIZEOF_StgHeader; \
110 INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
112 TICK_ENT_DYN_THK(); \
113 STK_CHK_NP(NOUPD_FRAME_SIZE); \
114 UPD_BH_SINGLE_ENTRY(); \
116 TICK_UPDF_OMITTED(); \
117 ENTER_CCS_THUNK(R1); \
118 SAVE_CCCS(NOUPD_FRAME_SIZE); \
119 W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info; \
120 Sp = Sp - NOUPD_FRAME_SIZE; \
121 R1 = StgThunk_payload(R1,0); \
122 if (GETTAG(R1) != 0) { \
123 jump RET_LBL(stg_sel_ret_##offset##_noupd); \
125 jump %GET_ENTRY(R1); \
128 SELECTOR_CODE_NOUPD(0)
129 SELECTOR_CODE_NOUPD(1)
130 SELECTOR_CODE_NOUPD(2)
131 SELECTOR_CODE_NOUPD(3)
132 SELECTOR_CODE_NOUPD(4)
133 SELECTOR_CODE_NOUPD(5)
134 SELECTOR_CODE_NOUPD(6)
135 SELECTOR_CODE_NOUPD(7)
136 SELECTOR_CODE_NOUPD(8)
137 SELECTOR_CODE_NOUPD(9)
138 SELECTOR_CODE_NOUPD(10)
139 SELECTOR_CODE_NOUPD(11)
140 SELECTOR_CODE_NOUPD(12)
141 SELECTOR_CODE_NOUPD(13)
142 SELECTOR_CODE_NOUPD(14)
143 SELECTOR_CODE_NOUPD(15)
145 /* -----------------------------------------------------------------------------
148 An apply thunk is a thunk of the form
150 let z = [x1...xn] \u x1...xn
153 We pre-compile some of these because the code is always the same.
155 These have to be independent of the update frame size, so the code
156 works when profiling etc.
157 -------------------------------------------------------------------------- */
159 /* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
160 * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
163 INFO_TABLE(stg_ap_1_upd,1,0,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
166 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
170 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
171 R1 = StgThunk_payload(R1,0);
172 Sp = Sp - SIZEOF_StgUpdateFrame;
176 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
179 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
183 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
184 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,1);
185 R1 = StgThunk_payload(R1,0);
186 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
187 Sp_adj(-1); // for stg_ap_*_ret
190 jump RET_LBL(stg_ap_p);
193 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
196 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
200 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
201 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,2);
202 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,1);
203 R1 = StgThunk_payload(R1,0);
204 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
205 Sp_adj(-1); // for stg_ap_*_ret
208 jump RET_LBL(stg_ap_pp);
211 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
214 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
218 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
219 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,3);
220 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,2);
221 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,1);
222 R1 = StgThunk_payload(R1,0);
223 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
224 Sp_adj(-1); // for stg_ap_*_ret
226 TICK_SLOW_CALL_ppp();
227 jump RET_LBL(stg_ap_ppp);
230 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
233 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
237 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
238 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,4);
239 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,3);
240 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,2);
241 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,1);
242 R1 = StgThunk_payload(R1,0);
243 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
244 Sp_adj(-1); // for stg_ap_*_ret
246 TICK_SLOW_CALL_pppp();
247 jump RET_LBL(stg_ap_pppp);
250 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
253 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
257 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
258 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,5);
259 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,4);
260 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,3);
261 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,2);
262 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,1);
263 R1 = StgThunk_payload(R1,0);
264 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
265 Sp_adj(-1); // for stg_ap_*_ret
267 TICK_SLOW_CALL_ppppp();
268 jump RET_LBL(stg_ap_ppppp);
271 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
274 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
278 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
279 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,6);
280 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,5);
281 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,4);
282 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,3);
283 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,2);
284 W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgThunk_payload(R1,1);
285 R1 = StgThunk_payload(R1,0);
286 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
287 Sp_adj(-1); // for stg_ap_*_ret
289 TICK_SLOW_CALL_pppppp();
290 jump RET_LBL(stg_ap_pppppp);