1 /* -----------------------------------------------------------------------------
2 * $Id: StgMiscClosures.hc,v 1.28 1999/11/02 15:06:03 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Entry code for various built-in closure types.
8 * ---------------------------------------------------------------------------*/
12 #include "StgMiscClosures.h"
13 #include "HeapStackCheck.h" /* for stg_gen_yield */
15 #include "StoragePriv.h"
23 /* ToDo: make the printing of panics more Win32-friendly, i.e.,
24 * pop up some lovely message boxes (as well).
26 #define DUMP_ERRMSG(msg) STGCALL2(fprintf,stderr,msg)
28 /* -----------------------------------------------------------------------------
29 Entry code for an indirection.
31 This code assumes R1 is in a register for now.
32 -------------------------------------------------------------------------- */
34 INFO_TABLE(IND_info,IND_entry,1,0,IND,,EF_,0,0);
38 TICK_ENT_IND(Node); /* tick */
40 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
42 JMP_(ENTRY_CODE(*R1.p));
46 INFO_TABLE(IND_STATIC_info,IND_STATIC_entry,1,0,IND_STATIC,,EF_,0,0);
47 STGFUN(IND_STATIC_entry)
50 TICK_ENT_IND(Node); /* tick */
52 R1.p = (P_) ((StgIndStatic*)R1.p)->indirectee;
54 JMP_(ENTRY_CODE(*R1.p));
58 INFO_TABLE(IND_PERM_info,IND_PERM_entry,1,1,IND_PERM,,EF_,0,0);
59 STGFUN(IND_PERM_entry)
62 /* Don't add INDs to granularity cost */
63 /* Dont: TICK_ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
65 #if defined(TICKY_TICKY) && !defined(PROFILING)
66 /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra */
67 TICK_ENT_PERM_IND(R1.p); /* tick */
70 /* Enter PAP cost centre -- lexical scoping only */
71 ENTER_CCS_PAP_CL(R1.cl);
73 /* For ticky-ticky, change the perm_ind to a normal ind on first
74 * entry, so the number of ent_perm_inds is the number of *thunks*
75 * entered again, not the number of subsequent entries.
77 * Since this screws up cost centres, we die if profiling and
78 * ticky_ticky are on at the same time. KSW 1999-01.
83 # error Profiling and ticky-ticky do not mix at present!
84 # endif /* PROFILING */
85 SET_INFO((StgInd*)R1.p,&IND_info);
86 #endif /* TICKY_TICKY */
88 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
90 /* Dont: TICK_ENT_VIA_NODE(); for ticky-ticky; as above */
92 #if defined(TICKY_TICKY) && !defined(PROFILING)
96 JMP_(ENTRY_CODE(*R1.p));
100 INFO_TABLE(IND_OLDGEN_info,IND_OLDGEN_entry,1,1,IND_OLDGEN,,EF_,0,0);
101 STGFUN(IND_OLDGEN_entry)
104 TICK_ENT_IND(Node); /* tick */
106 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
108 JMP_(ENTRY_CODE(*R1.p));
112 INFO_TABLE(IND_OLDGEN_PERM_info,IND_OLDGEN_PERM_entry,1,1,IND_OLDGEN_PERM,,EF_,0,0);
113 STGFUN(IND_OLDGEN_PERM_entry)
116 /* Dont: TICK_ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
118 #if defined(TICKY_TICKY) && !defined(PROFILING)
119 /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra */
120 TICK_ENT_PERM_IND(R1.p); /* tick */
123 /* Enter PAP cost centre -- lexical scoping only */
124 ENTER_CCS_PAP_CL(R1.cl);
126 /* see comment in IND_PERM */
129 # error Profiling and ticky-ticky do not mix at present!
130 # endif /* PROFILING */
131 SET_INFO((StgInd*)R1.p,&IND_OLDGEN_info);
132 #endif /* TICKY_TICKY */
134 R1.p = (P_) ((StgInd*)R1.p)->indirectee;
136 JMP_(ENTRY_CODE(*R1.p));
140 /* -----------------------------------------------------------------------------
143 This code assumes R1 is in a register for now.
144 -------------------------------------------------------------------------- */
146 INFO_TABLE(CAF_UNENTERED_info,CAF_UNENTERED_entry,1,3,CAF_UNENTERED,,EF_,0,0);
147 STGFUN(CAF_UNENTERED_entry)
150 /* ToDo: implement directly in GHC */
153 JMP_(stg_yield_to_Hugs);
157 /* 0,4 is entirely bogus; _do not_ rely on this info */
158 INFO_TABLE(CAF_ENTERED_info,CAF_ENTERED_entry,0,4,CAF_ENTERED,,EF_,0,0);
159 STGFUN(CAF_ENTERED_entry)
162 R1.p = (P_) ((StgCAF*)R1.p)->value; /* just a fancy indirection */
164 JMP_(GET_ENTRY(R1.cl));
168 /* -----------------------------------------------------------------------------
169 Entry code for a black hole.
171 Entering a black hole normally causes a cyclic data dependency, but
172 in the concurrent world, black holes are synchronization points,
173 and they are turned into blocking queues when there are threads
174 waiting for the evaluation of the closure to finish.
175 -------------------------------------------------------------------------- */
177 /* Note: a black hole must be big enough to be overwritten with an
178 * indirection/evacuee/catch. Thus we claim it has 1 non-pointer word of
179 * payload (in addition to the pointer word for the blocking queue), which
180 * should be big enough for an old-generation indirection.
183 INFO_TABLE(BLACKHOLE_info, BLACKHOLE_entry,0,2,BLACKHOLE,,EF_,0,0);
184 STGFUN(BLACKHOLE_entry)
188 CMPXCHG(R1.cl->header.info, &BLACKHOLE_info, &WHITEHOLE_info);
193 /* Put ourselves on the blocking queue for this black hole */
194 CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure;
195 ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
196 CurrentTSO->why_blocked = BlockedOnBlackHole;
197 CurrentTSO->block_info.closure = R1.cl;
198 recordMutable((StgMutClosure *)R1.cl);
199 /* Change the BLACKHOLE into a BLACKHOLE_BQ */
200 ((StgBlockingQueue *)R1.p)->header.info = &BLACKHOLE_BQ_info;
201 /* stg_gen_block is too heavyweight, use a specialised one */
206 INFO_TABLE(BLACKHOLE_BQ_info, BLACKHOLE_BQ_entry,1,1,BLACKHOLE_BQ,,EF_,0,0);
207 STGFUN(BLACKHOLE_BQ_entry)
211 CMPXCHG(R1.cl->header.info, &BLACKHOLE_info, &WHITEHOLE_info);
216 /* Put ourselves on the blocking queue for this black hole */
217 CurrentTSO->why_blocked = BlockedOnBlackHole;
218 CurrentTSO->block_info.closure = R1.cl;
219 CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
220 ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
222 ((StgBlockingQueue *)R1.p)->header.info = &BLACKHOLE_BQ_info;
225 /* stg_gen_block is too heavyweight, use a specialised one */
230 /* identical to BLACKHOLEs except for the infotag */
231 INFO_TABLE(CAF_BLACKHOLE_info, CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,,EF_,0,0);
232 STGFUN(CAF_BLACKHOLE_entry)
235 JMP_(BLACKHOLE_entry);
240 INFO_TABLE(SE_BLACKHOLE_info, SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,EF_,0,0);
241 STGFUN(SE_BLACKHOLE_entry)
244 STGCALL3(fprintf,stderr,"SE_BLACKHOLE at %p entered!\n",R1.p);
245 STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
249 INFO_TABLE(SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,EF_,0,0);
250 STGFUN(SE_CAF_BLACKHOLE_entry)
253 STGCALL3(fprintf,stderr,"SE_CAF_BLACKHOLE at %p entered!\n",R1.p);
254 STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
260 INFO_TABLE(WHITEHOLE_info, WHITEHOLE_entry,0,2,CONSTR_NOCAF_STATIC,,EF_,0,0);
261 STGFUN(WHITEHOLE_entry)
264 JMP_(GET_ENTRY(R1.cl));
269 /* -----------------------------------------------------------------------------
270 The code for a BCO returns to the scheduler
271 -------------------------------------------------------------------------- */
272 INFO_TABLE(BCO_info,BCO_entry,0,0,BCO,,EF_,0,0);
277 JMP_(stg_yield_to_Hugs);
281 /* -----------------------------------------------------------------------------
282 Some static info tables for things that don't get entered, and
283 therefore don't need entry code (i.e. boxed but unpointed objects)
284 -------------------------------------------------------------------------- */
286 #define NON_ENTERABLE_ENTRY_CODE(type) \
287 STGFUN(type##_entry) \
290 DUMP_ERRMSG(#type " object entered!\n"); \
291 STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE); \
295 INFO_TABLE(TSO_info, TSO_entry, 0,0,TSO,,EF_,0,0);
296 NON_ENTERABLE_ENTRY_CODE(TSO);
298 /* -----------------------------------------------------------------------------
299 Evacuees are left behind by the garbage collector. Any attempt to enter
301 -------------------------------------------------------------------------- */
303 INFO_TABLE(EVACUATED_info,EVACUATED_entry,1,0,EVACUATED,,EF_,0,0);
304 NON_ENTERABLE_ENTRY_CODE(EVACUATED);
306 /* -----------------------------------------------------------------------------
309 Live weak pointers have a special closure type. Dead ones are just
310 nullary constructors (although they live on the heap - we overwrite
311 live weak pointers with dead ones).
312 -------------------------------------------------------------------------- */
314 INFO_TABLE(WEAK_info,WEAK_entry,0,4,WEAK,,EF_,0,0);
315 NON_ENTERABLE_ENTRY_CODE(WEAK);
317 INFO_TABLE_CONSTR(DEAD_WEAK_info,DEAD_WEAK_entry,0,1,0,CONSTR,,EF_,0,0);
318 NON_ENTERABLE_ENTRY_CODE(DEAD_WEAK);
320 /* -----------------------------------------------------------------------------
323 This is a static nullary constructor (like []) that we use to mark an empty
324 finalizer in a weak pointer object.
325 -------------------------------------------------------------------------- */
327 INFO_TABLE_CONSTR(NO_FINALIZER_info,NO_FINALIZER_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
328 NON_ENTERABLE_ENTRY_CODE(NO_FINALIZER);
330 SET_STATIC_HDR(NO_FINALIZER_closure,NO_FINALIZER_info,0/*CC*/,,EI_)
333 /* -----------------------------------------------------------------------------
334 Foreign Objects are unlifted and therefore never entered.
335 -------------------------------------------------------------------------- */
337 INFO_TABLE(FOREIGN_info,FOREIGN_entry,0,1,FOREIGN,,EF_,0,0);
338 NON_ENTERABLE_ENTRY_CODE(FOREIGN);
340 /* -----------------------------------------------------------------------------
341 Stable Names are unlifted too.
342 -------------------------------------------------------------------------- */
344 INFO_TABLE(STABLE_NAME_info,STABLE_NAME_entry,0,1,STABLE_NAME,,EF_,0,0);
345 NON_ENTERABLE_ENTRY_CODE(STABLE_NAME);
347 /* -----------------------------------------------------------------------------
350 There are two kinds of these: full and empty. We need an info table
351 and entry code for each type.
352 -------------------------------------------------------------------------- */
354 INFO_TABLE(FULL_MVAR_info,FULL_MVAR_entry,4,0,MVAR,,EF_,0,0);
355 NON_ENTERABLE_ENTRY_CODE(FULL_MVAR);
357 INFO_TABLE(EMPTY_MVAR_info,EMPTY_MVAR_entry,4,0,MVAR,,EF_,0,0);
358 NON_ENTERABLE_ENTRY_CODE(EMPTY_MVAR);
360 /* -----------------------------------------------------------------------------
363 This is a static nullary constructor (like []) that we use to mark the
364 end of a linked TSO queue.
365 -------------------------------------------------------------------------- */
367 INFO_TABLE_CONSTR(END_TSO_QUEUE_info,END_TSO_QUEUE_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
368 NON_ENTERABLE_ENTRY_CODE(END_TSO_QUEUE);
370 SET_STATIC_HDR(END_TSO_QUEUE_closure,END_TSO_QUEUE_info,0/*CC*/,,EI_)
373 /* -----------------------------------------------------------------------------
376 Mutable lists (used by the garbage collector) consist of a chain of
377 StgMutClosures connected through their mut_link fields, ending in
378 an END_MUT_LIST closure.
379 -------------------------------------------------------------------------- */
381 INFO_TABLE_CONSTR(END_MUT_LIST_info,END_MUT_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
382 NON_ENTERABLE_ENTRY_CODE(END_MUT_LIST);
384 SET_STATIC_HDR(END_MUT_LIST_closure,END_MUT_LIST_info,0/*CC*/,,EI_)
387 INFO_TABLE(MUT_CONS_info, MUT_CONS_entry, 1, 1, MUT_VAR, , EF_, 0, 0);
388 NON_ENTERABLE_ENTRY_CODE(MUT_CONS);
390 /* -----------------------------------------------------------------------------
392 -------------------------------------------------------------------------- */
394 INFO_TABLE_CONSTR(END_EXCEPTION_LIST_info,END_EXCEPTION_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
395 NON_ENTERABLE_ENTRY_CODE(END_EXCEPTION_LIST);
397 SET_STATIC_HDR(END_EXCEPTION_LIST_closure,END_EXCEPTION_LIST_info,0/*CC*/,,EI_)
400 INFO_TABLE(EXCEPTION_CONS_info, EXCEPTION_CONS_entry, 1, 1, CONSTR, , EF_, 0, 0);
401 NON_ENTERABLE_ENTRY_CODE(EXCEPTION_CONS);
403 /* -----------------------------------------------------------------------------
406 These come in two basic flavours: arrays of data (StgArrWords) and arrays of
407 pointers (StgArrPtrs). They all have a similar layout:
409 ___________________________
410 | Info | No. of | data....
412 ---------------------------
414 These are *unpointed* objects: i.e. they cannot be entered.
416 -------------------------------------------------------------------------- */
418 #define ArrayInfo(type) \
419 INFO_TABLE(type##_info, type##_entry, 0, 0, type, , EF_,0,0);
421 ArrayInfo(ARR_WORDS);
422 NON_ENTERABLE_ENTRY_CODE(ARR_WORDS);
423 ArrayInfo(MUT_ARR_PTRS);
424 NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS);
425 ArrayInfo(MUT_ARR_PTRS_FROZEN);
426 NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS_FROZEN);
430 /* -----------------------------------------------------------------------------
432 -------------------------------------------------------------------------- */
434 INFO_TABLE(MUT_VAR_info, MUT_VAR_entry, 1, 1, MUT_VAR, , EF_, 0, 0);
435 NON_ENTERABLE_ENTRY_CODE(MUT_VAR);
437 /* -----------------------------------------------------------------------------
438 Standard Error Entry.
440 This is used for filling in vector-table entries that can never happen,
442 -------------------------------------------------------------------------- */
444 STGFUN(stg_error_entry) \
447 DUMP_ERRMSG("fatal: stg_error_entry"); \
448 STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE); \
452 /* -----------------------------------------------------------------------------
455 Entering this closure will just return to the address on the top of the
456 stack. Useful for getting a thread in a canonical form where we can
457 just enter the top stack word to start the thread. (see deleteThread)
458 * -------------------------------------------------------------------------- */
460 INFO_TABLE(dummy_ret_info, dummy_ret_entry, 0, 0, CONSTR_NOCAF_STATIC, , EF_, 0, 0);
467 JMP_(ENTRY_CODE(ret_addr));
470 SET_STATIC_HDR(dummy_ret_closure,dummy_ret_info,CCS_DONTZuCARE,,EI_)
473 /* -----------------------------------------------------------------------------
474 Strict IO application - performing an IO action and entering its result.
476 rts_evalIO() lets you perform Haskell IO actions from outside of Haskell-land,
477 returning back to you their result. Want this result to be evaluated to WHNF
478 by that time, so that we can easily get at the int/char/whatever using the
479 various get{Ty} functions provided by the RTS API.
481 forceIO takes care of this, performing the IO action and entering the
482 results that comes back.
484 * -------------------------------------------------------------------------- */
486 INFO_TABLE_SRT_BITMAP(forceIO_ret_info,forceIO_ret_entry,0,0,0,0,RET_SMALL,,EF_,0,0);
487 FN_(forceIO_ret_entry)
491 Sp -= sizeofW(StgSeqFrame);
493 JMP_(GET_ENTRY(R1.cl));
497 INFO_TABLE(forceIO_info,forceIO_entry,1,0,FUN,,EF_,0,0);
501 /* Sp[0] contains the IO action we want to perform */
503 /* Replace it with the return continuation that enters the result. */
504 Sp[0] = (W_)&forceIO_ret_info;
506 /* Push the RealWorld# tag and enter */
507 Sp[0] =(W_)REALWORLD_TAG;
508 JMP_(GET_ENTRY(R1.cl));
511 SET_STATIC_HDR(forceIO_closure,forceIO_info,CCS_DONTZuCARE,,EI_)
515 /* -----------------------------------------------------------------------------
516 Standard Infotables (for use in interpreter)
517 -------------------------------------------------------------------------- */
521 STGFUN(Hugs_CONSTR_entry)
523 /* R1 points at the constructor */
524 JMP_(ENTRY_CODE(((StgPtr*)Sp)[0]));
527 #define RET_BCO_ENTRY_TEMPLATE(label) \
532 ((StgPtr*)Sp)[0] = R1.p; \
533 JMP_(stg_yield_to_Hugs); \
537 RET_BCO_ENTRY_TEMPLATE(ret_bco_entry );
538 RET_BCO_ENTRY_TEMPLATE(ret_bco_0_entry);
539 RET_BCO_ENTRY_TEMPLATE(ret_bco_1_entry);
540 RET_BCO_ENTRY_TEMPLATE(ret_bco_2_entry);
541 RET_BCO_ENTRY_TEMPLATE(ret_bco_3_entry);
542 RET_BCO_ENTRY_TEMPLATE(ret_bco_4_entry);
543 RET_BCO_ENTRY_TEMPLATE(ret_bco_5_entry);
544 RET_BCO_ENTRY_TEMPLATE(ret_bco_6_entry);
545 RET_BCO_ENTRY_TEMPLATE(ret_bco_7_entry);
547 VEC_POLY_INFO_TABLE(ret_bco,0, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, RET_BCO,, EF_);
549 #endif /* INTERPRETER */
553 INFO_TABLE_CONSTR(Czh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgChar),0,CONSTR,,EF_,0,0);
554 INFO_TABLE_CONSTR(Izh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgInt),0,CONSTR,,EF_,0,0);
555 INFO_TABLE_CONSTR(I64zh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgInt64),0,CONSTR,,EF_,0,0);
556 INFO_TABLE_CONSTR(Fzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgFloat),0,CONSTR,,EF_,0,0);
557 INFO_TABLE_CONSTR(Dzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgDouble),0,CONSTR,,EF_,0,0);
558 INFO_TABLE_CONSTR(Azh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgAddr),0,CONSTR,,EF_,0,0);
559 INFO_TABLE_CONSTR(Wzh_con_info,Hugs_CONSTR_entry,0,sizeofW(StgWord),0,CONSTR,,EF_,0,0);
560 INFO_TABLE_CONSTR(StablePtr_con_info,Hugs_CONSTR_entry,0,sizeofW(StgStablePtr),0,CONSTR,,EF_,0,0);
562 /* These might seem redundant but {I,C}zh_static_info are used in
563 * {INT,CHAR}LIKE and the rest are used in RtsAPI.c
565 INFO_TABLE_CONSTR(Czh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgChar),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
566 INFO_TABLE_CONSTR(Izh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgInt),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
567 INFO_TABLE_CONSTR(I64zh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgInt64),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
568 INFO_TABLE_CONSTR(Fzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgFloat),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
569 INFO_TABLE_CONSTR(Dzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgDouble),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
570 INFO_TABLE_CONSTR(Azh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgAddr),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
571 INFO_TABLE_CONSTR(Wzh_static_info,Hugs_CONSTR_entry,0,sizeofW(StgWord),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
572 INFO_TABLE_CONSTR(StablePtr_static_info,Hugs_CONSTR_entry,0,sizeofW(StgStablePtr),0,CONSTR_NOCAF_STATIC,,EF_,0,0);
574 #endif /* !defined(COMPILER) */
576 /* -----------------------------------------------------------------------------
577 CHARLIKE and INTLIKE closures.
579 These are static representations of Chars and small Ints, so that
580 we can remove dynamic Chars and Ints during garbage collection and
581 replace them with references to the static objects.
582 -------------------------------------------------------------------------- */
584 #ifdef ENABLE_WIN32_DLL_SUPPORT
586 * When sticking the RTS in a DLL, we delay populating the
587 * Charlike and Intlike tables until load-time, which is only
588 * when we've got the real addresses to the C# and I# closures.
591 static INFO_TBL_CONST StgInfoTable czh_static_info;
592 static INFO_TBL_CONST StgInfoTable izh_static_info;
593 #define Char_hash_static_info czh_static_info
594 #define Int_hash_static_info izh_static_info
596 #define Char_hash_static_info Czh_static_info
597 #define Int_hash_static_info Izh_static_info
600 #define CHARLIKE_HDR(n) \
602 STATIC_HDR(Char_hash_static_info, /* C# */ \
607 #define INTLIKE_HDR(n) \
609 STATIC_HDR(Int_hash_static_info, /* I# */ \
614 /* put these in the *data* section, since the garbage collector relies
615 * on the fact that static closures live in the data section.
618 /* end the name with _closure, to convince the mangler this is a closure */
620 StgIntCharlikeClosure CHARLIKE_closure[] = {
879 StgIntCharlikeClosure INTLIKE_closure[] = {
880 INTLIKE_HDR(-16), /* MIN_INTLIKE == -16 */
912 INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */