[project @ 2000-12-14 15:19:47 by sewardj]
[ghc-hetmet.git] / ghc / rts / StgMiscClosures.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: StgMiscClosures.hc,v 1.54 2000/12/14 15:19:48 sewardj Exp $
3  *
4  * (c) The GHC Team, 1998-2000
5  *
6  * Entry code for various built-in closure types.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "Rts.h"
11 #include "RtsUtils.h"
12 #include "RtsFlags.h"
13 #include "StgMiscClosures.h"
14 #include "HeapStackCheck.h"   /* for stg_gen_yield */
15 #include "Storage.h"
16 #include "StoragePriv.h"
17 #include "Profiling.h"
18 #include "Prelude.h"
19 #include "Schedule.h"
20 #include "SMP.h"
21 #if defined(GRAN) || defined(PAR)
22 # include "GranSimRts.h"      /* for DumpRawGranEvent */
23 # include "StgRun.h"    /* for StgReturn and register saving */
24 #endif
25
26 #ifdef HAVE_STDIO_H
27 #include <stdio.h>
28 #endif
29
30 /* ToDo: make the printing of panics more win32-friendly, i.e.,
31  *       pop up some lovely message boxes (as well).
32  */
33 #define DUMP_ERRMSG(msg) STGCALL2(fprintf,stderr,msg)
34
35 /*
36   Template for the entry code of non-enterable closures.
37 */
38
39 #define NON_ENTERABLE_ENTRY_CODE(type)                                  \
40 STGFUN(stg_##type##_entry)                                                      \
41 {                                                                       \
42   FB_                                                                   \
43     DUMP_ERRMSG(#type " object entered!\n");                            \
44     STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE);                     \
45     return NULL;                                                        \
46   FE_                                                                   \
47 }
48
49
50 /* -----------------------------------------------------------------------------
51    Support for the bytecode interpreter.
52    -------------------------------------------------------------------------- */
53
54 #ifdef GHCI
55
56 /* 9 bits of return code for constructors created by mci_make_constr. */
57 FN_(stg_bco_constr_entry) 
58
59   /* R1 points at the constructor */
60   FB_ 
61     STGCALL2(fprintf,stderr,"stg_bco_constr_entry (direct return)!\n");
62     /* Pointless, since SET_TAG doesn't do anything */
63     SET_TAG( GET_TAG(GET_INFO(R1.cl))); 
64     JMP_(ENTRY_CODE((P_)(*Sp))); 
65   FE_ 
66 }
67
68 FN_(stg_bco_constr1_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),0)); FE_ }
69 FN_(stg_bco_constr2_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),1)); FE_ }
70 FN_(stg_bco_constr3_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),2)); FE_ }
71 FN_(stg_bco_constr4_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),3)); FE_ }
72 FN_(stg_bco_constr5_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),4)); FE_ }
73 FN_(stg_bco_constr6_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),5)); FE_ }
74 FN_(stg_bco_constr7_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),6)); FE_ }
75 FN_(stg_bco_constr8_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),7)); FE_ }
76  
77 /* Some info tables to be used when compiled code returns a value to
78    the interpreter, i.e. the interpreter pushes one of these onto the
79    stack before entering a value.  What the code does is to
80    impedance-match the compiled return convention (in R1/F1/D1 etc) to
81    the interpreter's convention (returned value is on top of stack),
82    and then cause the scheduler to enter the interpreter.
83
84    On entry, the stack (growing down) looks like this:
85
86       ptr to BCO holding return continuation
87       ptr to one of these info tables.
88  
89    The info table code, both direct and vectored, must:
90       * push R1/F1/D1 on the stack
91       * push the BCO (so it's now on the stack twice)
92       * Yield, ie, go to the scheduler.
93
94    Scheduler examines the t.o.s, discovers it is a BCO, and proceeds
95    directly to the bytecode interpreter.  That pops the top element
96    (the BCO, containing the return continuation), and interprets it.
97    Net result: return continuation gets interpreted, with the
98    following stack:
99
100       ptr to this BCO
101       ptr to the info table just jumped thru
102       return value
103
104    which is just what we want -- the "standard" return layout for the
105    interpreter.  Hurrah!
106
107    Don't ask me how unboxed tuple returns are supposed to work.  We
108    haven't got a good story about that yet.
109 */
110
111 /* When the returned value is in R1 ... */
112 #define STG_BCORET_R1_Template(label)   \
113    IFN_(label)                          \
114    {                                    \
115       StgPtr bco;                       \
116       FB_                               \
117       bco = ((StgPtr*)Sp)[1];           \
118       Sp -= 1;                          \
119       ((StgPtr*)Sp)[0] = R1.p;          \
120       Sp -= 1;                          \
121       ((StgPtr*)Sp)[0] = bco;           \
122       JMP_(stg_yield_to_interpreter);   \
123       FE_                               \
124    }
125
126 STG_BCORET_R1_Template(stg_bcoret_R1_entry);
127 STG_BCORET_R1_Template(stg_bcoret_R1_0_entry);
128 STG_BCORET_R1_Template(stg_bcoret_R1_1_entry);
129 STG_BCORET_R1_Template(stg_bcoret_R1_2_entry);
130 STG_BCORET_R1_Template(stg_bcoret_R1_3_entry);
131 STG_BCORET_R1_Template(stg_bcoret_R1_4_entry);
132 STG_BCORET_R1_Template(stg_bcoret_R1_5_entry);
133 STG_BCORET_R1_Template(stg_bcoret_R1_6_entry);
134 STG_BCORET_R1_Template(stg_bcoret_R1_7_entry);
135
136 VEC_POLY_INFO_TABLE(stg_bcoret_R1,0, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, RET_BCO,, EF_);
137
138
139 /* Entering a BCO.  Heave it on the stack and defer to the
140    scheduler. */
141 INFO_TABLE(stg_BCO_info,stg_BCO_entry,3,0,BCO,,EF_,"BCO","BCO");
142 STGFUN(stg_BCO_entry) {
143   FB_
144     Sp -= 1;
145     Sp[0] = R1.w;
146     JMP_(stg_yield_to_interpreter);
147   FE_
148 }
149
150 #endif /* GHCI */
151
152
153 /* -----------------------------------------------------------------------------
154    Entry code for an indirection.
155    -------------------------------------------------------------------------- */
156
157 INFO_TABLE(stg_IND_info,stg_IND_entry,1,0,IND,,EF_,0,0);
158 STGFUN(stg_IND_entry)
159 {
160     FB_
161     TICK_ENT_IND(Node); /* tick */
162
163     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
164     TICK_ENT_VIA_NODE();
165     JMP_(ENTRY_CODE(*R1.p));
166     FE_
167 }
168
169 INFO_TABLE(stg_IND_STATIC_info,stg_IND_STATIC_entry,1,0,IND_STATIC,,EF_,0,0);
170 STGFUN(stg_IND_STATIC_entry)
171 {
172     FB_
173     TICK_ENT_IND(Node); /* tick */
174     R1.p = (P_) ((StgIndStatic*)R1.p)->indirectee;
175     TICK_ENT_VIA_NODE();
176     JMP_(ENTRY_CODE(*R1.p));
177     FE_
178 }
179
180 INFO_TABLE(stg_IND_PERM_info,stg_IND_PERM_entry,1,1,IND_PERM,,EF_,"IND_PERM","IND_PERM");
181 STGFUN(stg_IND_PERM_entry)
182 {
183     FB_
184     /* Don't add INDs to granularity cost */
185     /* Dont: TICK_ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
186
187 #if defined(TICKY_TICKY) && !defined(PROFILING)
188     /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra  */
189     TICK_ENT_PERM_IND(R1.p); /* tick */
190 #endif
191
192     /* Enter PAP cost centre -- lexical scoping only */
193     ENTER_CCS_PAP_CL(R1.cl);
194
195     /* For ticky-ticky, change the perm_ind to a normal ind on first
196      * entry, so the number of ent_perm_inds is the number of *thunks*
197      * entered again, not the number of subsequent entries.
198      *
199      * Since this screws up cost centres, we die if profiling and
200      * ticky_ticky are on at the same time.  KSW 1999-01.
201      */
202
203 #ifdef TICKY_TICKY
204 #  ifdef PROFILING
205 #    error Profiling and ticky-ticky do not mix at present!
206 #  endif  /* PROFILING */
207     SET_INFO((StgInd*)R1.p,&IND_info);
208 #endif /* TICKY_TICKY */
209
210     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
211
212     /* Dont: TICK_ENT_VIA_NODE(); for ticky-ticky; as above */
213
214 #if defined(TICKY_TICKY) && !defined(PROFILING)
215     TICK_ENT_VIA_NODE();
216 #endif
217
218     JMP_(ENTRY_CODE(*R1.p));
219     FE_
220 }  
221
222 INFO_TABLE(stg_IND_OLDGEN_info,stg_IND_OLDGEN_entry,1,1,IND_OLDGEN,,EF_,0,0);
223 STGFUN(stg_IND_OLDGEN_entry)
224 {
225     FB_
226     TICK_ENT_IND(Node); /* tick */
227   
228     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
229     TICK_ENT_VIA_NODE();
230     JMP_(ENTRY_CODE(*R1.p));
231     FE_
232 }
233
234 INFO_TABLE(stg_IND_OLDGEN_PERM_info,stg_IND_OLDGEN_PERM_entry,1,1,IND_OLDGEN_PERM,,EF_,0,0);
235 STGFUN(stg_IND_OLDGEN_PERM_entry)
236 {
237     FB_
238     /* Dont: TICK_ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
239
240 #if defined(TICKY_TICKY) && !defined(PROFILING)
241     /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra  */
242     TICK_ENT_PERM_IND(R1.p); /* tick */
243 #endif
244   
245     /* Enter PAP cost centre -- lexical scoping only */
246     ENTER_CCS_PAP_CL(R1.cl);
247
248     /* see comment in IND_PERM */
249 #ifdef TICKY_TICKY
250 #  ifdef PROFILING
251 #    error Profiling and ticky-ticky do not mix at present!
252 #  endif  /* PROFILING */
253     SET_INFO((StgInd*)R1.p,&IND_OLDGEN_info);
254 #endif /* TICKY_TICKY */
255
256     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
257     TICK_ENT_VIA_NODE();
258     JMP_(ENTRY_CODE(*R1.p));
259     FE_
260 }
261
262 /* -----------------------------------------------------------------------------
263    Entry code for CAFs
264
265    This code assumes R1 is in a register for now.
266    -------------------------------------------------------------------------- */
267
268 INFO_TABLE(stg_CAF_UNENTERED_info,stg_CAF_UNENTERED_entry,1,3,CAF_UNENTERED,,EF_,0,0);
269 STGFUN(stg_CAF_UNENTERED_entry)
270 {
271     FB_
272     /* ToDo: implement directly in GHC */
273     Sp -= 1;
274     Sp[0] = R1.w;
275     JMP_(stg_yield_to_interpreter);
276     FE_
277 }
278
279 /* 0,4 is entirely bogus; _do not_ rely on this info */
280 INFO_TABLE(stg_CAF_ENTERED_info,stg_CAF_ENTERED_entry,0,4,CAF_ENTERED,,EF_,0,0);
281 STGFUN(stg_CAF_ENTERED_entry)
282 {
283     FB_
284     R1.p = (P_) ((StgCAF*)R1.p)->value; /* just a fancy indirection */
285     TICK_ENT_VIA_NODE();
286     JMP_(GET_ENTRY(R1.cl));
287     FE_
288 }
289
290 /* -----------------------------------------------------------------------------
291    Entry code for a black hole.
292
293    Entering a black hole normally causes a cyclic data dependency, but
294    in the concurrent world, black holes are synchronization points,
295    and they are turned into blocking queues when there are threads
296    waiting for the evaluation of the closure to finish.
297    -------------------------------------------------------------------------- */
298
299 /* Note: a BLACKHOLE and BLACKHOLE_BQ must be big enough to be
300  * overwritten with an indirection/evacuee/catch.  Thus we claim it
301  * has 1 non-pointer word of payload (in addition to the pointer word
302  * for the blocking queue in a BQ), which should be big enough for an
303  * old-generation indirection. 
304  */
305
306 INFO_TABLE(stg_BLACKHOLE_info, stg_BLACKHOLE_entry,0,2,BLACKHOLE,,EF_,"BLACKHOLE","BLACKHOLE");
307 STGFUN(stg_BLACKHOLE_entry)
308 {
309   FB_
310 #if defined(GRAN)
311     /* Before overwriting TSO_LINK */
312     STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
313 #endif
314
315 #ifdef SMP
316     {
317       bdescr *bd = Bdescr(R1.p);
318       if (bd->back != (bdescr *)BaseReg) {
319         if (bd->gen->no >= 1 || bd->step->no >= 1) {
320           CMPXCHG(R1.cl->header.info, &BLACKHOLE_info, &WHITEHOLE_info);
321         } else {
322           EXTFUN_RTS(stg_gc_enter_1_hponly);
323           JMP_(stg_gc_enter_1_hponly);
324         }
325       }
326     }
327 #endif
328     TICK_ENT_BH();
329
330     /* Put ourselves on the blocking queue for this black hole */
331 #if defined(GRAN) || defined(PAR)
332     /* in fact, only difference is the type of the end-of-queue marker! */
333     CurrentTSO->link = END_BQ_QUEUE;
334     ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO;
335 #else
336     CurrentTSO->link = END_TSO_QUEUE;
337     ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
338 #endif
339     /* jot down why and on what closure we are blocked */
340     CurrentTSO->why_blocked = BlockedOnBlackHole;
341     CurrentTSO->block_info.closure = R1.cl;
342     /* closure is mutable since something has just been added to its BQ */
343     recordMutable((StgMutClosure *)R1.cl);
344     /* Change the BLACKHOLE into a BLACKHOLE_BQ */
345     ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
346
347     /* PAR: dumping of event now done in blockThread -- HWL */
348
349     /* stg_gen_block is too heavyweight, use a specialised one */
350     BLOCK_NP(1);
351
352   FE_
353 }
354
355 INFO_TABLE(stg_BLACKHOLE_BQ_info, stg_BLACKHOLE_BQ_entry,1,1,BLACKHOLE_BQ,,EF_,"BLACKHOLE","BLACKHOLE");
356 STGFUN(stg_BLACKHOLE_BQ_entry)
357 {
358   FB_
359 #if defined(GRAN)
360     /* Before overwriting TSO_LINK */
361     STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
362 #endif
363
364 #ifdef SMP
365     {
366       bdescr *bd = Bdescr(R1.p);
367       if (bd->back != (bdescr *)BaseReg) {
368         if (bd->gen->no >= 1 || bd->step->no >= 1) {
369           CMPXCHG(R1.cl->header.info, &BLACKHOLE_info, &WHITEHOLE_info);
370         } else {
371           EXTFUN_RTS(stg_gc_enter_1_hponly);
372           JMP_(stg_gc_enter_1_hponly);
373         }
374       }
375     }
376 #endif
377
378     TICK_ENT_BH();
379
380     /* Put ourselves on the blocking queue for this black hole */
381     CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
382     ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
383     /* jot down why and on what closure we are blocked */
384     CurrentTSO->why_blocked = BlockedOnBlackHole;
385     CurrentTSO->block_info.closure = R1.cl;
386 #ifdef SMP
387     ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
388 #endif
389
390     /* PAR: dumping of event now done in blockThread -- HWL */
391
392     /* stg_gen_block is too heavyweight, use a specialised one */
393     BLOCK_NP(1);
394   FE_
395 }
396
397 /*
398    Revertible black holes are needed in the parallel world, to handle
399    negative acknowledgements of messages containing updatable closures.
400    The idea is that when the original message is transmitted, the closure
401    is turned into a revertible black hole...an object which acts like a
402    black hole when local threads try to enter it, but which can be reverted
403    back to the original closure if necessary.
404
405    It's actually a lot like a blocking queue (BQ) entry, because revertible
406    black holes are initially set up with an empty blocking queue.
407 */
408
409 #if defined(PAR) || defined(GRAN)
410
411 INFO_TABLE(stg_RBH_info, stg_RBH_entry,1,1,RBH,,EF_,0,0);
412 STGFUN(stg_RBH_entry)
413 {
414   FB_
415 # if defined(GRAN)
416     /* mainly statistics gathering for GranSim simulation */
417     STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
418 # endif
419
420     /* exactly the same as a BLACKHOLE_BQ_entry -- HWL */
421     /* Put ourselves on the blocking queue for this black hole */
422     CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
423     ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
424     /* jot down why and on what closure we are blocked */
425     CurrentTSO->why_blocked = BlockedOnBlackHole;
426     CurrentTSO->block_info.closure = R1.cl;
427
428     /* PAR: dumping of event now done in blockThread -- HWL */
429
430     /* stg_gen_block is too heavyweight, use a specialised one */
431     BLOCK_NP(1); 
432   FE_
433 }
434
435 INFO_TABLE(stg_RBH_Save_0_info, stg_RBH_Save_0_entry,0,2,CONSTR,,EF_,0,0);
436 NON_ENTERABLE_ENTRY_CODE(RBH_Save_0);
437
438 INFO_TABLE(stg_RBH_Save_1_info, stg_RBH_Save_1_entry,1,1,CONSTR,,EF_,0,0);
439 NON_ENTERABLE_ENTRY_CODE(RBH_Save_1);
440
441 INFO_TABLE(stg_RBH_Save_2_info, stg_RBH_Save_2_entry,2,0,CONSTR,,EF_,0,0);
442 NON_ENTERABLE_ENTRY_CODE(RBH_Save_2);
443 #endif /* defined(PAR) || defined(GRAN) */
444
445 /* identical to BLACKHOLEs except for the infotag */
446 INFO_TABLE(stg_CAF_BLACKHOLE_info, stg_CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,,EF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
447 STGFUN(stg_CAF_BLACKHOLE_entry)
448 {
449   FB_
450 #if defined(GRAN)
451     /* mainly statistics gathering for GranSim simulation */
452     STGCALL3(GranSimBlock,CurrentTSO,CurrentProc,(StgClosure *)R1.p /*Node*/);
453 #endif
454
455 #ifdef SMP
456     {
457       bdescr *bd = Bdescr(R1.p);
458       if (bd->back != (bdescr *)BaseReg) {
459         if (bd->gen->no >= 1 || bd->step->no >= 1) {
460           CMPXCHG(R1.cl->header.info, &CAF_BLACKHOLE_info, &WHITEHOLE_info);
461         } else {
462           EXTFUN_RTS(stg_gc_enter_1_hponly);
463           JMP_(stg_gc_enter_1_hponly);
464         }
465       }
466     }
467 #endif
468
469     TICK_ENT_BH();
470
471     /* Put ourselves on the blocking queue for this black hole */
472 #if defined(GRAN) || defined(PAR)
473     /* in fact, only difference is the type of the end-of-queue marker! */
474     CurrentTSO->link = END_BQ_QUEUE;
475     ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO;
476 #else
477     CurrentTSO->link = END_TSO_QUEUE;
478     ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
479 #endif
480     /* jot down why and on what closure we are blocked */
481     CurrentTSO->why_blocked = BlockedOnBlackHole;
482     CurrentTSO->block_info.closure = R1.cl;
483     /* closure is mutable since something has just been added to its BQ */
484     recordMutable((StgMutClosure *)R1.cl);
485     /* Change the CAF_BLACKHOLE into a BLACKHOLE_BQ */
486     ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
487
488     /* PAR: dumping of event now done in blockThread -- HWL */
489
490     /* stg_gen_block is too heavyweight, use a specialised one */
491     BLOCK_NP(1);
492   FE_
493 }
494
495 #ifdef TICKY_TICKY
496 INFO_TABLE(stg_SE_BLACKHOLE_info, stg_SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,EF_,0,0);
497 STGFUN(stg_SE_BLACKHOLE_entry)
498 {
499   FB_
500     STGCALL3(fprintf,stderr,"SE_BLACKHOLE at %p entered!\n",R1.p);
501     STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
502   FE_
503 }
504
505 INFO_TABLE(SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,EF_,0,0);
506 STGFUN(stg_SE_CAF_BLACKHOLE_entry)
507 {
508   FB_
509     STGCALL3(fprintf,stderr,"SE_CAF_BLACKHOLE at %p entered!\n",R1.p);
510     STGCALL1(shutdownHaskellAndExit,EXIT_FAILURE);
511   FE_
512 }
513 #endif
514
515 #ifdef SMP
516 INFO_TABLE(stg_WHITEHOLE_info, stg_WHITEHOLE_entry,0,2,CONSTR_NOCAF_STATIC,,EF_,0,0);
517 STGFUN(stg_WHITEHOLE_entry)
518 {
519   FB_
520      JMP_(GET_ENTRY(R1.cl));
521   FE_
522 }
523 #endif
524
525 /* -----------------------------------------------------------------------------
526    Some static info tables for things that don't get entered, and
527    therefore don't need entry code (i.e. boxed but unpointed objects)
528    NON_ENTERABLE_ENTRY_CODE now defined at the beginning of the file
529    -------------------------------------------------------------------------- */
530
531 INFO_TABLE(stg_TSO_info, stg_TSO_entry, 0,0,TSO,,EF_,"TSO","TSO");
532 NON_ENTERABLE_ENTRY_CODE(TSO);
533
534 /* -----------------------------------------------------------------------------
535    Evacuees are left behind by the garbage collector.  Any attempt to enter
536    one is a real bug.
537    -------------------------------------------------------------------------- */
538
539 INFO_TABLE(stg_EVACUATED_info,stg_EVACUATED_entry,1,0,EVACUATED,,EF_,0,0);
540 NON_ENTERABLE_ENTRY_CODE(EVACUATED);
541
542 /* -----------------------------------------------------------------------------
543    Weak pointers
544
545    Live weak pointers have a special closure type.  Dead ones are just
546    nullary constructors (although they live on the heap - we overwrite
547    live weak pointers with dead ones).
548    -------------------------------------------------------------------------- */
549
550 INFO_TABLE(stg_WEAK_info,stg_WEAK_entry,0,4,WEAK,,EF_,"WEAK","WEAK");
551 NON_ENTERABLE_ENTRY_CODE(WEAK);
552
553 INFO_TABLE_CONSTR(stg_DEAD_WEAK_info,stg_DEAD_WEAK_entry,0,1,0,CONSTR,,EF_,"DEAD_WEAK","DEAD_WEAK");
554 NON_ENTERABLE_ENTRY_CODE(DEAD_WEAK);
555
556 /* -----------------------------------------------------------------------------
557    NO_FINALIZER
558
559    This is a static nullary constructor (like []) that we use to mark an empty
560    finalizer in a weak pointer object.
561    -------------------------------------------------------------------------- */
562
563 INFO_TABLE_CONSTR(stg_NO_FINALIZER_info,stg_NO_FINALIZER_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
564 NON_ENTERABLE_ENTRY_CODE(NO_FINALIZER);
565
566 SET_STATIC_HDR(stg_NO_FINALIZER_closure,stg_NO_FINALIZER_info,0/*CC*/,,EI_)
567 , /*payload*/{} };
568
569 /* -----------------------------------------------------------------------------
570    Foreign Objects are unlifted and therefore never entered.
571    -------------------------------------------------------------------------- */
572
573 INFO_TABLE(stg_FOREIGN_info,stg_FOREIGN_entry,0,1,FOREIGN,,EF_,"FOREIGN","FOREIGN");
574 NON_ENTERABLE_ENTRY_CODE(FOREIGN);
575
576 /* -----------------------------------------------------------------------------
577    Stable Names are unlifted too.
578    -------------------------------------------------------------------------- */
579
580 INFO_TABLE(stg_STABLE_NAME_info,stg_STABLE_NAME_entry,0,1,STABLE_NAME,,EF_,"STABLE_NAME","STABLE_NAME");
581 NON_ENTERABLE_ENTRY_CODE(STABLE_NAME);
582
583 /* -----------------------------------------------------------------------------
584    MVars
585
586    There are two kinds of these: full and empty.  We need an info table
587    and entry code for each type.
588    -------------------------------------------------------------------------- */
589
590 INFO_TABLE(stg_FULL_MVAR_info,stg_FULL_MVAR_entry,4,0,MVAR,,EF_,"MVAR","MVAR");
591 NON_ENTERABLE_ENTRY_CODE(FULL_MVAR);
592
593 INFO_TABLE(stg_EMPTY_MVAR_info,stg_EMPTY_MVAR_entry,4,0,MVAR,,EF_,"MVAR","MVAR");
594 NON_ENTERABLE_ENTRY_CODE(EMPTY_MVAR);
595
596 /* -----------------------------------------------------------------------------
597    END_TSO_QUEUE
598
599    This is a static nullary constructor (like []) that we use to mark the
600    end of a linked TSO queue.
601    -------------------------------------------------------------------------- */
602
603 INFO_TABLE_CONSTR(stg_END_TSO_QUEUE_info,stg_END_TSO_QUEUE_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
604 NON_ENTERABLE_ENTRY_CODE(END_TSO_QUEUE);
605
606 SET_STATIC_HDR(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE_info,0/*CC*/,,EI_)
607 , /*payload*/{} };
608
609 /* -----------------------------------------------------------------------------
610    Mutable lists
611
612    Mutable lists (used by the garbage collector) consist of a chain of
613    StgMutClosures connected through their mut_link fields, ending in
614    an END_MUT_LIST closure.
615    -------------------------------------------------------------------------- */
616
617 INFO_TABLE_CONSTR(stg_END_MUT_LIST_info,stg_END_MUT_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
618 NON_ENTERABLE_ENTRY_CODE(END_MUT_LIST);
619
620 SET_STATIC_HDR(stg_END_MUT_LIST_closure,stg_END_MUT_LIST_info,0/*CC*/,,EI_)
621 , /*payload*/{} };
622
623 INFO_TABLE(stg_MUT_CONS_info, stg_MUT_CONS_entry, 1, 1, MUT_VAR, , EF_, 0, 0);
624 NON_ENTERABLE_ENTRY_CODE(MUT_CONS);
625
626 /* -----------------------------------------------------------------------------
627    Exception lists
628    -------------------------------------------------------------------------- */
629
630 INFO_TABLE_CONSTR(stg_END_EXCEPTION_LIST_info,stg_END_EXCEPTION_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
631 NON_ENTERABLE_ENTRY_CODE(END_EXCEPTION_LIST);
632
633 SET_STATIC_HDR(stg_END_EXCEPTION_LIST_closure,stg_END_EXCEPTION_LIST_info,0/*CC*/,,EI_)
634 , /*payload*/{} };
635
636 INFO_TABLE(stg_EXCEPTION_CONS_info, stg_EXCEPTION_CONS_entry, 1, 1, CONSTR, , EF_, 0, 0);
637 NON_ENTERABLE_ENTRY_CODE(EXCEPTION_CONS);
638
639 /* -----------------------------------------------------------------------------
640    Arrays
641
642    These come in two basic flavours: arrays of data (StgArrWords) and arrays of
643    pointers (StgArrPtrs).  They all have a similar layout:
644
645         ___________________________
646         | Info | No. of | data....
647         |  Ptr | Words  |
648         ---------------------------
649
650    These are *unpointed* objects: i.e. they cannot be entered.
651
652    -------------------------------------------------------------------------- */
653
654 #define ArrayInfo(type)                                 \
655 INFO_TABLE(stg_##type##_info, stg_##type##_entry, 0, 0, type, , EF_,"" # type "","" # type "");
656
657 ArrayInfo(ARR_WORDS);
658 NON_ENTERABLE_ENTRY_CODE(ARR_WORDS);
659 ArrayInfo(MUT_ARR_PTRS);
660 NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS);
661 ArrayInfo(MUT_ARR_PTRS_FROZEN);
662 NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS_FROZEN);
663
664 #undef ArrayInfo
665
666 /* -----------------------------------------------------------------------------
667    Mutable Variables
668    -------------------------------------------------------------------------- */
669
670 INFO_TABLE(stg_MUT_VAR_info, stg_MUT_VAR_entry, 1, 1, MUT_VAR, , EF_, "MUT_VAR", "MUT_VAR");
671 NON_ENTERABLE_ENTRY_CODE(MUT_VAR);
672
673 /* -----------------------------------------------------------------------------
674    Standard Error Entry.
675
676    This is used for filling in vector-table entries that can never happen,
677    for instance.
678    -------------------------------------------------------------------------- */
679 /* No longer used; we use NULL, because a) it never happens, right? and b)
680    Windows doesn't like DLL entry points being used as static initialisers
681 STGFUN(stg_error_entry)                                                 \
682 {                                                                       \
683   FB_                                                                   \
684     DUMP_ERRMSG("fatal: stg_error_entry");                              \
685     STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE);                     \
686     return NULL;                                                        \
687   FE_                                                                   \
688 }
689 */
690 /* -----------------------------------------------------------------------------
691    Dummy return closure
692  
693    Entering this closure will just return to the address on the top of the
694    stack.  Useful for getting a thread in a canonical form where we can
695    just enter the top stack word to start the thread.  (see deleteThread)
696  * -------------------------------------------------------------------------- */
697
698 INFO_TABLE(stg_dummy_ret_info, stg_dummy_ret_entry, 0, 0, CONSTR_NOCAF_STATIC, , EF_, 0, 0);
699 STGFUN(stg_dummy_ret_entry)
700 {
701   W_ ret_addr;
702   FB_
703   ret_addr = Sp[0];
704   Sp++;
705   JMP_(ENTRY_CODE(ret_addr));
706   FE_
707 }
708 SET_STATIC_HDR(stg_dummy_ret_closure,stg_dummy_ret_info,CCS_DONT_CARE,,EI_)
709 , /*payload*/{} };
710
711 /* -----------------------------------------------------------------------------
712     Strict IO application - performing an IO action and entering its result.
713     
714     rts_evalIO() lets you perform Haskell IO actions from outside of Haskell-land,
715     returning back to you their result. Want this result to be evaluated to WHNF
716     by that time, so that we can easily get at the int/char/whatever using the
717     various get{Ty} functions provided by the RTS API.
718
719     forceIO takes care of this, performing the IO action and entering the
720     results that comes back.
721
722  * -------------------------------------------------------------------------- */
723
724 #ifdef REG_R1
725 INFO_TABLE_SRT_BITMAP(stg_forceIO_ret_info,stg_forceIO_ret_entry,0,0,0,0,RET_SMALL,,EF_,0,0);
726 STGFUN(stg_forceIO_ret_entry)
727 {
728   FB_
729   Sp++;
730   Sp -= sizeofW(StgSeqFrame);
731   PUSH_SEQ_FRAME(Sp);
732   JMP_(GET_ENTRY(R1.cl));
733 }
734 #else
735 INFO_TABLE_SRT_BITMAP(stg_forceIO_ret_info,stg_forceIO_ret_entry,0,0,0,0,RET_SMALL,,EF_,0,0);
736 STGFUN(forceIO_ret_entry)
737 {
738   StgClosure *rval;
739   FB_
740   rval = (StgClosure *)Sp[0];
741   Sp += 2;
742   Sp -= sizeofW(StgSeqFrame);
743   PUSH_SEQ_FRAME(Sp);
744   R1.cl = rval;
745   JMP_(GET_ENTRY(R1.cl));
746 }
747 #endif
748
749 INFO_TABLE(stg_forceIO_info,stg_forceIO_entry,1,0,FUN_STATIC,,EF_,0,0);
750 FN_(stg_forceIO_entry)
751 {
752   FB_
753   /* Sp[0] contains the IO action we want to perform */
754   R1.p  = (P_)Sp[0];
755   /* Replace it with the return continuation that enters the result. */
756   Sp[0] = (W_)&stg_forceIO_ret_info;
757   Sp--;
758   /* Push the RealWorld# tag and enter */
759   Sp[0] =(W_)REALWORLD_TAG;
760   JMP_(GET_ENTRY(R1.cl));
761   FE_
762 }
763 SET_STATIC_HDR(stg_forceIO_closure,stg_forceIO_info,CCS_DONT_CARE,,EI_)
764 , /*payload*/{} };
765
766
767 /* -----------------------------------------------------------------------------
768    CHARLIKE and INTLIKE closures.  
769
770    These are static representations of Chars and small Ints, so that
771    we can remove dynamic Chars and Ints during garbage collection and
772    replace them with references to the static objects.
773    -------------------------------------------------------------------------- */
774
775 #if defined(INTERPRETER) || defined(ENABLE_WIN32_DLL_SUPPORT)
776 /*
777  * When sticking the RTS in a DLL, we delay populating the
778  * Charlike and Intlike tables until load-time, which is only
779  * when we've got the real addresses to the C# and I# closures.
780  *
781  */
782 static INFO_TBL_CONST StgInfoTable czh_static_info;
783 static INFO_TBL_CONST StgInfoTable izh_static_info;
784 #define Char_hash_static_info czh_static_info
785 #define Int_hash_static_info izh_static_info
786 #else
787 #define Char_hash_static_info PrelBase_Czh_static_info
788 #define Int_hash_static_info PrelBase_Izh_static_info
789 #endif
790
791 #define CHARLIKE_HDR(n)                                         \
792         {                                                       \
793           STATIC_HDR(Char_hash_static_info, /* C# */            \
794                          CCS_DONT_CARE),                        \
795           data : n                                              \
796         }
797                                              
798 #define INTLIKE_HDR(n)                                          \
799         {                                                       \
800           STATIC_HDR(Int_hash_static_info,  /* I# */            \
801                          CCS_DONT_CARE),                        \
802           data : n                                              \
803         }
804
805 /* put these in the *data* section, since the garbage collector relies
806  * on the fact that static closures live in the data section.
807  */
808
809 /* end the name with _closure, to convince the mangler this is a closure */
810
811 StgIntCharlikeClosure stg_CHARLIKE_closure[] = {
812     CHARLIKE_HDR(0),
813     CHARLIKE_HDR(1),
814     CHARLIKE_HDR(2),
815     CHARLIKE_HDR(3),
816     CHARLIKE_HDR(4),
817     CHARLIKE_HDR(5),
818     CHARLIKE_HDR(6),
819     CHARLIKE_HDR(7),
820     CHARLIKE_HDR(8),
821     CHARLIKE_HDR(9),
822     CHARLIKE_HDR(10),
823     CHARLIKE_HDR(11),
824     CHARLIKE_HDR(12),
825     CHARLIKE_HDR(13),
826     CHARLIKE_HDR(14),
827     CHARLIKE_HDR(15),
828     CHARLIKE_HDR(16),
829     CHARLIKE_HDR(17),
830     CHARLIKE_HDR(18),
831     CHARLIKE_HDR(19),
832     CHARLIKE_HDR(20),
833     CHARLIKE_HDR(21),
834     CHARLIKE_HDR(22),
835     CHARLIKE_HDR(23),
836     CHARLIKE_HDR(24),
837     CHARLIKE_HDR(25),
838     CHARLIKE_HDR(26),
839     CHARLIKE_HDR(27),
840     CHARLIKE_HDR(28),
841     CHARLIKE_HDR(29),
842     CHARLIKE_HDR(30),
843     CHARLIKE_HDR(31),
844     CHARLIKE_HDR(32),
845     CHARLIKE_HDR(33),
846     CHARLIKE_HDR(34),
847     CHARLIKE_HDR(35),
848     CHARLIKE_HDR(36),
849     CHARLIKE_HDR(37),
850     CHARLIKE_HDR(38),
851     CHARLIKE_HDR(39),
852     CHARLIKE_HDR(40),
853     CHARLIKE_HDR(41),
854     CHARLIKE_HDR(42),
855     CHARLIKE_HDR(43),
856     CHARLIKE_HDR(44),
857     CHARLIKE_HDR(45),
858     CHARLIKE_HDR(46),
859     CHARLIKE_HDR(47),
860     CHARLIKE_HDR(48),
861     CHARLIKE_HDR(49),
862     CHARLIKE_HDR(50),
863     CHARLIKE_HDR(51),
864     CHARLIKE_HDR(52),
865     CHARLIKE_HDR(53),
866     CHARLIKE_HDR(54),
867     CHARLIKE_HDR(55),
868     CHARLIKE_HDR(56),
869     CHARLIKE_HDR(57),
870     CHARLIKE_HDR(58),
871     CHARLIKE_HDR(59),
872     CHARLIKE_HDR(60),
873     CHARLIKE_HDR(61),
874     CHARLIKE_HDR(62),
875     CHARLIKE_HDR(63),
876     CHARLIKE_HDR(64),
877     CHARLIKE_HDR(65),
878     CHARLIKE_HDR(66),
879     CHARLIKE_HDR(67),
880     CHARLIKE_HDR(68),
881     CHARLIKE_HDR(69),
882     CHARLIKE_HDR(70),
883     CHARLIKE_HDR(71),
884     CHARLIKE_HDR(72),
885     CHARLIKE_HDR(73),
886     CHARLIKE_HDR(74),
887     CHARLIKE_HDR(75),
888     CHARLIKE_HDR(76),
889     CHARLIKE_HDR(77),
890     CHARLIKE_HDR(78),
891     CHARLIKE_HDR(79),
892     CHARLIKE_HDR(80),
893     CHARLIKE_HDR(81),
894     CHARLIKE_HDR(82),
895     CHARLIKE_HDR(83),
896     CHARLIKE_HDR(84),
897     CHARLIKE_HDR(85),
898     CHARLIKE_HDR(86),
899     CHARLIKE_HDR(87),
900     CHARLIKE_HDR(88),
901     CHARLIKE_HDR(89),
902     CHARLIKE_HDR(90),
903     CHARLIKE_HDR(91),
904     CHARLIKE_HDR(92),
905     CHARLIKE_HDR(93),
906     CHARLIKE_HDR(94),
907     CHARLIKE_HDR(95),
908     CHARLIKE_HDR(96),
909     CHARLIKE_HDR(97),
910     CHARLIKE_HDR(98),
911     CHARLIKE_HDR(99),
912     CHARLIKE_HDR(100),
913     CHARLIKE_HDR(101),
914     CHARLIKE_HDR(102),
915     CHARLIKE_HDR(103),
916     CHARLIKE_HDR(104),
917     CHARLIKE_HDR(105),
918     CHARLIKE_HDR(106),
919     CHARLIKE_HDR(107),
920     CHARLIKE_HDR(108),
921     CHARLIKE_HDR(109),
922     CHARLIKE_HDR(110),
923     CHARLIKE_HDR(111),
924     CHARLIKE_HDR(112),
925     CHARLIKE_HDR(113),
926     CHARLIKE_HDR(114),
927     CHARLIKE_HDR(115),
928     CHARLIKE_HDR(116),
929     CHARLIKE_HDR(117),
930     CHARLIKE_HDR(118),
931     CHARLIKE_HDR(119),
932     CHARLIKE_HDR(120),
933     CHARLIKE_HDR(121),
934     CHARLIKE_HDR(122),
935     CHARLIKE_HDR(123),
936     CHARLIKE_HDR(124),
937     CHARLIKE_HDR(125),
938     CHARLIKE_HDR(126),
939     CHARLIKE_HDR(127),
940     CHARLIKE_HDR(128),
941     CHARLIKE_HDR(129),
942     CHARLIKE_HDR(130),
943     CHARLIKE_HDR(131),
944     CHARLIKE_HDR(132),
945     CHARLIKE_HDR(133),
946     CHARLIKE_HDR(134),
947     CHARLIKE_HDR(135),
948     CHARLIKE_HDR(136),
949     CHARLIKE_HDR(137),
950     CHARLIKE_HDR(138),
951     CHARLIKE_HDR(139),
952     CHARLIKE_HDR(140),
953     CHARLIKE_HDR(141),
954     CHARLIKE_HDR(142),
955     CHARLIKE_HDR(143),
956     CHARLIKE_HDR(144),
957     CHARLIKE_HDR(145),
958     CHARLIKE_HDR(146),
959     CHARLIKE_HDR(147),
960     CHARLIKE_HDR(148),
961     CHARLIKE_HDR(149),
962     CHARLIKE_HDR(150),
963     CHARLIKE_HDR(151),
964     CHARLIKE_HDR(152),
965     CHARLIKE_HDR(153),
966     CHARLIKE_HDR(154),
967     CHARLIKE_HDR(155),
968     CHARLIKE_HDR(156),
969     CHARLIKE_HDR(157),
970     CHARLIKE_HDR(158),
971     CHARLIKE_HDR(159),
972     CHARLIKE_HDR(160),
973     CHARLIKE_HDR(161),
974     CHARLIKE_HDR(162),
975     CHARLIKE_HDR(163),
976     CHARLIKE_HDR(164),
977     CHARLIKE_HDR(165),
978     CHARLIKE_HDR(166),
979     CHARLIKE_HDR(167),
980     CHARLIKE_HDR(168),
981     CHARLIKE_HDR(169),
982     CHARLIKE_HDR(170),
983     CHARLIKE_HDR(171),
984     CHARLIKE_HDR(172),
985     CHARLIKE_HDR(173),
986     CHARLIKE_HDR(174),
987     CHARLIKE_HDR(175),
988     CHARLIKE_HDR(176),
989     CHARLIKE_HDR(177),
990     CHARLIKE_HDR(178),
991     CHARLIKE_HDR(179),
992     CHARLIKE_HDR(180),
993     CHARLIKE_HDR(181),
994     CHARLIKE_HDR(182),
995     CHARLIKE_HDR(183),
996     CHARLIKE_HDR(184),
997     CHARLIKE_HDR(185),
998     CHARLIKE_HDR(186),
999     CHARLIKE_HDR(187),
1000     CHARLIKE_HDR(188),
1001     CHARLIKE_HDR(189),
1002     CHARLIKE_HDR(190),
1003     CHARLIKE_HDR(191),
1004     CHARLIKE_HDR(192),
1005     CHARLIKE_HDR(193),
1006     CHARLIKE_HDR(194),
1007     CHARLIKE_HDR(195),
1008     CHARLIKE_HDR(196),
1009     CHARLIKE_HDR(197),
1010     CHARLIKE_HDR(198),
1011     CHARLIKE_HDR(199),
1012     CHARLIKE_HDR(200),
1013     CHARLIKE_HDR(201),
1014     CHARLIKE_HDR(202),
1015     CHARLIKE_HDR(203),
1016     CHARLIKE_HDR(204),
1017     CHARLIKE_HDR(205),
1018     CHARLIKE_HDR(206),
1019     CHARLIKE_HDR(207),
1020     CHARLIKE_HDR(208),
1021     CHARLIKE_HDR(209),
1022     CHARLIKE_HDR(210),
1023     CHARLIKE_HDR(211),
1024     CHARLIKE_HDR(212),
1025     CHARLIKE_HDR(213),
1026     CHARLIKE_HDR(214),
1027     CHARLIKE_HDR(215),
1028     CHARLIKE_HDR(216),
1029     CHARLIKE_HDR(217),
1030     CHARLIKE_HDR(218),
1031     CHARLIKE_HDR(219),
1032     CHARLIKE_HDR(220),
1033     CHARLIKE_HDR(221),
1034     CHARLIKE_HDR(222),
1035     CHARLIKE_HDR(223),
1036     CHARLIKE_HDR(224),
1037     CHARLIKE_HDR(225),
1038     CHARLIKE_HDR(226),
1039     CHARLIKE_HDR(227),
1040     CHARLIKE_HDR(228),
1041     CHARLIKE_HDR(229),
1042     CHARLIKE_HDR(230),
1043     CHARLIKE_HDR(231),
1044     CHARLIKE_HDR(232),
1045     CHARLIKE_HDR(233),
1046     CHARLIKE_HDR(234),
1047     CHARLIKE_HDR(235),
1048     CHARLIKE_HDR(236),
1049     CHARLIKE_HDR(237),
1050     CHARLIKE_HDR(238),
1051     CHARLIKE_HDR(239),
1052     CHARLIKE_HDR(240),
1053     CHARLIKE_HDR(241),
1054     CHARLIKE_HDR(242),
1055     CHARLIKE_HDR(243),
1056     CHARLIKE_HDR(244),
1057     CHARLIKE_HDR(245),
1058     CHARLIKE_HDR(246),
1059     CHARLIKE_HDR(247),
1060     CHARLIKE_HDR(248),
1061     CHARLIKE_HDR(249),
1062     CHARLIKE_HDR(250),
1063     CHARLIKE_HDR(251),
1064     CHARLIKE_HDR(252),
1065     CHARLIKE_HDR(253),
1066     CHARLIKE_HDR(254),
1067     CHARLIKE_HDR(255)
1068 };
1069
1070 StgIntCharlikeClosure stg_INTLIKE_closure[] = {
1071     INTLIKE_HDR(-16),   /* MIN_INTLIKE == -16 */
1072     INTLIKE_HDR(-15),
1073     INTLIKE_HDR(-14),
1074     INTLIKE_HDR(-13),
1075     INTLIKE_HDR(-12),
1076     INTLIKE_HDR(-11),
1077     INTLIKE_HDR(-10),
1078     INTLIKE_HDR(-9),
1079     INTLIKE_HDR(-8),
1080     INTLIKE_HDR(-7),
1081     INTLIKE_HDR(-6),
1082     INTLIKE_HDR(-5),
1083     INTLIKE_HDR(-4),
1084     INTLIKE_HDR(-3),
1085     INTLIKE_HDR(-2),
1086     INTLIKE_HDR(-1),
1087     INTLIKE_HDR(0),
1088     INTLIKE_HDR(1),
1089     INTLIKE_HDR(2),
1090     INTLIKE_HDR(3),
1091     INTLIKE_HDR(4),
1092     INTLIKE_HDR(5),
1093     INTLIKE_HDR(6),
1094     INTLIKE_HDR(7),
1095     INTLIKE_HDR(8),
1096     INTLIKE_HDR(9),
1097     INTLIKE_HDR(10),
1098     INTLIKE_HDR(11),
1099     INTLIKE_HDR(12),
1100     INTLIKE_HDR(13),
1101     INTLIKE_HDR(14),
1102     INTLIKE_HDR(15),
1103     INTLIKE_HDR(16)     /* MAX_INTLIKE == 16 */
1104 };