1 /* -----------------------------------------------------------------------------
2 * $Id: StgMiscClosures.hc,v 1.12 1999/02/05 15:25:09 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_PTRS);
331 ArrayInfo(MUT_ARR_PTRS_FROZEN);
335 /* -----------------------------------------------------------------------------
337 -------------------------------------------------------------------------- */
339 INFO_TABLE(MUT_VAR_info, MUT_VAR_entry, 1, 1, MUT_VAR, const, EF_, 0, 0);
340 NON_ENTERABLE_ENTRY_CODE(MUT_VAR);
342 /* -----------------------------------------------------------------------------
343 Standard Error Entry.
345 This is used for filling in vector-table entries that can never happen,
347 -------------------------------------------------------------------------- */
349 STGFUN(stg_error_entry) \
352 STGCALL1(fflush,stdout); \
353 STGCALL2(fprintf,stderr,"fatal: stg_error_entry"); \
354 STGCALL1(raiseError, errorHandler); \
355 exit(EXIT_FAILURE); /* not executed */ \
359 /* -----------------------------------------------------------------------------
362 Entering this closure will just return to the address on the top of the
363 stack. Useful for getting a thread in a canonical form where we can
364 just enter the top stack word to start the thread. (see deleteThread)
365 * -------------------------------------------------------------------------- */
367 INFO_TABLE(dummy_ret_info, dummy_ret_entry, 0, 0, CONSTR_NOCAF_STATIC, const, EF_, 0, 0);
374 JMP_(ENTRY_CODE(ret_addr));
377 SET_STATIC_HDR(dummy_ret_closure,dummy_ret_info,CCS_DONTZuCARE,,EI_)
380 /* -----------------------------------------------------------------------------
381 Standard Infotables (for use in interpreter)
382 -------------------------------------------------------------------------- */
386 STGFUN(Hugs_CONSTR_entry)
389 ((StgPtr*)Sp)[0] = R1.p;
390 /* vectored: JMP_(RET_VEC(((StgPtr*)Sp)[1],constrTag(?))); */
391 JMP_(ENTRY_CODE(((StgPtr*)Sp)[1]));
394 #define RET_BCO_ENTRY_TEMPLATE(label) \
399 ((StgPtr*)Sp)[0] = R1.p; \
400 JMP_(stg_yield_to_Hugs); \
404 RET_BCO_ENTRY_TEMPLATE(ret_bco_entry );
405 RET_BCO_ENTRY_TEMPLATE(ret_bco_0_entry);
406 RET_BCO_ENTRY_TEMPLATE(ret_bco_1_entry);
407 RET_BCO_ENTRY_TEMPLATE(ret_bco_2_entry);
408 RET_BCO_ENTRY_TEMPLATE(ret_bco_3_entry);
409 RET_BCO_ENTRY_TEMPLATE(ret_bco_4_entry);
410 RET_BCO_ENTRY_TEMPLATE(ret_bco_5_entry);
411 RET_BCO_ENTRY_TEMPLATE(ret_bco_6_entry);
412 RET_BCO_ENTRY_TEMPLATE(ret_bco_7_entry);
414 VEC_POLY_INFO_TABLE(ret_bco,0, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, RET_BCO);
416 #endif /* INTERPRETER */
420 INFO_TABLE_CONSTR(Czh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgChar),0,CONSTR,const,EF_,0,0);
421 INFO_TABLE_CONSTR(Izh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgInt),0,CONSTR,const,EF_,0,0);
422 INFO_TABLE_CONSTR(I64zh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgInt64),0,CONSTR,const,EF_,0,0);
423 INFO_TABLE_CONSTR(Fzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgFloat),0,CONSTR,const,EF_,0,0);
424 INFO_TABLE_CONSTR(Dzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgDouble),0,CONSTR,const,EF_,0,0);
425 INFO_TABLE_CONSTR(Azh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgAddr),0,CONSTR,const,EF_,0,0);
426 INFO_TABLE_CONSTR(Wzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgWord),0,CONSTR,const,EF_,0,0);
427 INFO_TABLE_CONSTR(StablePtr_con_info,Hugs_CONSTR_entry,0,sizeofW(StgStablePtr),0,CONSTR,const,EF_,0,0);
429 /* These might seem redundant but {I,C}zh_static_info are used in
430 * {INT,CHAR}LIKE and the rest are used in RtsAPI.c
432 INFO_TABLE_CONSTR(Czh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgChar),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
433 INFO_TABLE_CONSTR(Izh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgInt),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
434 INFO_TABLE_CONSTR(I64zh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgInt64),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
435 INFO_TABLE_CONSTR(Fzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgFloat),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
436 INFO_TABLE_CONSTR(Dzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgDouble),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
437 INFO_TABLE_CONSTR(Azh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgAddr),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
438 INFO_TABLE_CONSTR(Wzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgWord),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
439 INFO_TABLE_CONSTR(StablePtr_static_info,Hugs_CONSTR_entry,0,sizeofW(StgStablePtr),0,CONSTR_NOCAF_STATIC,const,EF_,0,0);
441 #endif /* !defined(COMPILER) */
443 /* -----------------------------------------------------------------------------
444 CHARLIKE and INTLIKE closures.
446 These are static representations of Chars and small Ints, so that
447 we can remove dynamic Chars and Ints during garbage collection and
448 replace them with references to the static objects.
449 -------------------------------------------------------------------------- */
451 #define CHARLIKE_HDR(n) \
453 STATIC_HDR(Czh_static_info, /* C# */ \
458 #define INTLIKE_HDR(n) \
460 STATIC_HDR(Izh_static_info, /* I# */ \
465 /* put these in the *data* section, since the garbage collector relies
466 * on the fact that static closures live in the data section.
469 /* end the name with _closure, to convince the mangler this is a closure */
471 StgIntCharlikeClosure CHARLIKE_closure[] = {
730 StgIntCharlikeClosure INTLIKE_closure[] = {
731 INTLIKE_HDR(-16), /* MIN_INTLIKE == -16 */
763 INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */