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)
36 #define RET_FRAMESIZE 2
38 #define SAVE_CCCS(fs) /* empty */
39 #define GET_SAVED_CCCS /* empty */
41 #define RET_FRAMESIZE 0
44 #define SELECTOR_CODE_UPD(offset) \
45 INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL) \
47 R1 = StgClosure_payload(R1,offset); \
49 Sp = Sp + SIZEOF_StgHeader; \
53 INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
56 STK_CHK_NP(WITHUPD_FRAME_SIZE); \
59 PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1); \
60 ENTER_CCS_THUNK(R1); \
61 SAVE_CCCS(WITHUPD_FRAME_SIZE); \
62 W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info; \
63 R1 = StgThunk_payload(R1,0); \
64 Sp = Sp - WITHUPD_FRAME_SIZE; \
65 jump %GET_ENTRY(R1); \
67 /* NOTE: no need to ENTER() here, we know the closure cannot evaluate to a function,
68 because we're going to do a field selection on the result. */
87 #define SELECTOR_CODE_NOUPD(offset) \
88 INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_FRAMESIZE, RET_BITMAP, RET_SMALL) \
90 R1 = StgClosure_payload(R1,offset); \
92 Sp = Sp + SIZEOF_StgHeader; \
93 jump %GET_ENTRY(R1); \
96 INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
99 STK_CHK_NP(NOUPD_FRAME_SIZE); \
100 UPD_BH_SINGLE_ENTRY(); \
102 TICK_UPDF_OMITTED(); \
103 ENTER_CCS_THUNK(R1); \
104 SAVE_CCCS(NOUPD_FRAME_SIZE); \
105 W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info; \
106 R1 = StgThunk_payload(R1,0); \
107 Sp = Sp - NOUPD_FRAME_SIZE; \
108 jump %GET_ENTRY(R1); \
111 SELECTOR_CODE_NOUPD(0)
112 SELECTOR_CODE_NOUPD(1)
113 SELECTOR_CODE_NOUPD(2)
114 SELECTOR_CODE_NOUPD(3)
115 SELECTOR_CODE_NOUPD(4)
116 SELECTOR_CODE_NOUPD(5)
117 SELECTOR_CODE_NOUPD(6)
118 SELECTOR_CODE_NOUPD(7)
119 SELECTOR_CODE_NOUPD(8)
120 SELECTOR_CODE_NOUPD(9)
121 SELECTOR_CODE_NOUPD(10)
122 SELECTOR_CODE_NOUPD(11)
123 SELECTOR_CODE_NOUPD(12)
124 SELECTOR_CODE_NOUPD(13)
125 SELECTOR_CODE_NOUPD(14)
126 SELECTOR_CODE_NOUPD(15)
128 /* -----------------------------------------------------------------------------
131 An apply thunk is a thunk of the form
133 let z = [x1...xn] \u x1...xn
136 We pre-compile some of these because the code is always the same.
138 These have to be independent of the update frame size, so the code
139 works when profiling etc.
140 -------------------------------------------------------------------------- */
142 /* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
143 * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
146 INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
149 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
153 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
154 R1 = StgThunk_payload(R1,0);
155 Sp = Sp - SIZEOF_StgUpdateFrame;
159 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
162 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
166 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
167 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,1);
168 R1 = StgThunk_payload(R1,0);
169 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
170 Sp_adj(-1); // for stg_ap_*_ret
173 jump RET_LBL(stg_ap_p);
176 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
179 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
183 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
184 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,2);
185 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,1);
186 R1 = StgThunk_payload(R1,0);
187 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
188 Sp_adj(-1); // for stg_ap_*_ret
191 jump RET_LBL(stg_ap_pp);
194 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
197 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
201 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
202 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,3);
203 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,2);
204 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,1);
205 R1 = StgThunk_payload(R1,0);
206 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
207 Sp_adj(-1); // for stg_ap_*_ret
209 TICK_SLOW_CALL_ppp();
210 jump RET_LBL(stg_ap_ppp);
213 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
216 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
220 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
221 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,4);
222 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,3);
223 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,2);
224 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,1);
225 R1 = StgThunk_payload(R1,0);
226 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
227 Sp_adj(-1); // for stg_ap_*_ret
229 TICK_SLOW_CALL_pppp();
230 jump RET_LBL(stg_ap_pppp);
233 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
236 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
240 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
241 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,5);
242 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,4);
243 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,3);
244 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,2);
245 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,1);
246 R1 = StgThunk_payload(R1,0);
247 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
248 Sp_adj(-1); // for stg_ap_*_ret
250 TICK_SLOW_CALL_ppppp();
251 jump RET_LBL(stg_ap_ppppp);
254 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
257 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
261 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
262 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,6);
263 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,5);
264 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,4);
265 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,3);
266 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,2);
267 W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgThunk_payload(R1,1);
268 R1 = StgThunk_payload(R1,0);
269 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
270 Sp_adj(-1); // for stg_ap_*_ret
272 TICK_SLOW_CALL_pppppp();
273 jump RET_LBL(stg_ap_pppppp);