1 /* -----------------------------------------------------------------------------
2 * $Id: StgMiscClosures.hc,v 1.11 1999/02/02 14:21:32 simonm Exp $
4 * Entry code for various built-in closure types.
6 * ---------------------------------------------------------------------------*/
10 #include "StgMiscClosures.h"
11 #include "HeapStackCheck.h" /* for stg_gen_yield */
13 #include "StoragePriv.h"
19 /* -----------------------------------------------------------------------------
20 Entry code for an indirection.
22 This code assumes R1 is in a register for now.
23 -------------------------------------------------------------------------- */
25 INFO_TABLE(IND_info,IND_entry,1,0,IND,const,EF_,0,0);
29 TICK_ENT_IND(Node); /* tick */
31 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
37 INFO_TABLE(IND_STATIC_info,IND_STATIC_entry,1,0,IND_STATIC,const,EF_,0,0);
38 STGFUN(IND_STATIC_entry)
41 TICK_ENT_IND(Node); /* tick */
43 R1.p = (P_) ((StgIndStatic*)R1.p)->indirectee;
49 INFO_TABLE(IND_PERM_info,IND_PERM_entry,1,0,IND_PERM,const,EF_,0,0);
50 STGFUN(IND_PERM_entry)
53 /* Don't add INDs to granularity cost */
55 /* Dont: ENT_IND(Node); for ticky-ticky; this ind is here only to help profi
58 /* Enter PAP cost centre -- lexical scoping only */
59 ENTER_CCS_PAP_CL(R1.cl);
61 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
63 /* Dont: TICK_ENT_VIA_NODE(); for ticky-ticky; as above */
69 INFO_TABLE(IND_OLDGEN_info,IND_OLDGEN_entry,1,1,IND_OLDGEN,const,EF_,0,0);
70 STGFUN(IND_OLDGEN_entry)
73 TICK_ENT_IND(Node); /* tick */
75 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
81 INFO_TABLE(IND_OLDGEN_PERM_info,IND_OLDGEN_PERM_entry,1,1,IND_OLDGEN_PERM,const,EF_,0,0);
82 STGFUN(IND_OLDGEN_PERM_entry)
85 TICK_ENT_IND(Node); /* tick */
87 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
93 /* -----------------------------------------------------------------------------
96 This code assumes R1 is in a register for now.
97 -------------------------------------------------------------------------- */
99 INFO_TABLE(CAF_UNENTERED_info,CAF_UNENTERED_entry,1,2,CAF_UNENTERED,const,EF_,0,0);
100 STGFUN(CAF_UNENTERED_entry)
103 /* ToDo: implement directly in GHC */
106 JMP_(stg_yield_to_Hugs);
110 INFO_TABLE(CAF_ENTERED_info,CAF_ENTERED_entry,2,1,CAF_ENTERED,const,EF_,0,0);
111 STGFUN(CAF_ENTERED_entry)
114 R1.p = (P_) ((StgCAF*)R1.p)->value; /* just a fancy indirection */
116 JMP_(GET_ENTRY(R1.cl));
120 /* -----------------------------------------------------------------------------
121 Entry code for a black hole.
123 Entering a black hole normally causes a cyclic data dependency, but
124 in the concurrent world, black holes are synchronization points,
125 and they are turned into blocking queues when there are threads
126 waiting for the evaluation of the closure to finish.
127 -------------------------------------------------------------------------- */
129 /* Note: a black hole must be big enough to be overwritten with an
130 * indirection/evacuee/catch. Thus we claim it has 1 non-pointer word of
131 * payload (in addition to the pointer word for the blocking queue), which
132 * should be big enough for an old-generation indirection.
135 INFO_TABLE(BLACKHOLE_info, BLACKHOLE_entry,0,2,BLACKHOLE,const,EF_,0,0);
136 STGFUN(BLACKHOLE_entry)
141 /* Change the BLACKHOLE into a BLACKHOLE_BQ */
142 ((StgBlockingQueue *)R1.p)->header.info = &BLACKHOLE_BQ_info;
143 /* Put ourselves on the blocking queue for this black hole */
144 CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure;
145 ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
146 recordMutable((StgMutClosure *)R1.cl);
148 /* stg_gen_block is too heavyweight, use a specialised one */
153 INFO_TABLE(BLACKHOLE_BQ_info, BLACKHOLE_BQ_entry,1,1,BLACKHOLE_BQ,const,EF_,0,0);
154 STGFUN(BLACKHOLE_BQ_entry)
159 /* Put ourselves on the blocking queue for this black hole */
160 CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
161 ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
163 /* stg_gen_block is too heavyweight, use a specialised one */
168 /* identical to BLACKHOLEs except for the infotag */
169 INFO_TABLE(CAF_BLACKHOLE_info, CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,const,EF_,0,0);
170 STGFUN(CAF_BLACKHOLE_entry)
175 /* Change the BLACKHOLE into a BLACKHOLE_BQ */
176 ((StgBlockingQueue *)R1.p)->header.info = &BLACKHOLE_BQ_info;
177 /* Put ourselves on the blocking queue for this black hole */
178 CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure;
179 ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
180 recordMutable((StgMutClosure *)R1.cl);
182 /* stg_gen_block is too heavyweight, use a specialised one */
187 /* -----------------------------------------------------------------------------
188 The code for a BCO returns to the scheduler
189 -------------------------------------------------------------------------- */
190 INFO_TABLE(BCO_info,BCO_entry,0,0,BCO,const,EF_,0,0);
195 JMP_(stg_yield_to_Hugs);
199 /* -----------------------------------------------------------------------------
200 Some static info tables for things that don't get entered, and
201 therefore don't need entry code (i.e. boxed but unpointed objects)
202 -------------------------------------------------------------------------- */
204 #define NON_ENTERABLE_ENTRY_CODE(type) \
205 STGFUN(type##_entry) \
208 STGCALL1(fflush,stdout); \
209 STGCALL2(fprintf,stderr,#type " object entered!\n"); \
210 STGCALL1(raiseError, errorHandler); \
211 stg_exit(EXIT_FAILURE); /* not executed */ \
215 INFO_TABLE(TSO_info, TSO_entry, 0,0,TSO,const,EF_,0,0);
216 NON_ENTERABLE_ENTRY_CODE(TSO);
218 /* -----------------------------------------------------------------------------
219 Evacuees are left behind by the garbage collector. Any attempt to enter
221 -------------------------------------------------------------------------- */
223 INFO_TABLE(EVACUATED_info,EVACUATED_entry,1,0,EVACUATED,const,EF_,0,0);
224 NON_ENTERABLE_ENTRY_CODE(EVACUATED);
226 /* -----------------------------------------------------------------------------
229 Live weak pointers have a special closure type. Dead ones are just
230 nullary constructors (although they live on the heap - we overwrite
231 live weak pointers with dead ones).
232 -------------------------------------------------------------------------- */
234 INFO_TABLE(WEAK_info,WEAK_entry,0,4,WEAK,const,EF_,0,0);
235 NON_ENTERABLE_ENTRY_CODE(WEAK);
237 INFO_TABLE_CONSTR(DEAD_WEAK_info,DEAD_WEAK_entry,0,1,0,CONSTR,const,EF_,0,0);
238 NON_ENTERABLE_ENTRY_CODE(DEAD_WEAK);
240 /* -----------------------------------------------------------------------------
243 This is a static nullary constructor (like []) that we use to mark an empty
244 finaliser in a weak pointer object.
245 -------------------------------------------------------------------------- */
247 INFO_TABLE_CONSTR(NO_FINALISER_info,NO_FINALISER_entry,0,0,0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
248 NON_ENTERABLE_ENTRY_CODE(NO_FINALISER);
250 SET_STATIC_HDR(NO_FINALISER_closure,NO_FINALISER_info,0/*CC*/,,EI_)
253 /* -----------------------------------------------------------------------------
254 Foreign Objects are unlifted and therefore never entered.
255 -------------------------------------------------------------------------- */
257 INFO_TABLE(FOREIGN_info,FOREIGN_entry,0,1,FOREIGN,const,EF_,0,0);
258 NON_ENTERABLE_ENTRY_CODE(FOREIGN);
260 /* -----------------------------------------------------------------------------
261 Stable Names are unlifted too.
262 -------------------------------------------------------------------------- */
264 INFO_TABLE(STABLE_NAME_info,STABLE_NAME_entry,0,1,STABLE_NAME,const,EF_,0,0);
265 NON_ENTERABLE_ENTRY_CODE(STABLE_NAME);
267 /* -----------------------------------------------------------------------------
270 There are two kinds of these: full and empty. We need an info table
271 and entry code for each type.
272 -------------------------------------------------------------------------- */
274 INFO_TABLE(FULL_MVAR_info,FULL_MVAR_entry,4,0,MVAR,const,EF_,0,0);
275 NON_ENTERABLE_ENTRY_CODE(FULL_MVAR);
277 INFO_TABLE(EMPTY_MVAR_info,EMPTY_MVAR_entry,4,0,MVAR,const,EF_,0,0);
278 NON_ENTERABLE_ENTRY_CODE(EMPTY_MVAR);
280 /* -----------------------------------------------------------------------------
283 This is a static nullary constructor (like []) that we use to mark the
284 end of a linked TSO queue.
285 -------------------------------------------------------------------------- */
287 INFO_TABLE_CONSTR(END_TSO_QUEUE_info,END_TSO_QUEUE_entry,0,0,0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
288 NON_ENTERABLE_ENTRY_CODE(END_TSO_QUEUE);
290 SET_STATIC_HDR(END_TSO_QUEUE_closure,END_TSO_QUEUE_info,0/*CC*/,,EI_)
293 /* -----------------------------------------------------------------------------
296 Mutable lists (used by the garbage collector) consist of a chain of
297 StgMutClosures connected through their mut_link fields, ending in
298 an END_MUT_LIST closure.
299 -------------------------------------------------------------------------- */
301 INFO_TABLE_CONSTR(END_MUT_LIST_info,END_MUT_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
302 NON_ENTERABLE_ENTRY_CODE(END_MUT_LIST);
304 SET_STATIC_HDR(END_MUT_LIST_closure,END_MUT_LIST_info,0/*CC*/,,EI_)
307 INFO_TABLE(MUT_CONS_info, MUT_CONS_entry, 1, 1, MUT_VAR, const, EF_, 0, 0);
308 NON_ENTERABLE_ENTRY_CODE(MUT_CONS);
310 /* -----------------------------------------------------------------------------
313 These come in two basic flavours: arrays of data (StgArrWords) and arrays of
314 pointers (StgArrPtrs). They all have a similar layout:
316 ___________________________
317 | Info | No. of | data....
319 ---------------------------
321 These are *unpointed* objects: i.e. they cannot be entered.
323 -------------------------------------------------------------------------- */
325 #define ArrayInfo(type) \
326 INFO_TABLE(type##_info, type##_entry, 0, 0, type, const, EF_,0,0); \
327 NON_ENTERABLE_ENTRY_CODE(type);
329 ArrayInfo(ARR_WORDS);
330 ArrayInfo(MUT_ARR_WORDS);
331 ArrayInfo(MUT_ARR_PTRS);
332 ArrayInfo(MUT_ARR_PTRS_FROZEN);
336 /* -----------------------------------------------------------------------------
338 -------------------------------------------------------------------------- */
340 INFO_TABLE(MUT_VAR_info, MUT_VAR_entry, 1, 1, MUT_VAR, const, EF_, 0, 0);
341 NON_ENTERABLE_ENTRY_CODE(MUT_VAR);
343 /* -----------------------------------------------------------------------------
344 Standard Error Entry.
346 This is used for filling in vector-table entries that can never happen,
348 -------------------------------------------------------------------------- */
350 STGFUN(stg_error_entry) \
353 STGCALL1(fflush,stdout); \
354 STGCALL2(fprintf,stderr,"fatal: stg_error_entry"); \
355 STGCALL1(raiseError, errorHandler); \
356 exit(EXIT_FAILURE); /* not executed */ \
360 /* -----------------------------------------------------------------------------
363 Entering this closure will just return to the address on the top of the
364 stack. Useful for getting a thread in a canonical form where we can
365 just enter the top stack word to start the thread. (see deleteThread)
366 * -------------------------------------------------------------------------- */
368 INFO_TABLE(dummy_ret_info, dummy_ret_entry, 0, 0, CONSTR_NOCAF_STATIC, const, EF_, 0, 0);
375 JMP_(ENTRY_CODE(ret_addr));
378 SET_STATIC_HDR(dummy_ret_closure,dummy_ret_info,CCS_DONTZuCARE,,EI_)
381 /* -----------------------------------------------------------------------------
382 Standard Infotables (for use in interpreter)
383 -------------------------------------------------------------------------- */
387 STGFUN(Hugs_CONSTR_entry)
390 ((StgPtr*)Sp)[0] = R1.p;
391 /* vectored: JMP_(RET_VEC(((StgPtr*)Sp)[1],constrTag(?))); */
392 JMP_(ENTRY_CODE(((StgPtr*)Sp)[1]));
395 #define RET_BCO_ENTRY_TEMPLATE(label) \
400 ((StgPtr*)Sp)[0] = R1.p; \
401 JMP_(stg_yield_to_Hugs); \
405 RET_BCO_ENTRY_TEMPLATE(ret_bco_entry );
406 RET_BCO_ENTRY_TEMPLATE(ret_bco_0_entry);
407 RET_BCO_ENTRY_TEMPLATE(ret_bco_1_entry);
408 RET_BCO_ENTRY_TEMPLATE(ret_bco_2_entry);
409 RET_BCO_ENTRY_TEMPLATE(ret_bco_3_entry);
410 RET_BCO_ENTRY_TEMPLATE(ret_bco_4_entry);
411 RET_BCO_ENTRY_TEMPLATE(ret_bco_5_entry);
412 RET_BCO_ENTRY_TEMPLATE(ret_bco_6_entry);
413 RET_BCO_ENTRY_TEMPLATE(ret_bco_7_entry);
415 VEC_POLY_INFO_TABLE(ret_bco,0, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, RET_BCO);
417 #endif /* INTERPRETER */
421 INFO_TABLE_CONSTR(Czh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgChar),0,CONSTR,const,EF_,0,0);
422 INFO_TABLE_CONSTR(Izh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgInt),0,CONSTR,const,EF_,0,0);
423 INFO_TABLE_CONSTR(I64zh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgInt64),0,CONSTR,const,EF_,0,0);
424 INFO_TABLE_CONSTR(Fzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgFloat),0,CONSTR,const,EF_,0,0);
425 INFO_TABLE_CONSTR(Dzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgDouble),0,CONSTR,const,EF_,0,0);
426 INFO_TABLE_CONSTR(Azh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgAddr),0,CONSTR,const,EF_,0,0);
427 INFO_TABLE_CONSTR(Wzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgWord),0,CONSTR,const,EF_,0,0);
428 INFO_TABLE_CONSTR(StablePtr_con_info,Hugs_CONSTR_entry,0,sizeofW(StgStablePtr),0,CONSTR,const,EF_,0,0);
430 /* These might seem redundant but {I,C}zh_static_info are used in
431 * {INT,CHAR}LIKE and the rest are used in RtsAPI.c
433 INFO_TABLE_CONSTR(Czh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgChar),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
434 INFO_TABLE_CONSTR(Izh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgInt),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
435 INFO_TABLE_CONSTR(I64zh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgInt64),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
436 INFO_TABLE_CONSTR(Fzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgFloat),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
437 INFO_TABLE_CONSTR(Dzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgDouble),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
438 INFO_TABLE_CONSTR(Azh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgAddr),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
439 INFO_TABLE_CONSTR(Wzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgWord),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
440 INFO_TABLE_CONSTR(StablePtr_static_info,Hugs_CONSTR_entry,0,sizeofW(StgStablePtr),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
442 #endif /* !defined(COMPILER) */
444 /* -----------------------------------------------------------------------------
445 CHARLIKE and INTLIKE closures.
447 These are static representations of Chars and small Ints, so that
448 we can remove dynamic Chars and Ints during garbage collection and
449 replace them with references to the static objects.
450 -------------------------------------------------------------------------- */
452 #define CHARLIKE_HDR(n) \
454 STATIC_HDR(Czh_static_info, /* C# */ \
459 #define INTLIKE_HDR(n) \
461 STATIC_HDR(Izh_static_info, /* I# */ \
466 /* put these in the *data* section, since the garbage collector relies
467 * on the fact that static closures live in the data section.
470 /* end the name with _closure, to convince the mangler this is a closure */
472 StgIntCharlikeClosure CHARLIKE_closure[] = {
731 StgIntCharlikeClosure INTLIKE_closure[] = {
732 INTLIKE_HDR(-16), /* MIN_INTLIKE == -16 */
764 INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */