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 */
42 #define SELECTOR_CODE_UPD(offset) \
43 INFO_TABLE_RET(stg_sel_ret_##offset##_upd, RET_SMALL, RET_PARAMS) \
45 R1 = StgClosure_payload(R1,offset); \
47 Sp = Sp + SIZEOF_StgHeader; \
51 INFO_TABLE_SELECTOR(stg_sel_##offset##_upd, offset, THUNK_SELECTOR, "stg_sel_upd", "stg_sel_upd") \
54 STK_CHK_NP(WITHUPD_FRAME_SIZE); \
57 PUSH_UPD_FRAME(Sp - SIZEOF_StgUpdateFrame, R1); \
58 ENTER_CCS_THUNK(R1); \
59 SAVE_CCCS(WITHUPD_FRAME_SIZE); \
60 W_[Sp-WITHUPD_FRAME_SIZE] = stg_sel_ret_##offset##_upd_info; \
61 R1 = StgThunk_payload(R1,0); \
62 Sp = Sp - WITHUPD_FRAME_SIZE; \
63 jump %GET_ENTRY(R1); \
65 /* NOTE: no need to ENTER() here, we know the closure cannot evaluate to a function,
66 because we're going to do a field selection on the result. */
85 #define SELECTOR_CODE_NOUPD(offset) \
86 INFO_TABLE_RET(stg_sel_ret_##offset##_noupd, RET_SMALL, RET_PARAMS) \
88 R1 = StgClosure_payload(R1,offset); \
90 Sp = Sp + SIZEOF_StgHeader; \
91 jump %GET_ENTRY(R1); \
94 INFO_TABLE_SELECTOR(stg_sel_##offset##_noupd, offset, THUNK_SELECTOR, "stg_sel_noupd", "stg_sel_noupd")\
97 STK_CHK_NP(NOUPD_FRAME_SIZE); \
98 UPD_BH_SINGLE_ENTRY(); \
100 TICK_UPDF_OMITTED(); \
101 ENTER_CCS_THUNK(R1); \
102 SAVE_CCCS(NOUPD_FRAME_SIZE); \
103 W_[Sp-NOUPD_FRAME_SIZE] = stg_sel_ret_##offset##_noupd_info; \
104 R1 = StgThunk_payload(R1,0); \
105 Sp = Sp - NOUPD_FRAME_SIZE; \
106 jump %GET_ENTRY(R1); \
109 SELECTOR_CODE_NOUPD(0)
110 SELECTOR_CODE_NOUPD(1)
111 SELECTOR_CODE_NOUPD(2)
112 SELECTOR_CODE_NOUPD(3)
113 SELECTOR_CODE_NOUPD(4)
114 SELECTOR_CODE_NOUPD(5)
115 SELECTOR_CODE_NOUPD(6)
116 SELECTOR_CODE_NOUPD(7)
117 SELECTOR_CODE_NOUPD(8)
118 SELECTOR_CODE_NOUPD(9)
119 SELECTOR_CODE_NOUPD(10)
120 SELECTOR_CODE_NOUPD(11)
121 SELECTOR_CODE_NOUPD(12)
122 SELECTOR_CODE_NOUPD(13)
123 SELECTOR_CODE_NOUPD(14)
124 SELECTOR_CODE_NOUPD(15)
126 /* -----------------------------------------------------------------------------
129 An apply thunk is a thunk of the form
131 let z = [x1...xn] \u x1...xn
134 We pre-compile some of these because the code is always the same.
136 These have to be independent of the update frame size, so the code
137 works when profiling etc.
138 -------------------------------------------------------------------------- */
140 /* stg_ap_1_upd_info is a bit redundant, but there appears to be a bug
141 * in the compiler that means stg_ap_1 is generated occasionally (ToDo)
144 INFO_TABLE(stg_ap_1_upd,1,1,THUNK_1_0,"stg_ap_1_upd_info","stg_ap_1_upd_info")
147 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(1));
151 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
152 R1 = StgThunk_payload(R1,0);
153 Sp = Sp - SIZEOF_StgUpdateFrame;
157 INFO_TABLE(stg_ap_2_upd,2,0,THUNK_2_0,"stg_ap_2_upd_info","stg_ap_2_upd_info")
160 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(2));
164 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
165 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,1);
166 R1 = StgThunk_payload(R1,0);
167 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(1);
168 Sp_adj(-1); // for stg_ap_*_ret
171 jump RET_LBL(stg_ap_p);
174 INFO_TABLE(stg_ap_3_upd,3,0,THUNK,"stg_ap_3_upd_info","stg_ap_3_upd_info")
177 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(3));
181 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
182 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,2);
183 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,1);
184 R1 = StgThunk_payload(R1,0);
185 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(2);
186 Sp_adj(-1); // for stg_ap_*_ret
189 jump RET_LBL(stg_ap_pp);
192 INFO_TABLE(stg_ap_4_upd,4,0,THUNK,"stg_ap_4_upd_info","stg_ap_4_upd_info")
195 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(4));
199 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
200 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,3);
201 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,2);
202 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,1);
203 R1 = StgThunk_payload(R1,0);
204 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(3);
205 Sp_adj(-1); // for stg_ap_*_ret
207 TICK_SLOW_CALL_ppp();
208 jump RET_LBL(stg_ap_ppp);
211 INFO_TABLE(stg_ap_5_upd,5,0,THUNK,"stg_ap_5_upd_info","stg_ap_5_upd_info")
214 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(5));
218 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
219 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,4);
220 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,3);
221 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,2);
222 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,1);
223 R1 = StgThunk_payload(R1,0);
224 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(4);
225 Sp_adj(-1); // for stg_ap_*_ret
227 TICK_SLOW_CALL_pppp();
228 jump RET_LBL(stg_ap_pppp);
231 INFO_TABLE(stg_ap_6_upd,6,0,THUNK,"stg_ap_6_upd_info","stg_ap_6_upd_info")
234 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(6));
238 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
239 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,5);
240 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,4);
241 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,3);
242 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,2);
243 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,1);
244 R1 = StgThunk_payload(R1,0);
245 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(5);
246 Sp_adj(-1); // for stg_ap_*_ret
248 TICK_SLOW_CALL_ppppp();
249 jump RET_LBL(stg_ap_ppppp);
252 INFO_TABLE(stg_ap_7_upd,7,0,THUNK,"stg_ap_7_upd_info","stg_ap_7_upd_info")
255 STK_CHK_NP(SIZEOF_StgUpdateFrame+WDS(7));
259 PUSH_UPD_FRAME(Sp-SIZEOF_StgUpdateFrame,R1);
260 W_[Sp-SIZEOF_StgUpdateFrame-WDS(1)] = StgThunk_payload(R1,6);
261 W_[Sp-SIZEOF_StgUpdateFrame-WDS(2)] = StgThunk_payload(R1,5);
262 W_[Sp-SIZEOF_StgUpdateFrame-WDS(3)] = StgThunk_payload(R1,4);
263 W_[Sp-SIZEOF_StgUpdateFrame-WDS(4)] = StgThunk_payload(R1,3);
264 W_[Sp-SIZEOF_StgUpdateFrame-WDS(5)] = StgThunk_payload(R1,2);
265 W_[Sp-SIZEOF_StgUpdateFrame-WDS(6)] = StgThunk_payload(R1,1);
266 R1 = StgThunk_payload(R1,0);
267 Sp = Sp - SIZEOF_StgUpdateFrame - WDS(6);
268 Sp_adj(-1); // for stg_ap_*_ret
270 TICK_SLOW_CALL_pppppp();
271 jump RET_LBL(stg_ap_pppppp);