1 /* ----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2004
5 * Entry code for various built-in closure types.
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 import pthread_mutex_lock;
16 import base_GHCziBase_Czh_static_info;
17 import base_GHCziBase_Izh_static_info;
19 /* ----------------------------------------------------------------------------
20 Support for the bytecode interpreter.
21 ------------------------------------------------------------------------- */
23 /* 9 bits of return code for constructors created by the interpreter. */
24 stg_interp_constr_entry
26 /* R1 points at the constructor */
27 jump %ENTRY_CODE(Sp(0));
30 /* Some info tables to be used when compiled code returns a value to
31 the interpreter, i.e. the interpreter pushes one of these onto the
32 stack before entering a value. What the code does is to
33 impedance-match the compiled return convention (in R1p/R1n/F1/D1 etc) to
34 the interpreter's convention (returned value is on top of stack),
35 and then cause the scheduler to enter the interpreter.
37 On entry, the stack (growing down) looks like this:
39 ptr to BCO holding return continuation
40 ptr to one of these info tables.
42 The info table code, both direct and vectored, must:
43 * push R1/F1/D1 on the stack, and its tag if necessary
44 * push the BCO (so it's now on the stack twice)
45 * Yield, ie, go to the scheduler.
47 Scheduler examines the t.o.s, discovers it is a BCO, and proceeds
48 directly to the bytecode interpreter. That pops the top element
49 (the BCO, containing the return continuation), and interprets it.
50 Net result: return continuation gets interpreted, with the
54 ptr to the info table just jumped thru
57 which is just what we want -- the "standard" return layout for the
60 Don't ask me how unboxed tuple returns are supposed to work. We
61 haven't got a good story about that yet.
64 INFO_TABLE_RET( stg_ctoi_R1p, RET_BCO)
68 Sp(0) = stg_enter_info;
69 jump stg_yield_to_interpreter;
73 * When the returned value is a pointer, but unlifted, in R1 ...
75 INFO_TABLE_RET( stg_ctoi_R1unpt, RET_BCO )
79 Sp(0) = stg_gc_unpt_r1_info;
80 jump stg_yield_to_interpreter;
84 * When the returned value is a non-pointer in R1 ...
86 INFO_TABLE_RET( stg_ctoi_R1n, RET_BCO )
90 Sp(0) = stg_gc_unbx_r1_info;
91 jump stg_yield_to_interpreter;
95 * When the returned value is in F1
97 INFO_TABLE_RET( stg_ctoi_F1, RET_BCO )
100 F_[Sp + WDS(1)] = F1;
101 Sp(0) = stg_gc_f1_info;
102 jump stg_yield_to_interpreter;
106 * When the returned value is in D1
108 INFO_TABLE_RET( stg_ctoi_D1, RET_BCO )
110 Sp_adj(-1) - SIZEOF_DOUBLE;
111 D_[Sp + WDS(1)] = D1;
112 Sp(0) = stg_gc_d1_info;
113 jump stg_yield_to_interpreter;
117 * When the returned value is in L1
119 INFO_TABLE_RET( stg_ctoi_L1, RET_BCO )
122 L_[Sp + WDS(1)] = L1;
123 Sp(0) = stg_gc_l1_info;
124 jump stg_yield_to_interpreter;
128 * When the returned value is a void
130 INFO_TABLE_RET( stg_ctoi_V, RET_BCO )
133 Sp(0) = stg_gc_void_info;
134 jump stg_yield_to_interpreter;
138 * Dummy info table pushed on the top of the stack when the interpreter
139 * should apply the BCO on the stack to its arguments, also on the
142 INFO_TABLE_RET( stg_apply_interp, RET_BCO )
144 /* Just in case we end up in here... (we shouldn't) */
145 jump stg_yield_to_interpreter;
148 /* ----------------------------------------------------------------------------
150 ------------------------------------------------------------------------- */
152 INFO_TABLE_FUN( stg_BCO, 4, 0, BCO, "BCO", "BCO", ARG_BCO )
154 /* entering a BCO means "apply it", same as a function */
157 Sp(0) = stg_apply_interp_info;
158 jump stg_yield_to_interpreter;
161 /* ----------------------------------------------------------------------------
162 Info tables for indirections.
164 SPECIALISED INDIRECTIONS: we have a specialised indirection for direct returns,
165 so that we can avoid entering
166 the object when we know it points directly to a value. The update
167 code (Updates.cmm) updates objects with the appropriate kind of
168 indirection. We only do this for young-gen indirections.
169 ------------------------------------------------------------------------- */
171 INFO_TABLE(stg_IND,1,0,IND,"IND","IND")
173 TICK_ENT_DYN_IND(); /* tick */
174 R1 = UNTAG(StgInd_indirectee(R1));
179 INFO_TABLE(stg_IND_direct,1,0,IND,"IND","IND")
181 TICK_ENT_DYN_IND(); /* tick */
182 R1 = StgInd_indirectee(R1);
184 jump %ENTRY_CODE(Sp(0));
187 INFO_TABLE(stg_IND_STATIC,1,0,IND_STATIC,"IND_STATIC","IND_STATIC")
189 TICK_ENT_STATIC_IND(); /* tick */
190 R1 = UNTAG(StgInd_indirectee(R1));
195 INFO_TABLE(stg_IND_PERM,1,0,IND_PERM,"IND_PERM","IND_PERM")
197 /* Don't add INDs to granularity cost */
199 /* Don't: TICK_ENT_STATIC_IND(Node); for ticky-ticky; this ind is
200 here only to help profiling */
202 #if defined(TICKY_TICKY) && !defined(PROFILING)
203 /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than
210 /* Enter PAP cost centre */
211 ENTER_CCS_PAP_CL(R1);
213 /* For ticky-ticky, change the perm_ind to a normal ind on first
214 * entry, so the number of ent_perm_inds is the number of *thunks*
215 * entered again, not the number of subsequent entries.
217 * Since this screws up cost centres, we die if profiling and
218 * ticky_ticky are on at the same time. KSW 1999-01.
222 # error Profiling and ticky-ticky do not mix at present!
223 # endif /* PROFILING */
224 StgHeader_info(R1) = stg_IND_info;
225 #endif /* TICKY_TICKY */
227 R1 = UNTAG(StgInd_indirectee(R1));
229 #if defined(TICKY_TICKY) && !defined(PROFILING)
237 INFO_TABLE(stg_IND_OLDGEN,1,0,IND_OLDGEN,"IND_OLDGEN","IND_OLDGEN")
239 TICK_ENT_STATIC_IND(); /* tick */
240 R1 = UNTAG(StgInd_indirectee(R1));
245 INFO_TABLE(stg_IND_OLDGEN_PERM,1,0,IND_OLDGEN_PERM,"IND_OLDGEN_PERM","IND_OLDGEN_PERM")
247 /* Don't: TICK_ENT_STATIC_IND(Node); for ticky-ticky;
248 this ind is here only to help profiling */
250 #if defined(TICKY_TICKY) && !defined(PROFILING)
251 /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND,
252 rather than being extra */
253 TICK_ENT_PERM_IND(); /* tick */
258 /* Enter PAP cost centre -- lexical scoping only */
259 ENTER_CCS_PAP_CL(R1);
261 /* see comment in IND_PERM */
264 # error Profiling and ticky-ticky do not mix at present!
265 # endif /* PROFILING */
266 StgHeader_info(R1) = stg_IND_OLDGEN_info;
267 #endif /* TICKY_TICKY */
269 R1 = UNTAG(StgInd_indirectee(R1));
275 /* ----------------------------------------------------------------------------
278 Entering a black hole normally causes a cyclic data dependency, but
279 in the concurrent world, black holes are synchronization points,
280 and they are turned into blocking queues when there are threads
281 waiting for the evaluation of the closure to finish.
282 ------------------------------------------------------------------------- */
284 /* Note: a BLACKHOLE must be big enough to be
285 * overwritten with an indirection/evacuee/catch. Thus we claim it
286 * has 1 non-pointer word of payload.
288 INFO_TABLE(stg_BLACKHOLE,0,1,BLACKHOLE,"BLACKHOLE","BLACKHOLE")
291 /* Before overwriting TSO_LINK */
292 STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
298 // foreign "C" debugBelch("BLACKHOLE entry\n");
301 /* Actually this is not necessary because R1 is about to be destroyed. */
304 #if defined(THREADED_RTS)
305 foreign "C" ACQUIRE_LOCK(sched_mutex "ptr");
306 // released in stg_block_blackhole_finally
309 /* Put ourselves on the blackhole queue */
310 StgTSO_link(CurrentTSO) = W_[blackhole_queue];
311 W_[blackhole_queue] = CurrentTSO;
313 /* jot down why and on what closure we are blocked */
314 StgTSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
315 StgTSO_block_info(CurrentTSO) = R1;
317 jump stg_block_blackhole;
320 #if defined(PAR) || defined(GRAN)
322 INFO_TABLE(stg_RBH,1,1,RBH,"RBH","RBH")
325 /* mainly statistics gathering for GranSim simulation */
326 STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
329 /* exactly the same as a BLACKHOLE_BQ_entry -- HWL */
330 /* Put ourselves on the blocking queue for this black hole */
331 TSO_link(CurrentTSO) = StgBlockingQueue_blocking_queue(R1);
332 StgBlockingQueue_blocking_queue(R1) = CurrentTSO;
333 /* jot down why and on what closure we are blocked */
334 TSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
335 TSO_block_info(CurrentTSO) = R1;
337 /* PAR: dumping of event now done in blockThread -- HWL */
339 /* stg_gen_block is too heavyweight, use a specialised one */
343 INFO_TABLE(stg_RBH_Save_0,0,2,CONSTR,"RBH_Save_0","RBH_Save_0")
344 { foreign "C" barf("RBH_Save_0 object entered!"); }
346 INFO_TABLE(stg_RBH_Save_1,1,1,CONSTR,"RBH_Save_1","RBH_Save_1");
347 { foreign "C" barf("RBH_Save_1 object entered!"); }
349 INFO_TABLE(stg_RBH_Save_2,2,0,CONSTR,"RBH_Save_2","RBH_Save_2");
350 { foreign "C" barf("RBH_Save_2 object entered!"); }
352 #endif /* defined(PAR) || defined(GRAN) */
354 /* identical to BLACKHOLEs except for the infotag */
355 INFO_TABLE(stg_CAF_BLACKHOLE,0,1,CAF_BLACKHOLE,"CAF_BLACKHOLE","CAF_BLACKHOLE")
358 /* mainly statistics gathering for GranSim simulation */
359 STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1 /*Node*/);
365 #if defined(THREADED_RTS)
366 // foreign "C" debugBelch("BLACKHOLE entry\n");
369 #if defined(THREADED_RTS)
370 foreign "C" ACQUIRE_LOCK(sched_mutex "ptr");
371 // released in stg_block_blackhole_finally
374 /* Put ourselves on the blackhole queue */
375 StgTSO_link(CurrentTSO) = W_[blackhole_queue];
376 W_[blackhole_queue] = CurrentTSO;
378 /* jot down why and on what closure we are blocked */
379 StgTSO_why_blocked(CurrentTSO) = BlockedOnBlackHole::I16;
380 StgTSO_block_info(CurrentTSO) = R1;
382 jump stg_block_blackhole;
385 #ifdef EAGER_BLACKHOLING
386 INFO_TABLE(stg_SE_BLACKHOLE,0,1,SE_BLACKHOLE,"SE_BLACKHOLE","SE_BLACKHOLE")
387 { foreign "C" barf("SE_BLACKHOLE object entered!"); }
389 INFO_TABLE(stg_SE_CAF_BLACKHOLE,0,1,SE_CAF_BLACKHOLE,"SE_CAF_BLACKHOLE","SE_CAF_BLACKHOLE")
390 { foreign "C" barf("SE_CAF_BLACKHOLE object entered!"); }
393 /* ----------------------------------------------------------------------------
394 Whiteholes are used for the "locked" state of a closure (see lockClosure())
396 The closure type is BLAKCHOLE, just because we need a valid closure type
398 ------------------------------------------------------------------------- */
400 INFO_TABLE(stg_WHITEHOLE, 0,0, BLACKHOLE, "WHITEHOLE", "WHITEHOLE")
401 { foreign "C" barf("WHITEHOLE object entered!"); }
403 /* ----------------------------------------------------------------------------
404 Some static info tables for things that don't get entered, and
405 therefore don't need entry code (i.e. boxed but unpointed objects)
406 NON_ENTERABLE_ENTRY_CODE now defined at the beginning of the file
407 ------------------------------------------------------------------------- */
409 INFO_TABLE(stg_TSO, 0,0,TSO, "TSO", "TSO")
410 { foreign "C" barf("TSO object entered!"); }
412 /* ----------------------------------------------------------------------------
413 Evacuees are left behind by the garbage collector. Any attempt to enter
415 ------------------------------------------------------------------------- */
417 INFO_TABLE(stg_EVACUATED,1,0,EVACUATED,"EVACUATED","EVACUATED")
418 { foreign "C" barf("EVACUATED object entered!"); }
420 /* ----------------------------------------------------------------------------
423 Live weak pointers have a special closure type. Dead ones are just
424 nullary constructors (although they live on the heap - we overwrite
425 live weak pointers with dead ones).
426 ------------------------------------------------------------------------- */
428 INFO_TABLE(stg_WEAK,0,4,WEAK,"WEAK","WEAK")
429 { foreign "C" barf("WEAK object entered!"); }
432 * It's important when turning an existing WEAK into a DEAD_WEAK
433 * (which is what finalizeWeak# does) that we don't lose the link
434 * field and break the linked list of weak pointers. Hence, we give
435 * DEAD_WEAK 4 non-pointer fields, the same as WEAK.
437 INFO_TABLE_CONSTR(stg_DEAD_WEAK,0,4,0,CONSTR,"DEAD_WEAK","DEAD_WEAK")
438 { foreign "C" barf("DEAD_WEAK object entered!"); }
440 /* ----------------------------------------------------------------------------
443 This is a static nullary constructor (like []) that we use to mark an empty
444 finalizer in a weak pointer object.
445 ------------------------------------------------------------------------- */
447 INFO_TABLE_CONSTR(stg_NO_FINALIZER,0,0,0,CONSTR_NOCAF_STATIC,"NO_FINALIZER","NO_FINALIZER")
448 { foreign "C" barf("NO_FINALIZER object entered!"); }
450 CLOSURE(stg_NO_FINALIZER_closure,stg_NO_FINALIZER);
452 /* ----------------------------------------------------------------------------
453 Stable Names are unlifted too.
454 ------------------------------------------------------------------------- */
456 INFO_TABLE(stg_STABLE_NAME,0,1,STABLE_NAME,"STABLE_NAME","STABLE_NAME")
457 { foreign "C" barf("STABLE_NAME object entered!"); }
459 /* ----------------------------------------------------------------------------
462 There are two kinds of these: full and empty. We need an info table
463 and entry code for each type.
464 ------------------------------------------------------------------------- */
466 INFO_TABLE(stg_FULL_MVAR,3,0,MVAR,"MVAR","MVAR")
467 { foreign "C" barf("FULL_MVAR object entered!"); }
469 INFO_TABLE(stg_EMPTY_MVAR,3,0,MVAR,"MVAR","MVAR")
470 { foreign "C" barf("EMPTY_MVAR object entered!"); }
472 /* -----------------------------------------------------------------------------
474 -------------------------------------------------------------------------- */
476 INFO_TABLE(stg_TVAR, 0, 0, TVAR, "TVAR", "TVAR")
477 { foreign "C" barf("TVAR object entered!"); }
479 INFO_TABLE(stg_TVAR_WATCH_QUEUE, 0, 0, TVAR_WATCH_QUEUE, "TVAR_WATCH_QUEUE", "TVAR_WATCH_QUEUE")
480 { foreign "C" barf("TVAR_WATCH_QUEUE object entered!"); }
482 INFO_TABLE(stg_ATOMIC_INVARIANT, 0, 0, ATOMIC_INVARIANT, "ATOMIC_INVARIANT", "ATOMIC_INVARIANT")
483 { foreign "C" barf("ATOMIC_INVARIANT object entered!"); }
485 INFO_TABLE(stg_INVARIANT_CHECK_QUEUE, 0, 0, INVARIANT_CHECK_QUEUE, "INVARIANT_CHECK_QUEUE", "INVARIANT_CHECK_QUEUE")
486 { foreign "C" barf("INVARIANT_CHECK_QUEUE object entered!"); }
488 INFO_TABLE(stg_TREC_CHUNK, 0, 0, TREC_CHUNK, "TREC_CHUNK", "TREC_CHUNK")
489 { foreign "C" barf("TREC_CHUNK object entered!"); }
491 INFO_TABLE(stg_TREC_HEADER, 0, 0, TREC_HEADER, "TREC_HEADER", "TREC_HEADER")
492 { foreign "C" barf("TREC_HEADER object entered!"); }
494 INFO_TABLE_CONSTR(stg_END_STM_WATCH_QUEUE,0,0,0,CONSTR_NOCAF_STATIC,"END_STM_WATCH_QUEUE","END_STM_WATCH_QUEUE")
495 { foreign "C" barf("END_STM_WATCH_QUEUE object entered!"); }
497 INFO_TABLE_CONSTR(stg_END_INVARIANT_CHECK_QUEUE,0,0,0,CONSTR_NOCAF_STATIC,"END_INVARIANT_CHECK_QUEUE","END_INVARIANT_CHECK_QUEUE")
498 { foreign "C" barf("END_INVARIANT_CHECK_QUEUE object entered!"); }
500 INFO_TABLE_CONSTR(stg_END_STM_CHUNK_LIST,0,0,0,CONSTR_NOCAF_STATIC,"END_STM_CHUNK_LIST","END_STM_CHUNK_LIST")
501 { foreign "C" barf("END_STM_CHUNK_LIST object entered!"); }
503 INFO_TABLE_CONSTR(stg_NO_TREC,0,0,0,CONSTR_NOCAF_STATIC,"NO_TREC","NO_TREC")
504 { foreign "C" barf("NO_TREC object entered!"); }
506 CLOSURE(stg_END_STM_WATCH_QUEUE_closure,stg_END_STM_WATCH_QUEUE);
508 CLOSURE(stg_END_INVARIANT_CHECK_QUEUE_closure,stg_END_INVARIANT_CHECK_QUEUE);
510 CLOSURE(stg_END_STM_CHUNK_LIST_closure,stg_END_STM_CHUNK_LIST);
512 CLOSURE(stg_NO_TREC_closure,stg_NO_TREC);
514 /* ----------------------------------------------------------------------------
517 This is a static nullary constructor (like []) that we use to mark the
518 end of a linked TSO queue.
519 ------------------------------------------------------------------------- */
521 INFO_TABLE_CONSTR(stg_END_TSO_QUEUE,0,0,0,CONSTR_NOCAF_STATIC,"END_TSO_QUEUE","END_TSO_QUEUE")
522 { foreign "C" barf("END_TSO_QUEUE object entered!"); }
524 CLOSURE(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE);
526 /* ----------------------------------------------------------------------------
528 ------------------------------------------------------------------------- */
530 INFO_TABLE_CONSTR(stg_END_EXCEPTION_LIST,0,0,0,CONSTR_NOCAF_STATIC,"END_EXCEPTION_LIST","END_EXCEPTION_LIST")
531 { foreign "C" barf("END_EXCEPTION_LIST object entered!"); }
533 CLOSURE(stg_END_EXCEPTION_LIST_closure,stg_END_EXCEPTION_LIST);
535 INFO_TABLE(stg_EXCEPTION_CONS,1,1,CONSTR,"EXCEPTION_CONS","EXCEPTION_CONS")
536 { foreign "C" barf("EXCEPTION_CONS object entered!"); }
538 /* ----------------------------------------------------------------------------
541 These come in two basic flavours: arrays of data (StgArrWords) and arrays of
542 pointers (StgArrPtrs). They all have a similar layout:
544 ___________________________
545 | Info | No. of | data....
547 ---------------------------
549 These are *unpointed* objects: i.e. they cannot be entered.
551 ------------------------------------------------------------------------- */
553 INFO_TABLE(stg_ARR_WORDS, 0, 0, ARR_WORDS, "ARR_WORDS", "ARR_WORDS")
554 { foreign "C" barf("ARR_WORDS object entered!"); }
556 INFO_TABLE(stg_MUT_ARR_PTRS_CLEAN, 0, 0, MUT_ARR_PTRS_CLEAN, "MUT_ARR_PTRS_CLEAN", "MUT_ARR_PTRS_CLEAN")
557 { foreign "C" barf("MUT_ARR_PTRS_CLEAN object entered!"); }
559 INFO_TABLE(stg_MUT_ARR_PTRS_DIRTY, 0, 0, MUT_ARR_PTRS_DIRTY, "MUT_ARR_PTRS_DIRTY", "MUT_ARR_PTRS_DIRTY")
560 { foreign "C" barf("MUT_ARR_PTRS_DIRTY object entered!"); }
562 INFO_TABLE(stg_MUT_ARR_PTRS_FROZEN, 0, 0, MUT_ARR_PTRS_FROZEN, "MUT_ARR_PTRS_FROZEN", "MUT_ARR_PTRS_FROZEN")
563 { foreign "C" barf("MUT_ARR_PTRS_FROZEN object entered!"); }
565 INFO_TABLE(stg_MUT_ARR_PTRS_FROZEN0, 0, 0, MUT_ARR_PTRS_FROZEN0, "MUT_ARR_PTRS_FROZEN0", "MUT_ARR_PTRS_FROZEN0")
566 { foreign "C" barf("MUT_ARR_PTRS_FROZEN0 object entered!"); }
568 /* ----------------------------------------------------------------------------
570 ------------------------------------------------------------------------- */
572 INFO_TABLE(stg_MUT_VAR_CLEAN, 1, 0, MUT_VAR_CLEAN, "MUT_VAR_CLEAN", "MUT_VAR_CLEAN")
573 { foreign "C" barf("MUT_VAR_CLEAN object entered!"); }
574 INFO_TABLE(stg_MUT_VAR_DIRTY, 1, 0, MUT_VAR_DIRTY, "MUT_VAR_DIRTY", "MUT_VAR_DIRTY")
575 { foreign "C" barf("MUT_VAR_DIRTY object entered!"); }
577 /* ----------------------------------------------------------------------------
580 Entering this closure will just return to the address on the top of the
581 stack. Useful for getting a thread in a canonical form where we can
582 just enter the top stack word to start the thread. (see deleteThread)
583 * ------------------------------------------------------------------------- */
585 INFO_TABLE( stg_dummy_ret, 0, 0, CONSTR_NOCAF_STATIC, "DUMMY_RET", "DUMMY_RET")
587 jump %ENTRY_CODE(Sp(0));
589 CLOSURE(stg_dummy_ret_closure,stg_dummy_ret);
591 /* ----------------------------------------------------------------------------
592 CHARLIKE and INTLIKE closures.
594 These are static representations of Chars and small Ints, so that
595 we can remove dynamic Chars and Ints during garbage collection and
596 replace them with references to the static objects.
597 ------------------------------------------------------------------------- */
599 #if defined(__PIC__) && defined(mingw32_TARGET_OS)
601 * When sticking the RTS in a DLL, we delay populating the
602 * Charlike and Intlike tables until load-time, which is only
603 * when we've got the real addresses to the C# and I# closures.
606 #warning Is this correct? _imp is a pointer!
607 #define Char_hash_static_info _imp__base_GHCziBase_Czh_static
608 #define Int_hash_static_info _imp__base_GHCziBase_Izh_static
610 #define Char_hash_static_info base_GHCziBase_Czh_static
611 #define Int_hash_static_info base_GHCziBase_Izh_static
615 #define CHARLIKE_HDR(n) CLOSURE(Char_hash_static_info, n)
616 #define INTLIKE_HDR(n) CLOSURE(Int_hash_static_info, n)
618 /* put these in the *data* section, since the garbage collector relies
619 * on the fact that static closures live in the data section.
622 /* end the name with _closure, to convince the mangler this is a closure */
625 stg_CHARLIKE_closure:
886 INTLIKE_HDR(-16) /* MIN_INTLIKE == -16 */
918 INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */