[project @ 2004-08-13 10:45:16 by simonmar]
[ghc-hetmet.git] / ghc / rts / StgMiscClosures.hc
index a2de22c..8bf5dbb 100644 (file)
@@ -1,17 +1,17 @@
 /* -----------------------------------------------------------------------------
- * $Id: StgMiscClosures.hc,v 1.50 2000/11/13 14:40:37 simonmar Exp $
+ * $Id: StgMiscClosures.hc,v 1.85 2003/05/14 09:14:00 simonmar Exp $
  *
- * (c) The GHC Team, 1998-2000
+ * (c) The GHC Team, 1998-2002
  *
  * Entry code for various built-in closure types.
  *
  * ---------------------------------------------------------------------------*/
 
+#include "Stg.h"
 #include "Rts.h"
 #include "RtsUtils.h"
 #include "RtsFlags.h"
 #include "StgMiscClosures.h"
-#include "HeapStackCheck.h"   /* for stg_gen_yield */
 #include "Storage.h"
 #include "StoragePriv.h"
 #include "Profiling.h"
@@ -23,8 +23,8 @@
 # include "StgRun.h"   /* for StgReturn and register saving */
 #endif
 
-#ifdef HAVE_STDIO_H
-#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
 #endif
 
 /* ToDo: make the printing of panics more win32-friendly, i.e.,
   Template for the entry code of non-enterable closures.
 */
 
-#define NON_ENTERABLE_ENTRY_CODE(type)                                 \
-STGFUN(stg_##type##_entry)                                                     \
-{                                                                      \
-  FB_                                                                  \
-    DUMP_ERRMSG(#type " object entered!\n");                            \
-    STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE);                    \
-    return NULL;                                                       \
-  FE_                                                                  \
+#define NON_ENTERABLE_ENTRY_CODE(type)         \
+IF_(stg_##type##_entry)                        \
+{                                              \
+  FB_                                          \
+    STGCALL1(barf, #type " object entered!");  \
+  FE_                                          \
 }
 
 
 /* -----------------------------------------------------------------------------
-   Support for the metacircular interpreter.
+   Support for the bytecode interpreter.
    -------------------------------------------------------------------------- */
 
-#ifdef GHCI
-
-/* 9 bits of return code for constructors created by mci_make_constr. */
-FN_(stg_mci_constr_entry) 
+/* 9 bits of return code for constructors created by the interpreter. */
+FN_(stg_interp_constr_entry) 
 { 
   /* R1 points at the constructor */
   FB_ 
-    STGCALL2(fprintf,stderr,"mci_constr_entry (direct return)!\n");
+    /* STGCALL2(fprintf,stderr,"stg_interp_constr_entry (direct return)!\n"); */
     /* Pointless, since SET_TAG doesn't do anything */
     SET_TAG( GET_TAG(GET_INFO(R1.cl))); 
     JMP_(ENTRY_CODE((P_)(*Sp))); 
   FE_ 
 }
 
-FN_(stg_mci_constr1_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),0)); FE_ }
-FN_(stg_mci_constr2_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),1)); FE_ }
-FN_(stg_mci_constr3_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),2)); FE_ }
-FN_(stg_mci_constr4_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),3)); FE_ }
-FN_(stg_mci_constr5_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),4)); FE_ }
-FN_(stg_mci_constr6_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),5)); FE_ }
-FN_(stg_mci_constr7_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),6)); FE_ }
-FN_(stg_mci_constr8_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),7)); FE_ }
+FN_(stg_interp_constr1_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),0)); FE_ }
+FN_(stg_interp_constr2_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),1)); FE_ }
+FN_(stg_interp_constr3_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),2)); FE_ }
+FN_(stg_interp_constr4_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),3)); FE_ }
+FN_(stg_interp_constr5_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),4)); FE_ }
+FN_(stg_interp_constr6_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),5)); FE_ }
+FN_(stg_interp_constr7_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),6)); FE_ }
+FN_(stg_interp_constr8_entry) { FB_ JMP_(RET_VEC((P_)(*Sp),7)); FE_ }
  
+/* Some info tables to be used when compiled code returns a value to
+   the interpreter, i.e. the interpreter pushes one of these onto the
+   stack before entering a value.  What the code does is to
+   impedance-match the compiled return convention (in R1p/R1n/F1/D1 etc) to
+   the interpreter's convention (returned value is on top of stack),
+   and then cause the scheduler to enter the interpreter.
 
-/* Since this stuff is ostensibly in some other module, we need
-   to supply an __init_ function.
-*/
-EF_(__init_MCIzumakezuconstr);
-START_MOD_INIT(__init_MCIzumakezuconstr)
-END_MOD_INIT()
-
+   On entry, the stack (growing down) looks like this:
 
