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 = StgClosure_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 = StgClosure_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 = StgClosure_payload(R1,0);
155 Sp = Sp - SIZEOF_StgUpdateFrame;
156 Sp_adj(-1); // for stg_ap_0_ret
157 jump RET_LBL(stg_ap_0);
160 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
163 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
167 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
168 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,1);
169 R1 = StgClosure_payload(R1,0);
170 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
171 Sp_adj(-1); // for stg_ap_0_ret
174 jump RET_LBL(stg_ap_p);
177 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
180 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
184 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
185 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,2);
186 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,1);
187 R1 = StgClosure_payload(R1,0);
188 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
189 Sp_adj(-1); // for stg_ap_0_ret
192 jump RET_LBL(stg_ap_pp);
195 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
198 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
202 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
203 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,3);
204 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,2);
205 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,1);
206 R1 = StgClosure_payload(R1,0);
207 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
208 Sp_adj(-1); // for stg_ap_0_ret
210 TICK_SLOW_CALL_ppp();
211 jump RET_LBL(stg_ap_ppp);
214 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
217 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
221 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
222 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,4);
223 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,3);
224 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,2);
225 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,1);
226 R1 = StgClosure_payload(R1,0);
227 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
228 Sp_adj(-1); // for stg_ap_0_ret
230 TICK_SLOW_CALL_pppp();
231 jump RET_LBL(stg_ap_pppp);
234 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
237 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
241 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
242 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,5);
243 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,4);
244 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,3);
245 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,2);
246 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgClosure_payload(R1,1);
247 R1 = StgClosure_payload(R1,0);
248 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
249 Sp_adj(-1); // for stg_ap_0_ret
251 TICK_SLOW_CALL_ppppp();
252 jump RET_LBL(stg_ap_ppppp);
255 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
258 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
262 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
263 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgClosure_payload(R1,6);
264 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgClosure_payload(R1,5);
265 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgClosure_payload(R1,4);
266 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgClosure_payload(R1,3);
267 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgClosure_payload(R1,2);
268 W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgClosure_payload(R1,1);
269 R1 = StgClosure_payload(R1,0);
270 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
271 Sp_adj(-1); // for stg_ap_0_ret
273 TICK_SLOW_CALL_pppppp();
274 jump RET_LBL(stg_ap_pppppp);