-INFO_TABLE(mci_make_constr_info,   mci_make_constr_entry,   0,0,FUN_STATIC,static,EF_,0,0);
-INFO_TABLE(mci_make_constrI_info,  mci_make_constrI_entry,  0,0,FUN_STATIC,static,EF_,0,0);
-INFO_TABLE(mci_make_constrP_info,  mci_make_constrP_entry,  0,0,FUN_STATIC,static,EF_,0,0);
-INFO_TABLE(mci_make_constrPP_info, mci_make_constrPP_entry, 0,0,FUN_STATIC,static,EF_,0,0);
-INFO_TABLE(mci_make_constrPPP_info,mci_make_constrPPP_entry,0,0,FUN_STATIC,static,EF_,0,0);
-
-SET_STATIC_HDR(MCIzumakezuconstr_mcizumakezuconstr_closure,
-               mci_make_constr_info,0,,EI_)
-   ,{ /* payload */ }
-};
-SET_STATIC_HDR(MCIzumakezuconstr_mcizumakezuconstrI_closure,
-               mci_make_constrI_info,0,,EI_)
-   ,{ /* payload */ }
-};
-SET_STATIC_HDR(MCIzumakezuconstr_mcizumakezuconstrP_closure,
-               mci_make_constrP_info,0,,EI_)
-   ,{ /* payload */ }
-};
-SET_STATIC_HDR(MCIzumakezuconstr_mcizumakezuconstrPP_closure,
-               mci_make_constrPP_info,0,,EI_)
-   ,{ /* payload */ }
-};
-SET_STATIC_HDR(MCIzumakezuconstr_mcizumakezuconstrPPP_closure,
-               mci_make_constrPPP_info,0,,EI_)
-   ,{ /* payload */ }
-};
+      ptr to BCO holding return continuation
+      ptr to one of these info tables.
+   The info table code, both direct and vectored, must:
+      * push R1/F1/D1 on the stack, and its tag if necessary
+      * push the BCO (so it's now on the stack twice)
+      * Yield, ie, go to the scheduler.
+
+   Scheduler examines the t.o.s, discovers it is a BCO, and proceeds
+   directly to the bytecode interpreter.  That pops the top element
+   (the BCO, containing the return continuation), and interprets it.
+   Net result: return continuation gets interpreted, with the
+   following stack:
+
+      ptr to this BCO
+      ptr to the info table just jumped thru
+      return value
+
+   which is just what we want -- the "standard" return layout for the
+   interpreter.  Hurrah!
+
+   Don't ask me how unboxed tuple returns are supposed to work.  We
+   haven't got a good story about that yet.
+*/
 
+// When the returned value is a pointer in R1...
+#define STG_CtoI_RET_R1p_Template(label)       \
+   IF_(label)                                  \
+   {                                           \
+      FB_                                      \
+      Sp -= 2;                                 \
+      Sp[1] = R1.w;                            \
+      Sp[0] = (W_)&stg_enter_info;             \
+      JMP_(stg_yield_to_interpreter);          \
+      FE_                                      \
+   }
 
-/* Make a constructor with no args. */
-STGFUN(mci_make_constr_entry)
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_0_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_1_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_2_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_3_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_4_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_5_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_6_ret);
+STG_CtoI_RET_R1p_Template(stg_ctoi_ret_R1p_7_ret);
+
+VEC_POLY_INFO_TABLE( stg_ctoi_ret_R1p, 0/* special layout */,
+                    0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, 
+                    RET_BCO,, EF_);
+
+// When the returned value is a pointer, but unlifted, in R1 ...
+INFO_TABLE_RET( stg_ctoi_ret_R1unpt_info, stg_ctoi_ret_R1unpt_entry,
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_ctoi_ret_R1unpt_entry)
 {
-  nat size, np, nw;
-  StgClosure* con;
-  StgInfoTable* itbl;
-  FB_
-    /* Sp[0 & 1] are tag, Addr#
-    */
-    itbl = ((StgInfoTable**)Sp)[1];
-    np   = INFO_PTR_TO_STRUCT(itbl)->layout.payload.ptrs;
-    nw   = INFO_PTR_TO_STRUCT(itbl)->layout.payload.nptrs;
-    size = sizeofW(StgHeader) + stg_max(MIN_NONUPD_SIZE, np+nw);
-    /* STGCALL5(fprintf,stderr,"np %d  nw %d  size %d\n",np,nw,size); */
-
-    /* The total number of words to copy off the stack is np + nw.
-       That doesn't include tag words, tho.
-    */
-    HP_CHK_GEN_TICKY(size, NO_PTRS, mci_make_constr_entry, );
-    TICK_ALLOC_PRIM(sizeofW(StgHeader), size-sizeofW(StgHeader), 0);
-    CCS_ALLOC(CCCS,size); /* ccs prof */
-
-    con = (StgClosure*)(Hp + 1 - size);
-    SET_HDR(con, itbl,CCCS);
-
-    Sp = Sp +2; /* Zap the Addr# arg */
-    R1.cl = con;
-
-    JMP_(ENTRY_CODE(GET_INFO(R1.cl)));
-  FE_
+   FB_
+   Sp -= 2;
+   Sp[1] = R1.w;
+   Sp[0] = (W_)&stg_gc_unpt_r1_info;
+   JMP_(stg_yield_to_interpreter);
+   FE_
 }
 
-/* Make a constructor with 1 Int# arg */
-STGFUN(mci_make_constrI_entry)
+// When the returned value is a non-pointer in R1 ...
+INFO_TABLE_RET( stg_ctoi_ret_R1n_info, stg_ctoi_ret_R1n_entry,
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_ctoi_ret_R1n_entry)
 {
-  nat size, np, nw;
-  StgClosure* con;
-  StgInfoTable* itbl;
-  FB_
-    /* Sp[0 & 1] are tag, Addr#
-       Sp[2 & 3] are tag, Int#
-    */
-    itbl = ((StgInfoTable**)Sp)[1];
-    np   = INFO_PTR_TO_STRUCT(itbl)->layout.payload.ptrs;
-    nw   = INFO_PTR_TO_STRUCT(itbl)->layout.payload.nptrs;
-    size = sizeofW(StgHeader) + stg_max(MIN_NONUPD_SIZE, np+nw);
-    /* STGCALL5(fprintf,stderr,"np %d  nw %d  size %d\n",np,nw,size); */
-
-    /* The total number of words to copy off the stack is np + nw.
-       That doesn't include tag words, tho.
-    */
-    HP_CHK_GEN_TICKY(size, NO_PTRS, mci_make_constrI_entry, );
-    TICK_ALLOC_PRIM(sizeofW(StgHeader), size-sizeofW(StgHeader), 0);
-    CCS_ALLOC(CCCS,size); /* ccs prof */
-
-    con = (StgClosure*)(Hp + 1 - size);
-    SET_HDR(con, itbl,CCCS);
-
-    con->payload[0] = ((StgClosure**)Sp)[3];
-    Sp = Sp +1/*word*/ +1/*tag*/;  /* Zap the Int# arg */
-    Sp = Sp +2; /* Zap the Addr# arg */
-    R1.cl = con;
-
-    JMP_(ENTRY_CODE(GET_INFO(R1.cl)));
-  FE_
+   FB_
+   Sp -= 2;
+   Sp[1] = R1.w;
+   Sp[0] = (W_)&stg_gc_unbx_r1_info;
+   JMP_(stg_yield_to_interpreter);
+   FE_
 }
 
-STGFUN(mci_make_constrP_entry)
+
+// When the returned value is in F1 ...
+INFO_TABLE_RET( stg_ctoi_ret_F1_info, stg_ctoi_ret_F1_entry, 
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_ctoi_ret_F1_entry)
 {
-  FB_
-  DUMP_ERRMSG("mci_make_constrP_entry: unimplemented!\n");
-  STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE);
-  return 0;
-  FE_
+   FB_
+   Sp -= 2;
+   ASSIGN_FLT(Sp+1, F1);
+   Sp[0] = (W_)&stg_gc_f1_info;
+   JMP_(stg_yield_to_interpreter);
+   FE_
 }
 
-
-/* Make a constructor with 2 pointer args. */
-STGFUN(mci_make_constrPP_entry)
+// When the returned value is in D1 ...
+INFO_TABLE_RET( stg_ctoi_ret_D1_info, stg_ctoi_ret_D1_entry,
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_ctoi_ret_D1_entry)
 {
-  nat size, np, nw;
-  StgClosure* con;
-  StgInfoTable* itbl;
-  FB_
-    /* Sp[0 & 1] are tag, Addr#
-       Sp[2]     first arg
-       Sp[3]     second arg
-    */
-    itbl = ((StgInfoTable**)Sp)[1];
-    np   = INFO_PTR_TO_STRUCT(itbl)->layout.payload.ptrs;
-    nw   = INFO_PTR_TO_STRUCT(itbl)->layout.payload.nptrs;
-    size = sizeofW(StgHeader) + stg_max(MIN_NONUPD_SIZE, np+nw);
-    /* STGCALL5(fprintf,stderr,"np %d  nw %d  size %d\n",np,nw,size); */
-
-    /* The total number of words to copy off the stack is np + nw.
-       That doesn't include tag words, tho.
-    */
-    HP_CHK_GEN_TICKY(size, NO_PTRS, mci_make_constrPP_entry, );
-    TICK_ALLOC_PRIM(sizeofW(StgHeader), size-sizeofW(StgHeader), 0);
-    CCS_ALLOC(CCCS,size); /* ccs prof */
-
-    con = (StgClosure*)(Hp + 1 - size);
-    SET_HDR(con, itbl,CCCS);
-
-    con->payload[0] = ((StgClosure**)Sp)[2];
-    con->payload[1] = ((StgClosure**)Sp)[3];
-    Sp = Sp +2; /* Zap 2 ptr args */
-    Sp = Sp +2; /* Zap the Addr# arg */
-    R1.cl = con;
-
-    JMP_(ENTRY_CODE(GET_INFO(R1.cl)));
-  FE_
+   FB_
+   Sp -= 1 + sizeofW(StgDouble);
+   ASSIGN_DBL(Sp+1, D1);
+   Sp[0] = (W_)&stg_gc_d1_info;
+   JMP_(stg_yield_to_interpreter);
+   FE_
 }
 
+// When the returned value is in L1 ...
+INFO_TABLE_RET( stg_ctoi_ret_L1_info, stg_ctoi_ret_L1_entry,
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_ctoi_ret_L1_entry)
+{
+   FB_
+   Sp -= 1 + sizeofW(StgInt64);
+   ASSIGN_Word64(Sp+1, L1);
+   Sp[0] = (W_)&stg_gc_l1_info;
+   JMP_(stg_yield_to_interpreter);
+   FE_
+}
 
-STGFUN(mci_make_constrPPP_entry)
+// When the returned value a VoidRep ...
+INFO_TABLE_RET( stg_ctoi_ret_V_info, stg_ctoi_ret_V_entry,
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_ctoi_ret_V_entry)
 {
-  FB_
-  DUMP_ERRMSG("mci_make_constrPPP_entry: unimplemented!\n");
-  STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE);
-  return 0;
-  FE_
+   FB_
+   Sp--;
+   Sp[0] = (W_)&stg_gc_void_info;
+   JMP_(stg_yield_to_interpreter);
+   FE_
 }
 
-#if 0
-/* It would be nice if this worked, but it doesn't.  Yet. */
-STGFUN(mci_make_constr_entry)
+// Dummy info table pushed on the top of the stack when the interpreter
+// should apply the BCO on the stack to its arguments, also on the stack.
+INFO_TABLE_RET( stg_apply_interp_info, stg_apply_interp_entry,
+               0/* special layout */,
+               0/*srt*/, 0/*srt_off*/, 0/*srt_bitmap*/, RET_BCO,, IF_, 0, 0);
+IF_(stg_apply_interp_entry)
 {
-  nat size, np, nw_heap, nw_really, w;
-  StgClosure* con;
-  StgInfoTable* itbl;
-  W_* r;
-  FB_
-    itbl      = ((StgInfoTable**)Sp)[0];
-STGCALL3(fprintf,stderr,"mmc: itbl = %d\n",itbl);
-
-STGCALL3(fprintf,stderr,"mmc: sp-4 = %d\n", ((W_*)Sp)[-4] );
-STGCALL3(fprintf,stderr,"mmc: sp-3 = %d\n", ((W_*)Sp)[-3] );
-STGCALL3(fprintf,stderr,"mmc: sp-2 = %d\n", ((W_*)Sp)[-2] );
-STGCALL3(fprintf,stderr,"mmc: sp-1 = %d\n", ((W_*)Sp)[-1] );
-STGCALL3(fprintf,stderr,"mmc: sp+0 = %d\n", ((W_*)Sp)[0] );
-STGCALL3(fprintf,stderr,"mmc: sp+1 = %d\n", ((W_*)Sp)[1] );
-STGCALL3(fprintf,stderr,"mmc: sp+2 = %d\n", ((W_*)Sp)[2] );
-STGCALL3(fprintf,stderr,"mmc: sp+3 = %d\n", ((W_*)Sp)[3] );
-STGCALL3(fprintf,stderr,"mmc: sp+4 = %d\n", ((W_*)Sp)[4] );
-    np        = itbl->layout.payload.ptrs;
-    nw_really = itbl->layout.payload.nptrs;
-    nw_heap   = stg_max(nw_really, MIN_NONUPD_SIZE-np);
-    size      = CONSTR_sizeW( np, nw_heap );
-
-    /* The total number of words to copy off the stack is np + nw.
-       That doesn't include tag words, tho.
-    */
-    HP_CHK_GEN_TICKY(size, NO_PTRS, mci_make_constr_entry, );
-    TICK_ALLOC_PRIM(sizeofW(StgHeader), size-sizeofW(StgHeader), 0);
-    CCS_ALLOC(CCCS,size); /* ccs prof */
-
-    con = (StgClosure*)(Hp + 1 - size);
-    SET_HDR(con, itbl,CCCS);
-
-    /* Copy into the closure. */
-    w = 0;
-    r = Sp+1;
-    while (1) {
-       if (w == np + nw) break;
-       ASSERT(w < np + nw);
-       if (IS_ARG_TAG(*r)) { 
-          nat n = *r++;
-          for (; n > 0; n--)
-             con->payload[w++] = (StgClosure*)(*r++);
-       } else {
-          con->payload[w++] = (StgClosure*)(*r++);
-       }
-       ASSERT((P_)r <= (P_)Su);
-    }
+    FB_
+    // Just in case we end up in here... (we shouldn't)
+    JMP_(stg_yield_to_interpreter);
+    FE_
+}
 
-    /* Remove all the args we've used. */
-    Sp = r;
+/* -----------------------------------------------------------------------------
+   Entry code for a BCO
+   -------------------------------------------------------------------------- */
 
-    R1.cl = con;
-    JMP_(ENTRY_CODE(R1.cl));
+INFO_TABLE_FUN_GEN(stg_BCO_info,stg_BCO_entry,4,0,
+             0,0,0,  /* no SRT */
+             ARG_BCO, 0/*dummy arity*/, 0/*dummy bitmap*/, NULL/*slow_apply*/,
+             BCO,,EF_,"BCO","BCO");
+FN_(stg_BCO_entry) {
+  FB_
+  // entering a BCO means "apply it", same as a function
+  Sp -= 2;
+  Sp[1] = R1.w;
+  Sp[0] = (W_)&stg_apply_interp_info;
+  JMP_(stg_yield_to_interpreter);
   FE_
 }
-#endif
-
-#endif /* GHCI */
-
 
 /* -----------------------------------------------------------------------------
-   Entry code for an indirection.
+   Info tables for indirections.
+
+   SPECIALISED INDIRECTIONS: we have a specialised indirection for each
+   kind of return (direct, vectored 0-7), so that we can avoid entering
+   the object when we know what kind of return it will do.  The update
+   code (Updates.hc) updates objects with the appropriate kind of
+   indirection.  We only do this for young-gen indirections.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_IND_info,stg_IND_entry,1,0,IND,,EF_,0,0);
-STGFUN(stg_IND_entry)
+INFO_TABLE(stg_IND_info,stg_IND_entry,1,0,IND,,IF_,"IND","IND");
+IF_(stg_IND_entry)
 {
     FB_
-    TICK_ENT_IND(Node);        /* tick */
-
+    TICK_ENT_DYN_IND(Node);    /* tick */
     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
     TICK_ENT_VIA_NODE();
-    JMP_(ENTRY_CODE(*R1.p));
+    JMP_(GET_ENTRY(R1.cl));
     FE_
 }
 
-INFO_TABLE(stg_IND_STATIC_info,stg_IND_STATIC_entry,1,0,IND_STATIC,,EF_,0,0);
-STGFUN(stg_IND_STATIC_entry)
+#define IND_SPEC(n,ret) \
+INFO_TABLE(stg_IND_##n##_info,stg_IND_##n##_entry,1,0,IND,,IF_,"IND","IND"); \
+IF_(stg_IND_##n##_entry)                       \
+{                                              \
+    FB_                                                \
+    TICK_ENT_DYN_IND(Node);    /* tick */      \
+    R1.p = (P_) ((StgInd*)R1.p)->indirectee;   \
+    TICK_ENT_VIA_NODE();                       \
+    JMP_(ret);                                 \
+    FE_                                                \
+}
+
+IND_SPEC(direct, ENTRY_CODE(Sp[0]))
+IND_SPEC(0, RET_VEC(Sp[0],0))
+IND_SPEC(1, RET_VEC(Sp[0],1))
+IND_SPEC(2, RET_VEC(Sp[0],2))
+IND_SPEC(3, RET_VEC(Sp[0],3))
+IND_SPEC(4, RET_VEC(Sp[0],4))
+IND_SPEC(5, RET_VEC(Sp[0],5))
+IND_SPEC(6, RET_VEC(Sp[0],6))
+IND_SPEC(7, RET_VEC(Sp[0],7))
+
+INFO_TABLE(stg_IND_STATIC_info,stg_IND_STATIC_entry,1,0,IND_STATIC,,IF_,"IND_STATIC","IND_STATIC");
+IF_(stg_IND_STATIC_entry)
 {
     FB_
-    TICK_ENT_IND(Node);        /* tick */
+    TICK_ENT_STATIC_IND(Node); /* tick */
     R1.p = (P_) ((StgIndStatic*)R1.p)->indirectee;
     TICK_ENT_VIA_NODE();
-    JMP_(ENTRY_CODE(*R1.p));
+    JMP_(GET_ENTRY(R1.cl));
     FE_
 }
 
-INFO_TABLE(stg_IND_PERM_info,stg_IND_PERM_entry,1,1,IND_PERM,,EF_,"IND_PERM","IND_PERM");
-STGFUN(stg_IND_PERM_entry)
+INFO_TABLE(stg_IND_PERM_info,stg_IND_PERM_entry,1,1,IND_PERM,,IF_,"IND_PERM","IND_PERM");
+IF_(stg_IND_PERM_entry)
 {
     FB_
     /* Don't add INDs to granularity cost */
-    /* Dont: TICK_ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
+    /* Dont: TICK_ENT_STATIC_IND(Node); for ticky-ticky; this ind is here only to help profiling */
 
 #if defined(TICKY_TICKY) && !defined(PROFILING)
     /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra  */
     TICK_ENT_PERM_IND(R1.p); /* tick */
 #endif
 
+    LDV_ENTER((StgInd *)R1.p);
+
     /* Enter PAP cost centre -- lexical scoping only */
     ENTER_CCS_PAP_CL(R1.cl);
 
@@ -353,7 +328,7 @@ STGFUN(stg_IND_PERM_entry)
 #  ifdef PROFILING
 #    error Profiling and ticky-ticky do not mix at present!
 #  endif  /* PROFILING */
-    SET_INFO((StgInd*)R1.p,&IND_info);
+    SET_INFO((StgInd*)R1.p,&stg_IND_info);
 #endif /* TICKY_TICKY */
 
     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
@@ -364,33 +339,34 @@ STGFUN(stg_IND_PERM_entry)
     TICK_ENT_VIA_NODE();
 #endif
 
-    JMP_(ENTRY_CODE(*R1.p));
+    JMP_(GET_ENTRY(R1.cl));
     FE_
 }  
 
-INFO_TABLE(stg_IND_OLDGEN_info,stg_IND_OLDGEN_entry,1,1,IND_OLDGEN,,EF_,0,0);
-STGFUN(stg_IND_OLDGEN_entry)
+INFO_TABLE(stg_IND_OLDGEN_info,stg_IND_OLDGEN_entry,1,1,IND_OLDGEN,,IF_,"IND_OLDGEN","IND_OLDGEN");
+IF_(stg_IND_OLDGEN_entry)
 {
     FB_
-    TICK_ENT_IND(Node);        /* tick */
-  
+    TICK_ENT_STATIC_IND(Node); /* tick */
     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
     TICK_ENT_VIA_NODE();
-    JMP_(ENTRY_CODE(*R1.p));
+    JMP_(GET_ENTRY(R1.cl));
     FE_
 }
 
-INFO_TABLE(stg_IND_OLDGEN_PERM_info,stg_IND_OLDGEN_PERM_entry,1,1,IND_OLDGEN_PERM,,EF_,0,0);
-STGFUN(stg_IND_OLDGEN_PERM_entry)
+INFO_TABLE(stg_IND_OLDGEN_PERM_info,stg_IND_OLDGEN_PERM_entry,1,1,IND_OLDGEN_PERM,,IF_,"IND_OLDGEN_PERM","IND_OLDGEN_PERM");
+IF_(stg_IND_OLDGEN_PERM_entry)
 {
     FB_
-    /* Dont: TICK_ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
+    /* Dont: TICK_ENT_STATIC_IND(Node); for ticky-ticky; this ind is here only to help profiling */
 
 #if defined(TICKY_TICKY) && !defined(PROFILING)
     /* TICKY_TICKY && !PROFILING means PERM_IND *replaces* an IND, rather than being extra  */
     TICK_ENT_PERM_IND(R1.p); /* tick */
 #endif
-  
+
+    LDV_ENTER((StgInd *)R1.p);
+
     /* Enter PAP cost centre -- lexical scoping only */
     ENTER_CCS_PAP_CL(R1.cl);
 
@@ -399,39 +375,11 @@ STGFUN(stg_IND_OLDGEN_PERM_entry)
 #  ifdef PROFILING
 #    error Profiling and ticky-ticky do not mix at present!
 #  endif  /* PROFILING */
-    SET_INFO((StgInd*)R1.p,&IND_OLDGEN_info);
+    SET_INFO((StgInd*)R1.p,&stg_IND_OLDGEN_info);
 #endif /* TICKY_TICKY */
 
     R1.p = (P_) ((StgInd*)R1.p)->indirectee;
     TICK_ENT_VIA_NODE();
-    JMP_(ENTRY_CODE(*R1.p));
-    FE_
-}
-
-/* -----------------------------------------------------------------------------
-   Entry code for CAFs
-
-   This code assumes R1 is in a register for now.
-   -------------------------------------------------------------------------- */
-
-INFO_TABLE(stg_CAF_UNENTERED_info,stg_CAF_UNENTERED_entry,1,3,CAF_UNENTERED,,EF_,0,0);
-STGFUN(stg_CAF_UNENTERED_entry)
-{
-    FB_
-    /* ToDo: implement directly in GHC */
-    Sp -= 1;
-    Sp[0] = R1.w;
-    JMP_(stg_yield_to_Hugs);
-    FE_
-}
-
-/* 0,4 is entirely bogus; _do not_ rely on this info */
-INFO_TABLE(stg_CAF_ENTERED_info,stg_CAF_ENTERED_entry,0,4,CAF_ENTERED,,EF_,0,0);
-STGFUN(stg_CAF_ENTERED_entry)
-{
-    FB_
-    R1.p = (P_) ((StgCAF*)R1.p)->value; /* just a fancy indirection */
-    TICK_ENT_VIA_NODE();
     JMP_(GET_ENTRY(R1.cl));
     FE_
 }
@@ -452,8 +400,8 @@ STGFUN(stg_CAF_ENTERED_entry)
  * old-generation indirection. 
  */
 
-INFO_TABLE(stg_BLACKHOLE_info, stg_BLACKHOLE_entry,0,2,BLACKHOLE,,EF_,"BLACKHOLE","BLACKHOLE");
-STGFUN(stg_BLACKHOLE_entry)
+INFO_TABLE(stg_BLACKHOLE_info, stg_BLACKHOLE_entry,0,2,BLACKHOLE,,IF_,"BLACKHOLE","BLACKHOLE");
+IF_(stg_BLACKHOLE_entry)
 {
   FB_
 #if defined(GRAN)
@@ -464,9 +412,9 @@ STGFUN(stg_BLACKHOLE_entry)
 #ifdef SMP
     {
       bdescr *bd = Bdescr(R1.p);
-      if (bd->back != (bdescr *)BaseReg) {
-       if (bd->gen->no >= 1 || bd->step->no >= 1) {
-         CMPXCHG(R1.cl->header.info, &BLACKHOLE_info, &WHITEHOLE_info);
+      if (bd->u.back != (bdescr *)BaseReg) {
+       if (bd->gen_no >= 1 || bd->step->no >= 1) {
+         CMPXCHG(R1.cl->header.info, &stg_BLACKHOLE_info, &stg_WHITEHOLE_info);
        } else {
          EXTFUN_RTS(stg_gc_enter_1_hponly);
          JMP_(stg_gc_enter_1_hponly);
@@ -476,33 +424,48 @@ STGFUN(stg_BLACKHOLE_entry)
 #endif
     TICK_ENT_BH();
 
+    // Actually this is not necessary because R1.p is about to be destroyed.
+    LDV_ENTER((StgClosure *)R1.p);
+
     /* Put ourselves on the blocking queue for this black hole */
 #if defined(GRAN) || defined(PAR)
-    /* in fact, only difference is the type of the end-of-queue marker! */
+    // in fact, only difference is the type of the end-of-queue marker!
     CurrentTSO->link = END_BQ_QUEUE;
     ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO;
 #else
     CurrentTSO->link = END_TSO_QUEUE;
     ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
 #endif
-    /* jot down why and on what closure we are blocked */
+    // jot down why and on what closure we are blocked
     CurrentTSO->why_blocked = BlockedOnBlackHole;
     CurrentTSO->block_info.closure = R1.cl;
-    /* closure is mutable since something has just been added to its BQ */
-    recordMutable((StgMutClosure *)R1.cl);
+
     /* Change the BLACKHOLE into a BLACKHOLE_BQ */
+#ifdef PROFILING
+
+    // The size remains the same, so we call LDV_recordDead() - no need to fill slop.
+    LDV_recordDead((StgClosure *)R1.p, BLACKHOLE_sizeW());
+#endif
+    // 
+    // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
+    // 
     ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
+#ifdef PROFILING
+    LDV_recordCreate((StgClosure *)R1.p);
+#endif
 
-    /* PAR: dumping of event now done in blockThread -- HWL */
+    // closure is mutable since something has just been added to its BQ
+    recordMutable((StgMutClosure *)R1.cl);
 
-    /* stg_gen_block is too heavyweight, use a specialised one */
-    BLOCK_NP(1);
+    // PAR: dumping of event now done in blockThread -- HWL
 
+    // stg_gen_block is too heavyweight, use a specialised one
+    BLOCK_NP(1);
   FE_
 }
 
-INFO_TABLE(stg_BLACKHOLE_BQ_info, stg_BLACKHOLE_BQ_entry,1,1,BLACKHOLE_BQ,,EF_,"BLACKHOLE","BLACKHOLE");
-STGFUN(stg_BLACKHOLE_BQ_entry)
+INFO_TABLE(stg_BLACKHOLE_BQ_info, stg_BLACKHOLE_BQ_entry,1,1,BLACKHOLE_BQ,,IF_,"BLACKHOLE","BLACKHOLE");
+IF_(stg_BLACKHOLE_BQ_entry)
 {
   FB_
 #if defined(GRAN)
@@ -513,9 +476,9 @@ STGFUN(stg_BLACKHOLE_BQ_entry)
 #ifdef SMP
     {
       bdescr *bd = Bdescr(R1.p);
-      if (bd->back != (bdescr *)BaseReg) {
-       if (bd->gen->no >= 1 || bd->step->no >= 1) {
-         CMPXCHG(R1.cl->header.info, &BLACKHOLE_info, &WHITEHOLE_info);
+      if (bd->u.back != (bdescr *)BaseReg) {
+       if (bd->gen_no >= 1 || bd->step->no >= 1) {
+         CMPXCHG(R1.cl->header.info, &stg_BLACKHOLE_info, &stg_WHITEHOLE_info);
        } else {
          EXTFUN_RTS(stg_gc_enter_1_hponly);
          JMP_(stg_gc_enter_1_hponly);
@@ -525,6 +488,7 @@ STGFUN(stg_BLACKHOLE_BQ_entry)
 #endif
 
     TICK_ENT_BH();
+    LDV_ENTER((StgClosure *)R1.p);
 
     /* Put ourselves on the blocking queue for this black hole */
     CurrentTSO->link = ((StgBlockingQueue *)R1.p)->blocking_queue;
@@ -557,8 +521,8 @@ STGFUN(stg_BLACKHOLE_BQ_entry)
 
 #if defined(PAR) || defined(GRAN)
 
-INFO_TABLE(stg_RBH_info, stg_RBH_entry,1,1,RBH,,EF_,0,0);
-STGFUN(stg_RBH_entry)
+INFO_TABLE(stg_RBH_info, stg_RBH_entry,1,1,RBH,,IF_,"RBH","RBH");
+IF_(stg_RBH_entry)
 {
   FB_
 # if defined(GRAN)
@@ -581,19 +545,19 @@ STGFUN(stg_RBH_entry)
   FE_
 }
 
-INFO_TABLE(RBH_Save_0_info, RBH_Save_0_entry,0,2,CONSTR,,EF_,0,0);
+INFO_TABLE(stg_RBH_Save_0_info, stg_RBH_Save_0_entry,0,2,CONSTR,,IF_,"RBH_Save_0","RBH_Save_0");
 NON_ENTERABLE_ENTRY_CODE(RBH_Save_0);
 
-INFO_TABLE(RBH_Save_1_info, RBH_Save_1_entry,1,1,CONSTR,,EF_,0,0);
+INFO_TABLE(stg_RBH_Save_1_info, stg_RBH_Save_1_entry,1,1,CONSTR,,IF_,"RBH_Save_1","RBH_Save_1");
 NON_ENTERABLE_ENTRY_CODE(RBH_Save_1);
 
-INFO_TABLE(RBH_Save_2_info, RBH_Save_2_entry,2,0,CONSTR,,EF_,0,0);
+INFO_TABLE(stg_RBH_Save_2_info, stg_RBH_Save_2_entry,2,0,CONSTR,,IF_,"RBH_Save_2","RBH_Save_2");
 NON_ENTERABLE_ENTRY_CODE(RBH_Save_2);
 #endif /* defined(PAR) || defined(GRAN) */
 
 /* identical to BLACKHOLEs except for the infotag */
-INFO_TABLE(CAF_BLACKHOLE_info, CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,,EF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
-STGFUN(stg_CAF_BLACKHOLE_entry)
+INFO_TABLE(stg_CAF_BLACKHOLE_info, stg_CAF_BLACKHOLE_entry,0,2,CAF_BLACKHOLE,,IF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
+IF_(stg_CAF_BLACKHOLE_entry)
 {
   FB_
 #if defined(GRAN)
@@ -604,9 +568,9 @@ STGFUN(stg_CAF_BLACKHOLE_entry)
 #ifdef SMP
     {
       bdescr *bd = Bdescr(R1.p);
-      if (bd->back != (bdescr *)BaseReg) {
-       if (bd->gen->no >= 1 || bd->step->no >= 1) {
-         CMPXCHG(R1.cl->header.info, &CAF_BLACKHOLE_info, &WHITEHOLE_info);
+      if (bd->u.back != (bdescr *)BaseReg) {
+       if (bd->gen_no >= 1 || bd->step->no >= 1) {
+         CMPXCHG(R1.cl->header.info, &stg_CAF_BLACKHOLE_info, &stg_WHITEHOLE_info);
        } else {
          EXTFUN_RTS(stg_gc_enter_1_hponly);
          JMP_(stg_gc_enter_1_hponly);
@@ -616,34 +580,37 @@ STGFUN(stg_CAF_BLACKHOLE_entry)
 #endif
 
     TICK_ENT_BH();
+    LDV_ENTER((StgClosure *)R1.p);
 
-    /* Put ourselves on the blocking queue for this black hole */
+    // Put ourselves on the blocking queue for this black hole
 #if defined(GRAN) || defined(PAR)
-    /* in fact, only difference is the type of the end-of-queue marker! */
+    // in fact, only difference is the type of the end-of-queue marker!
     CurrentTSO->link = END_BQ_QUEUE;
     ((StgBlockingQueue *)R1.p)->blocking_queue = (StgBlockingQueueElement *)CurrentTSO;
 #else
     CurrentTSO->link = END_TSO_QUEUE;
     ((StgBlockingQueue *)R1.p)->blocking_queue = CurrentTSO;
 #endif
-    /* jot down why and on what closure we are blocked */
+    // jot down why and on what closure we are blocked
     CurrentTSO->why_blocked = BlockedOnBlackHole;
     CurrentTSO->block_info.closure = R1.cl;
-    /* closure is mutable since something has just been added to its BQ */
-    recordMutable((StgMutClosure *)R1.cl);
-    /* Change the CAF_BLACKHOLE into a BLACKHOLE_BQ */
+
+    // Change the CAF_BLACKHOLE into a BLACKHOLE_BQ_STATIC
     ((StgBlockingQueue *)R1.p)->header.info = &stg_BLACKHOLE_BQ_info;
 
-    /* PAR: dumping of event now done in blockThread -- HWL */
+    // closure is mutable since something has just been added to its BQ
+    recordMutable((StgMutClosure *)R1.cl);
 
-    /* stg_gen_block is too heavyweight, use a specialised one */
+    // PAR: dumping of event now done in blockThread -- HWL
+
+    // stg_gen_block is too heavyweight, use a specialised one
     BLOCK_NP(1);
   FE_
 }
 
-#ifdef TICKY_TICKY
-INFO_TABLE(stg_SE_BLACKHOLE_info, stg_SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,EF_,0,0);
-STGFUN(stg_SE_BLACKHOLE_entry)
+#ifdef EAGER_BLACKHOLING
+INFO_TABLE(stg_SE_BLACKHOLE_info, stg_SE_BLACKHOLE_entry,0,2,SE_BLACKHOLE,,IF_,"SE_BLACKHOLE","SE_BLACKHOLE");
+IF_(stg_SE_BLACKHOLE_entry)
 {
   FB_
     STGCALL3(fprintf,stderr,"SE_BLACKHOLE at %p entered!\n",R1.p);
@@ -651,8 +618,8 @@ STGFUN(stg_SE_BLACKHOLE_entry)
   FE_
 }
 
-INFO_TABLE(SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,EF_,0,0);
-STGFUN(stg_SE_CAF_BLACKHOLE_entry)
+INFO_TABLE(stg_SE_CAF_BLACKHOLE_info, SE_CAF_BLACKHOLE_entry,0,2,SE_CAF_BLACKHOLE,,IF_,"CAF_BLACKHOLE","CAF_BLACKHOLE");
+IF_(stg_SE_CAF_BLACKHOLE_entry)
 {
   FB_
     STGCALL3(fprintf,stderr,"SE_CAF_BLACKHOLE at %p entered!\n",R1.p);
@@ -662,34 +629,22 @@ STGFUN(stg_SE_CAF_BLACKHOLE_entry)
 #endif
 
 #ifdef SMP
-INFO_TABLE(stg_WHITEHOLE_info, stg_WHITEHOLE_entry,0,2,CONSTR_NOCAF_STATIC,,EF_,0,0);
-STGFUN(stg_WHITEHOLE_entry)
+INFO_TABLE(stg_WHITEHOLE_info, stg_WHITEHOLE_entry,0,2,CONSTR_NOCAF_STATIC,,IF_,"WHITEHOLE","WHITEHOLE");
+IF_(stg_WHITEHOLE_entry)
 {
   FB_
-     JMP_(GET_ENTRY(R1.cl));
+    JMP_(GET_ENTRY(R1.cl));
   FE_
 }
 #endif
 
 /* -----------------------------------------------------------------------------
-   The code for a BCO returns to the scheduler
-   -------------------------------------------------------------------------- */
-INFO_TABLE(stg_BCO_info,stg_BCO_entry,0,0,BCO,,EF_,"BCO","BCO");
-STGFUN(stg_BCO_entry) {                                
-  FB_  
-    Sp -= 1;
-    Sp[0] = R1.w;
-    JMP_(stg_yield_to_Hugs);
-  FE_                                                          
-}
-
-/* -----------------------------------------------------------------------------
    Some static info tables for things that don't get entered, and
    therefore don't need entry code (i.e. boxed but unpointed objects)
    NON_ENTERABLE_ENTRY_CODE now defined at the beginning of the file
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_TSO_info, stg_TSO_entry, 0,0,TSO,,EF_,"TSO","TSO");
+INFO_TABLE(stg_TSO_info, stg_TSO_entry, 0,0,TSO,,IF_,"TSO","TSO");
 NON_ENTERABLE_ENTRY_CODE(TSO);
 
 /* -----------------------------------------------------------------------------
@@ -697,7 +652,7 @@ NON_ENTERABLE_ENTRY_CODE(TSO);
    one is a real bug.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_EVACUATED_info,stg_EVACUATED_entry,1,0,EVACUATED,,EF_,0,0);
+INFO_TABLE(stg_EVACUATED_info,stg_EVACUATED_entry,1,0,EVACUATED,,IF_,"EVACUATED","EVACUATED");
 NON_ENTERABLE_ENTRY_CODE(EVACUATED);
 
 /* -----------------------------------------------------------------------------
@@ -708,10 +663,15 @@ NON_ENTERABLE_ENTRY_CODE(EVACUATED);
    live weak pointers with dead ones).
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_WEAK_info,stg_WEAK_entry,0,4,WEAK,,EF_,"WEAK","WEAK");
+INFO_TABLE(stg_WEAK_info,stg_WEAK_entry,0,4,WEAK,,IF_,"WEAK","WEAK");
 NON_ENTERABLE_ENTRY_CODE(WEAK);
 
-INFO_TABLE_CONSTR(stg_DEAD_WEAK_info,stg_DEAD_WEAK_entry,0,1,0,CONSTR,,EF_,"DEAD_WEAK","DEAD_WEAK");
+// It's important when turning an existing WEAK into a DEAD_WEAK
+// (which is what finalizeWeak# does) that we don't lose the link
+// field and break the linked list of weak pointers.  Hence, we give
+// DEAD_WEAK 4 non-pointer fields, the same as WEAK.
+
+INFO_TABLE_CONSTR(stg_DEAD_WEAK_info,stg_DEAD_WEAK_entry,0,4,0,CONSTR,,IF_,"DEAD_WEAK","DEAD_WEAK");
 NON_ENTERABLE_ENTRY_CODE(DEAD_WEAK);
 
 /* -----------------------------------------------------------------------------
@@ -721,24 +681,24 @@ NON_ENTERABLE_ENTRY_CODE(DEAD_WEAK);
    finalizer in a weak pointer object.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE_CONSTR(stg_NO_FINALIZER_info,stg_NO_FINALIZER_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
+INFO_TABLE_CONSTR(stg_NO_FINALIZER_info,stg_NO_FINALIZER_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"NO_FINALIZER","NO_FINALIZER");
 NON_ENTERABLE_ENTRY_CODE(NO_FINALIZER);
 
-SET_STATIC_HDR(stg_NO_FINALIZER_closure,NO_FINALIZER_info,0/*CC*/,,EI_)
+SET_STATIC_HDR(stg_NO_FINALIZER_closure,stg_NO_FINALIZER_info,0/*CC*/,,extern const StgInfoTable)
 , /*payload*/{} };
 
 /* -----------------------------------------------------------------------------
    Foreign Objects are unlifted and therefore never entered.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_FOREIGN_info,stg_FOREIGN_entry,0,1,FOREIGN,,EF_,"FOREIGN","FOREIGN");
+INFO_TABLE(stg_FOREIGN_info,stg_FOREIGN_entry,0,1,FOREIGN,,IF_,"FOREIGN","FOREIGN");
 NON_ENTERABLE_ENTRY_CODE(FOREIGN);
 
 /* -----------------------------------------------------------------------------
    Stable Names are unlifted too.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_STABLE_NAME_info,stg_STABLE_NAME_entry,0,1,STABLE_NAME,,EF_,"STABLE_NAME","STABLE_NAME");
+INFO_TABLE(stg_STABLE_NAME_info,stg_STABLE_NAME_entry,0,1,STABLE_NAME,,IF_,"STABLE_NAME","STABLE_NAME");
 NON_ENTERABLE_ENTRY_CODE(STABLE_NAME);
 
 /* -----------------------------------------------------------------------------
@@ -748,10 +708,10 @@ NON_ENTERABLE_ENTRY_CODE(STABLE_NAME);
    and entry code for each type.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_FULL_MVAR_info,stg_FULL_MVAR_entry,4,0,MVAR,,EF_,"MVAR","MVAR");
+INFO_TABLE(stg_FULL_MVAR_info,stg_FULL_MVAR_entry,4,0,MVAR,,IF_,"MVAR","MVAR");
 NON_ENTERABLE_ENTRY_CODE(FULL_MVAR);
 
-INFO_TABLE(stg_EMPTY_MVAR_info,stg_EMPTY_MVAR_entry,4,0,MVAR,,EF_,"MVAR","MVAR");
+INFO_TABLE(stg_EMPTY_MVAR_info,stg_EMPTY_MVAR_entry,4,0,MVAR,,IF_,"MVAR","MVAR");
 NON_ENTERABLE_ENTRY_CODE(EMPTY_MVAR);
 
 /* -----------------------------------------------------------------------------
@@ -761,10 +721,10 @@ NON_ENTERABLE_ENTRY_CODE(EMPTY_MVAR);
    end of a linked TSO queue.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE_CONSTR(stg_END_TSO_QUEUE_info,stg_END_TSO_QUEUE_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
+INFO_TABLE_CONSTR(stg_END_TSO_QUEUE_info,stg_END_TSO_QUEUE_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"END_TSO_QUEUE","END_TSO_QUEUE");
 NON_ENTERABLE_ENTRY_CODE(END_TSO_QUEUE);
 
-SET_STATIC_HDR(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE_info,0/*CC*/,,EI_)
+SET_STATIC_HDR(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE_info,0/*CC*/,,extern const StgInfoTable)
 , /*payload*/{} };
 
 /* -----------------------------------------------------------------------------
@@ -775,26 +735,26 @@ SET_STATIC_HDR(stg_END_TSO_QUEUE_closure,stg_END_TSO_QUEUE_info,0/*CC*/,,EI_)
    an END_MUT_LIST closure.
    -------------------------------------------------------------------------- */
 
-INFO_TABLE_CONSTR(stg_END_MUT_LIST_info,stg_END_MUT_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
+INFO_TABLE_CONSTR(stg_END_MUT_LIST_info,stg_END_MUT_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"END_MUT_LIST","END_MUT_LIST");
 NON_ENTERABLE_ENTRY_CODE(END_MUT_LIST);
 
-SET_STATIC_HDR(stg_END_MUT_LIST_closure,stg_END_MUT_LIST_info,0/*CC*/,,EI_)
+SET_STATIC_HDR(stg_END_MUT_LIST_closure,stg_END_MUT_LIST_info,0/*CC*/,,extern const StgInfoTable)
 , /*payload*/{} };
 
-INFO_TABLE(stg_MUT_CONS_info, stg_MUT_CONS_entry, 1, 1, MUT_VAR, , EF_, 0, 0);
+INFO_TABLE(stg_MUT_CONS_info, stg_MUT_CONS_entry, 1, 1, MUT_CONS, , IF_, "MUT_CONS", "MUT_CONS");
 NON_ENTERABLE_ENTRY_CODE(MUT_CONS);
 
 /* -----------------------------------------------------------------------------
    Exception lists
    -------------------------------------------------------------------------- */
 
-INFO_TABLE_CONSTR(stg_END_EXCEPTION_LIST_info,stg_END_EXCEPTION_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,EF_,0,0);
+INFO_TABLE_CONSTR(stg_END_EXCEPTION_LIST_info,stg_END_EXCEPTION_LIST_entry,0,0,0,CONSTR_NOCAF_STATIC,,IF_,"END_EXCEPTION_LIST","END_EXCEPTION_LIST");
 NON_ENTERABLE_ENTRY_CODE(END_EXCEPTION_LIST);
 
-SET_STATIC_HDR(stg_END_EXCEPTION_LIST_closure,stg_END_EXCEPTION_LIST_info,0/*CC*/,,EI_)
+SET_STATIC_HDR(stg_END_EXCEPTION_LIST_closure,stg_END_EXCEPTION_LIST_info,0/*CC*/,,extern const StgInfoTable)
 , /*payload*/{} };
 
-INFO_TABLE(stg_EXCEPTION_CONS_info, stg_EXCEPTION_CONS_entry, 1, 1, CONSTR, , EF_, 0, 0);
+INFO_TABLE(stg_EXCEPTION_CONS_info, stg_EXCEPTION_CONS_entry, 1, 1, CONSTR, , IF_, "EXCEPTION_CONS", "EXCEPTION_CONS");
 NON_ENTERABLE_ENTRY_CODE(EXCEPTION_CONS);
 
 /* -----------------------------------------------------------------------------
@@ -813,7 +773,7 @@ NON_ENTERABLE_ENTRY_CODE(EXCEPTION_CONS);
    -------------------------------------------------------------------------- */
 
 #define ArrayInfo(type)                                        \
-INFO_TABLE(stg_##type##_info, stg_##type##_entry, 0, 0, type, , EF_,"" # type "","" # type "");
+INFO_TABLE(stg_##type##_info, stg_##type##_entry, 0, 0, type, , IF_,"" # type "","" # type "");
 
 ArrayInfo(ARR_WORDS);
 NON_ENTERABLE_ENTRY_CODE(ARR_WORDS);
@@ -828,27 +788,10 @@ NON_ENTERABLE_ENTRY_CODE(MUT_ARR_PTRS_FROZEN);
    Mutable Variables
    -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_MUT_VAR_info, stg_MUT_VAR_entry, 1, 1, MUT_VAR, , EF_, "MUT_VAR", "MUT_VAR");
+INFO_TABLE(stg_MUT_VAR_info, stg_MUT_VAR_entry, 1, 1, MUT_VAR, , IF_, "MUT_VAR", "MUT_VAR");
 NON_ENTERABLE_ENTRY_CODE(MUT_VAR);
 
 /* -----------------------------------------------------------------------------
-   Standard Error Entry.
-
-   This is used for filling in vector-table entries that can never happen,
-   for instance.
-   -------------------------------------------------------------------------- */
-/* No longer used; we use NULL, because a) it never happens, right? and b)
-   Windows doesn't like DLL entry points being used as static initialisers
-STGFUN(stg_error_entry)                                                        \
-{                                                                      \
-  FB_                                                                  \
-    DUMP_ERRMSG("fatal: stg_error_entry");                              \
-    STGCALL1(shutdownHaskellAndExit, EXIT_FAILURE);                    \
-    return NULL;                                                       \
-  FE_                                                                  \
-}
-*/
-/* -----------------------------------------------------------------------------
    Dummy return closure
  
    Entering this closure will just return to the address on the top of the
@@ -856,111 +799,18 @@ STGFUN(stg_error_entry)                                                  \
    just enter the top stack word to start the thread.  (see deleteThread)
  * -------------------------------------------------------------------------- */
 
-INFO_TABLE(stg_dummy_ret_info, stg_dummy_ret_entry, 0, 0, CONSTR_NOCAF_STATIC, , EF_, 0, 0);
-STGFUN(stg_dummy_ret_entry)
-{
-  W_ ret_addr;
-  FB_
-  ret_addr = Sp[0];
-  Sp++;
-  JMP_(ENTRY_CODE(ret_addr));
-  FE_
-}
-SET_STATIC_HDR(stg_dummy_ret_closure,stg_dummy_ret_info,CCS_DONT_CARE,,EI_)
-, /*payload*/{} };
-
-/* -----------------------------------------------------------------------------
-    Strict IO application - performing an IO action and entering its result.
-    
-    rts_evalIO() lets you perform Haskell IO actions from outside of Haskell-land,
-    returning back to you their result. Want this result to be evaluated to WHNF
-    by that time, so that we can easily get at the int/char/whatever using the
-    various get{Ty} functions provided by the RTS API.
-
-    forceIO takes care of this, performing the IO action and entering the
-    results that comes back.
-
- * -------------------------------------------------------------------------- */
-
-#ifdef REG_R1
-INFO_TABLE_SRT_BITMAP(stg_forceIO_ret_info,stg_forceIO_ret_entry,0,0,0,0,RET_SMALL,,EF_,0,0);
-STGFUN(stg_forceIO_ret_entry)
-{
-  FB_
-  Sp++;
-  Sp -= sizeofW(StgSeqFrame);
-  PUSH_SEQ_FRAME(Sp);
-  JMP_(GET_ENTRY(R1.cl));
-}
-#else
-INFO_TABLE_SRT_BITMAP(stg_forceIO_ret_info,stg_forceIO_ret_entry,0,0,0,0,RET_SMALL,,EF_,0,0);
-STGFUN(forceIO_ret_entry)
-{
-  StgClosure *rval;
-  FB_
-  rval = (StgClosure *)Sp[0];
-  Sp += 2;
-  Sp -= sizeofW(StgSeqFrame);
-  PUSH_SEQ_FRAME(Sp);
-  R1.cl = rval;
-  JMP_(GET_ENTRY(R1.cl));
-}
-#endif
+INFO_TABLE( stg_dummy_ret_info, stg_dummy_ret_entry, 
+           0, 0, CONSTR_NOCAF_STATIC, , EF_, "DUMMY_RET", "DUMMY_RET");
 
-INFO_TABLE(stg_forceIO_info,stg_forceIO_entry,1,0,FUN_STATIC,,EF_,0,0);
-FN_(stg_forceIO_entry)
+STGFUN(stg_dummy_ret_entry)
 {
   FB_
-  /* Sp[0] contains the IO action we want to perform */
-  R1.p  = (P_)Sp[0];
-  /* Replace it with the return continuation that enters the result. */
-  Sp[0] = (W_)&stg_forceIO_ret_info;
-  Sp--;
-  /* Push the RealWorld# tag and enter */
-  Sp[0] =(W_)REALWORLD_TAG;
-  JMP_(GET_ENTRY(R1.cl));
+  JMP_(ENTRY_CODE(Sp[0]));
   FE_
 }
-SET_STATIC_HDR(stg_forceIO_closure,stg_forceIO_info,CCS_DONT_CARE,,EI_)
+SET_STATIC_HDR(stg_dummy_ret_closure,stg_dummy_ret_info,CCS_DONT_CARE,,extern const StgInfoTable)
 , /*payload*/{} };
 
-
-/* -----------------------------------------------------------------------------
-   Standard Infotables (for use in interpreter)
-   -------------------------------------------------------------------------- */
-
-#ifdef INTERPRETER
-
-STGFUN(stg_Hugs_CONSTR_entry)
-{
-    /* R1 points at the constructor */
-    JMP_(ENTRY_CODE(((StgPtr*)Sp)[0]));
-}
-
-#define RET_BCO_ENTRY_TEMPLATE(label)  \
-   IFN_(label)                         \
-   {                                    \
-      FB_                              \
-      Sp -= 1;                         \
-      ((StgPtr*)Sp)[0] = R1.p;         \
-      JMP_(stg_yield_to_Hugs);          \
-      FE_                               \
-   }
-
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_entry  );
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_0_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_1_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_2_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_3_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_4_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_5_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_6_entry);
-RET_BCO_ENTRY_TEMPLATE(stg_ret_bco_7_entry);
-
-VEC_POLY_INFO_TABLE(stg_ret_bco,0, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, RET_BCO,, EF_);
-
-#endif /* INTERPRETER */
-
 /* -----------------------------------------------------------------------------
    CHARLIKE and INTLIKE closures.  
 
@@ -981,8 +831,8 @@ static INFO_TBL_CONST StgInfoTable izh_static_info;
 #define Char_hash_static_info czh_static_info
 #define Int_hash_static_info izh_static_info
 #else
-#define Char_hash_static_info PrelBase_Czh_static_info
-#define Int_hash_static_info PrelBase_Izh_static_info
+#define Char_hash_static_info GHCziBase_Czh_static_info
+#define Int_hash_static_info GHCziBase_Izh_static_info
 #endif
 
 #define CHARLIKE_HDR(n)                                                \