[project @ 2001-08-03 15:05:52 by sewardj]
[ghc-hetmet.git] / ghc / rts / Interpreter.c
index 7187b60..c249c76 100644 (file)
@@ -5,12 +5,10 @@
  * Copyright (c) 1994-2000.
  *
  * $RCSfile: Interpreter.c,v $
- * $Revision: 1.7 $
- * $Date: 2001/01/03 16:44:30 $
+ * $Revision: 1.26 $
+ * $Date: 2001/08/03 15:05:52 $
  * ---------------------------------------------------------------------------*/
 
-#ifdef GHCI
-
 #include "Rts.h"
 #include "RtsAPI.h"
 #include "RtsUtils.h"
  * The new bytecode interpreter
  * ------------------------------------------------------------------------*/
 
-/* Sp points to the lowest live word on the stack. */
+/* The interpreter can be compiled so it just interprets BCOs and
+   hands literally everything else to the scheduler.  This gives a
+   "reference interpreter" which is correct but slow -- useful for
+   debugging.  By default, we handle certain closures specially so as
+   to dramatically cut down on the number of deferrals to the
+   scheduler.  Ie normally you don't want REFERENCE_INTERPRETER to be
+   defined. */
+
+/* #define REFERENCE_INTERPRETER */
+
+/* Gather stats about entry, opcode, opcode-pair frequencies.  For
+   tuning the interpreter. */
+
+/* #define INTERP_STATS */
+
+
+
+/* iSp points to the lowest live word on the stack. */
 
 #define StackWord(n)  iSp[n]
 #define BCO_NEXT      instrs[bciPtr++]
    SAVE_STACK_POINTERS; return retcode;
 
 
+static __inline__ StgPtr allocate_UPD ( int n_words )
+{
+   if (n_words - sizeofW(StgHeader) < MIN_UPD_SIZE)
+      n_words = MIN_UPD_SIZE + sizeofW(StgHeader);
+   return allocate(n_words);
+}
+
+static __inline__ StgPtr allocate_NONUPD ( int n_words )
+{
+   if (n_words - sizeofW(StgHeader) < MIN_NONUPD_SIZE)
+      n_words = MIN_NONUPD_SIZE + sizeofW(StgHeader);
+   return allocate(n_words);
+}
+
+
+#ifdef INTERP_STATS
+/* Hacky stats, for tuning the interpreter ... */
+int it_unknown_entries[N_CLOSURE_TYPES];
+int it_total_unknown_entries;
+int it_total_entries;
+
+int it_retto_BCO;
+int it_retto_UPDATE;
+int it_retto_other;
+
+int it_slides;
+int it_insns;
+int it_BCO_entries;
+
+int it_ofreq[27];
+int it_oofreq[27][27];
+int it_lastopc;
+
+void interp_startup ( void )
+{
+   int i, j;
+   it_retto_BCO = it_retto_UPDATE = it_retto_other = 0;
+   it_total_entries = it_total_unknown_entries = 0;
+   for (i = 0; i < N_CLOSURE_TYPES; i++)
+      it_unknown_entries[i] = 0;
+   it_slides = it_insns = it_BCO_entries = 0;
+   for (i = 0; i < 27; i++) it_ofreq[i] = 0;
+   for (i = 0; i < 27; i++) 
+     for (j = 0; j < 27; j++)
+        it_oofreq[i][j] = 0;
+   it_lastopc = 0;
+}
+
+void interp_shutdown ( void )
+{
+   int i, j, k, o_max, i_max, j_max;
+   fprintf(stderr, "%d constrs entered -> (%d BCO, %d UPD, %d ??? )\n",
+                   it_retto_BCO + it_retto_UPDATE + it_retto_other,
+                   it_retto_BCO, it_retto_UPDATE, it_retto_other );
+   fprintf(stderr, "%d total entries, %d unknown entries \n", 
+                   it_total_entries, it_total_unknown_entries);
+   for (i = 0; i < N_CLOSURE_TYPES; i++) {
+     if (it_unknown_entries[i] == 0) continue;
+     fprintf(stderr, "   type %2d: unknown entries (%4.1f%%) == %d\n",
+            i, 100.0 * ((double)it_unknown_entries[i]) / 
+                        ((double)it_total_unknown_entries),
+             it_unknown_entries[i]);
+   }
+   fprintf(stderr, "%d insns, %d slides, %d BCO_entries\n", 
+                   it_insns, it_slides, it_BCO_entries);
+   for (i = 0; i < 27; i++) 
+      fprintf(stderr, "opcode %2d got %d\n", i, it_ofreq[i] );
+
+   for (k = 1; k < 20; k++) {
+      o_max = 0;
+      i_max = j_max = 0;
+      for (i = 0; i < 27; i++) {
+         for (j = 0; j < 27; j++) {
+           if (it_oofreq[i][j] > o_max) {
+               o_max = it_oofreq[i][j];
+              i_max = i; j_max = j;
+           }
+        }
+      }
+      
+      fprintf ( stderr, "%d:  count (%4.1f%%) %6d   is %d then %d\n",
+                k, ((double)o_max) * 100.0 / ((double)it_insns), o_max,
+                   i_max, j_max );
+      it_oofreq[i_max][j_max] = 0;
+
+   }
+}
+#endif
+
+
 StgThreadReturnCode interpretBCO ( Capability* cap )
 {
    /* On entry, the closure to interpret is on the top of the
@@ -64,6 +169,7 @@ StgThreadReturnCode interpretBCO ( Capability* cap )
 
     LOAD_STACK_POINTERS;
 
+    /* We don't change this ... */
     iSpLim = cap->rCurrentTSO->stack + RESERVED_STACK_WORDS;
 
     /* Main object-entering loop.  Object to be entered is on top of
@@ -72,53 +178,187 @@ StgThreadReturnCode interpretBCO ( Capability* cap )
 
     obj = (StgClosure*)StackWord(0); iSp++;
 
+    nextEnter_obj:
+
+#   ifdef INTERP_STATS
+    it_total_entries++;
+#   endif
+
     IF_DEBUG(evaluator,
              fprintf(stderr, 
              "\n---------------------------------------------------------------\n");
              fprintf(stderr,"Entering: "); printObj(obj);
              fprintf(stderr,"iSp = %p\tiSu = %p\n", iSp, iSu);
              fprintf(stderr, "\n" );
+
+            //      checkSanity(1);
+            //             iSp--; StackWord(0) = obj;
+            //             checkStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
+            //             iSp++;
+
              printStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
              fprintf(stderr, "\n\n");
             );
 
+
+
     switch ( get_itbl(obj)->type ) {
+
        case INVALID_OBJECT:
                barf("Invalid object %p",(StgPtr)obj);
 
-    case AP_UPD:
-      { nat Words;
-        nat i;
-        StgAP_UPD *ap = (StgAP_UPD*)obj;
-fprintf(stderr, "home-grown AP_UPD code\n");
-        Words = ap->n_args;
+#      ifndef REFERENCE_INTERPRETER
+
+       case IND:
+       case IND_OLDGEN:
+       case IND_PERM:
+       case IND_OLDGEN_PERM:
+       case IND_STATIC:
+       { 
+          obj = ((StgInd*)obj)->indirectee;
+          goto nextEnter_obj;
+       }
+
+       case CONSTR:
+       case CONSTR_1_0:
+       case CONSTR_0_1:
+       case CONSTR_2_0:
+       case CONSTR_1_1:
+       case CONSTR_0_2:
+       case CONSTR_INTLIKE:
+       case CONSTR_CHARLIKE:
+       case CONSTR_STATIC:
+       case CONSTR_NOCAF_STATIC:
+       nextEnter_obj_CONSTR:
+       {
+          StgInfoTable* ret_itbl = (StgInfoTable*)StackWord(0);
+          if (ret_itbl == (StgInfoTable*)&stg_ctoi_ret_R1p_info) {
+#            ifdef INTERP_STATS
+             it_retto_BCO++;
+#            endif
+             /* Returning this constr to a BCO.  Push the constr on
+                the stack and enter the return continuation BCO, which
+                is immediately underneath ret_itbl. */
+             StackWord(-1) = (W_)obj;
+             obj = (StgClosure*)StackWord(1);
+             iSp --;
+            if (get_itbl(obj)->type == BCO) 
+                goto nextEnter_obj_BCO; /* fast-track common case */
+             else
+                goto nextEnter_obj; /* a safe fallback */
+         } else
+         if (ret_itbl == (StgInfoTable*)&stg_upd_frame_info) {
+#            ifdef INTERP_STATS
+            it_retto_UPDATE++;
+#            endif
+             /* Returning this constr to an update frame.  Do the
+                update and re-enter the constr. */
+             ASSERT((W_*)iSu == iSp);
+             UPD_IND(iSu->updatee, obj); 
+             iSu = iSu->link;
+             iSp += sizeofW(StgUpdateFrame);
+             goto nextEnter_obj_CONSTR;
+          }
+#         ifdef INTERP_STATS
+          else it_retto_other++;
+#         endif
+          goto defer_to_sched;
+       }
+
+       case AP_UPD:
+       /* Copied from stg_AP_UPD_entry. */
+       { 
+          nat i, words;
+          StgAP_UPD *ap = (StgAP_UPD*)obj;
+          words = ap->n_args;
+
+         /* Stack check.  If a stack overflow might occur, don't enter
+             the closure; let the scheduler handle it instead. */
+          if (iSp - (words+sizeofW(StgUpdateFrame)) < iSpLim)
+             goto defer_to_sched;
+
+         /* Ok; we're safe.  Party on.  Push an update frame. */
+          iSp -= sizeofW(StgUpdateFrame);
+          {
+              StgUpdateFrame *__frame;
+              __frame = (StgUpdateFrame *)iSp;
+              SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);
+              __frame->link = iSu;
+              __frame->updatee = (StgClosure *)(ap);
+              iSu = __frame;
+          }
+
+          /* Reload the stack */
+          iSp -= words;
+          for (i=0; i < words; i++) StackWord(i) = (W_)ap->payload[i];
 
-        iSp -= sizeofW(StgUpdateFrame);
+          obj = (StgClosure*)ap->fun;
+          goto nextEnter_obj;
+       }
 
-        {
-                StgUpdateFrame *__frame;
-                __frame = (StgUpdateFrame *)iSp;
-                SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);
-                __frame->link = iSu;
-                __frame->updatee = (StgClosure *)(ap);
-                iSu = __frame;
-        }
+       case PAP:
+       /* Copied from stg_PAP_entry. */
+       {
+          nat     words, i;
+          StgPAP* pap = (StgPAP *)obj;
+  
+          /*
+           * remove any update frames on the top of the stack, by just
+           * performing the update here.
+           */
+          while ((W_)iSu - (W_)iSp == 0) {
+
+             switch (get_itbl(iSu)->type) {
+
+             case UPDATE_FRAME:
+                /* We're sitting on top of an update frame, so let's
+                   do the business. */
+                UPD_IND(iSu->updatee, pap);
+                iSu = iSu->link;
+                iSp += sizeofW(StgUpdateFrame);
+                continue;
+
+             case SEQ_FRAME:
+                /* Too complicated ... adopt the Usual Solution. */
+                /* fprintf(stderr, "!!! SEQ frame in PAP update\n"); */
+                goto defer_to_sched;
+
+             case CATCH_FRAME:
+                /* can't happen, see stg_update_PAP */
+                barf("interpretBCO: PAP_entry: CATCH_FRAME");
+
+             default:
+                barf("interpretBCO: PAP_entry: strange activation record");
+             }
+          }
 
-        iSp -= Words;
+          words = pap->n_args;
 
-        /* Reload the stack */
-        for (i=0; i<Words; i++) StackWord(i) = (W_)ap->payload[i];
+         /* Stack check.  If a stack overflow might occur, don't enter
+             the closure; let the scheduler handle it instead. */
+          if (iSp - words < iSpLim)
+             goto defer_to_sched;
 
-        iSp--; StackWord(0) = (W_)ap->fun;
-        goto nextEnter;
-      }
+          /* Ok; safe. */         
+          iSp -= words;
+          for (i=0; i < words; i++) StackWord(i) = (W_)pap->payload[i];
 
-       case BCO:
+          obj = (StgClosure*)pap->fun;
+          goto nextEnter_obj;
+       }
 
+#      endif /* ndef REFERENCE_INTERPRETER */
+
+       case BCO:
        /* ---------------------------------------------------- */
        /* Start of the bytecode interpreter                    */
        /* ---------------------------------------------------- */
+       nextEnter_obj_BCO:
+#      ifdef INTERP_STATS
+       it_BCO_entries++;
+#      endif
        {
+          int do_print_stack = 1;
           register int       bciPtr     = 1; /* instruction pointer */
           register StgBCO*   bco        = (StgBCO*)obj;
           register UShort*   instrs     = (UShort*)(&bco->instrs->payload[0]);
@@ -127,61 +367,132 @@ fprintf(stderr, "home-grown AP_UPD code\n");
           register StgInfoTable** itbls = (StgInfoTable**)
                                              (&bco->itbls->payload[0]);
 
+          /* Heap check */
           if (doYouWantToGC()) {
             iSp--; StackWord(0) = (W_)bco;
+             cap->rCurrentTSO->what_next = ThreadEnterInterp;
              RETURN(HeapOverflow);
           }
 
+          /* "Standard" stack check */
+          if (iSp - (INTERP_STACK_CHECK_THRESH+1) < iSpLim) {
+             iSp--;
+             StackWord(0) = (W_)obj;
+             cap->rCurrentTSO->what_next = ThreadEnterInterp;
+             RETURN(StackOverflow);
+          }
+
+          /* Context-switch check */
+          if (context_switch) {
+             iSp--;
+             StackWord(0) = (W_)obj;
+             cap->rCurrentTSO->what_next = ThreadEnterInterp;
+             RETURN(ThreadYielding);
+         }
+
+#         ifdef INTERP_STATS
+          it_lastopc = 0; /* no opcode */
+#         endif
+
           nextInsn:
 
           ASSERT(bciPtr <= instrs[0]);
           IF_DEBUG(evaluator,
+                  //if (do_print_stack) {
                   //fprintf(stderr, "\n-- BEGIN stack\n");
                   //printStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
                   //fprintf(stderr, "-- END stack\n\n");
+                  //}
+                   do_print_stack = 1;
                   fprintf(stderr,"iSp = %p   iSu = %p   pc = %d      ", iSp, iSu, bciPtr);
-                  disInstr(bco,bciPtr);
-                  if (0) { int i;
-                           fprintf(stderr,"\n");
-                           for (i = 8; i >= 0; i--) 
-                              fprintf(stderr, "%d  %p\n", i, (StgPtr)(*(iSp+i)));
-                           fprintf(stderr,"\n");
-                         }
-                 );
+                   disInstr(bco,bciPtr);
+                    if (0) { int i;
+                             fprintf(stderr,"\n");
+                             for (i = 8; i >= 0; i--) 
+                                fprintf(stderr, "%d  %p\n", i, (StgPtr)(*(iSp+i)));
+                             fprintf(stderr,"\n");
+                           }
+                   //if (do_print_stack) checkStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
+                  );
+
+#         ifdef INTERP_STATS
+          it_insns++;
+          ASSERT( (int)instrs[bciPtr] >= 0 && (int)instrs[bciPtr] < 27 );
+          it_ofreq[ (int)instrs[bciPtr] ] ++;
+          it_oofreq[ it_lastopc ][ (int)instrs[bciPtr] ] ++;
+          it_lastopc = (int)instrs[bciPtr];
+#         endif
 
           switch (BCO_NEXT) {
 
+              case bci_STKCHECK: {
+               /* An explicit stack check; we hope these will be
+                   rare. */
+                int stk_words_reqd = BCO_NEXT + 1;
+                if (iSp - stk_words_reqd < iSpLim) {
+                   iSp--;
+                   StackWord(0) = (W_)obj;
+                   cap->rCurrentTSO->what_next = ThreadEnterInterp;
+                   RETURN(StackOverflow);
+                }
+                goto nextInsn;
+              }
               case bci_ARGCHECK: {
                  int i;
                  StgPAP* pap;
                  int arg_words_reqd = BCO_NEXT;
                  int arg_words_avail = ((W_*)iSu) - ((W_*)iSp);
                  if (arg_words_avail >= arg_words_reqd) goto nextInsn;
-                 /* Handle arg check failure.  Copy the spare args
-                    into a PAP frame. */
- fprintf(stderr, "arg check fail %d %d\n", arg_words_reqd, arg_words_avail );
-                 pap = (StgPAP*)allocate(PAP_sizeW(arg_words_avail));
+
+#                ifndef REFERENCE_INTERPRETER
+
+                 /* Optimisation: if there are no args avail and the
+                    t-o-s is an update frame, do the update, and
+                    re-enter the object. */
+                 if (arg_words_avail == 0 
+                    && get_itbl(iSu)->type == UPDATE_FRAME) {
+                    UPD_IND(iSu->updatee, obj); 
+                    iSu = iSu->link;
+                    iSp += sizeofW(StgUpdateFrame);
+                    goto nextEnter_obj_BCO;
+                }
+
+#                endif /* ndef REFERENCE_INTERPRETER */
+
+                 /* Handle arg check failure.  General case: copy the
+                    spare args into a PAP frame. */
+                 pap = (StgPAP*)allocate_UPD(PAP_sizeW(arg_words_avail));
                  SET_HDR(pap,&stg_PAP_info,CCS_SYSTEM/*ToDo*/);
                  pap->n_args = arg_words_avail;
                  pap->fun = obj;
                  for (i = 0; i < arg_words_avail; i++)
                     pap->payload[i] = (StgClosure*)StackWord(i);
+
                  /* Push on the stack and defer to the scheduler. */
                  iSp = (StgPtr)iSu;
                  iSp --;
                  StackWord(0) = (W_)pap;
-                 RETURN(ThreadEnterGHC);
+                IF_DEBUG(evaluator,
+                          fprintf(stderr,"\tBuilt "); 
+                          printObj((StgClosure*)pap);
+                        );
+                 cap->rCurrentTSO->what_next = ThreadEnterGHC;
+                 RETURN(ThreadYielding);
               }
               case bci_PUSH_L: {
                  int o1 = BCO_NEXT;
                  ASSERT((W_*)iSp+o1 < (W_*)iSu);
                  StackWord(-1) = StackWord(o1);
                  iSp--;
+                 do_print_stack = 0;
                  goto nextInsn;
               }
               case bci_PUSH_LL: {
                  int o1 = BCO_NEXT;
                  int o2 = BCO_NEXT;
+                 ASSERT((W_*)iSp+o1 < (W_*)iSu);
+                 ASSERT((W_*)iSp+o2 < (W_*)iSu);
                  StackWord(-1) = StackWord(o1);
                  StackWord(-2) = StackWord(o2);
                  iSp -= 2;
@@ -191,6 +502,9 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                  int o1 = BCO_NEXT;
                  int o2 = BCO_NEXT;
                  int o3 = BCO_NEXT;
+                 ASSERT((W_*)iSp+o1 < (W_*)iSu);
+                 ASSERT((W_*)iSp+o2 < (W_*)iSu);
+                 ASSERT((W_*)iSp+o3 < (W_*)iSu);
                  StackWord(-1) = StackWord(o1);
                  StackWord(-2) = StackWord(o2);
                  StackWord(-3) = StackWord(o3);
@@ -206,19 +520,19 @@ fprintf(stderr, "home-grown AP_UPD code\n");
               case bci_PUSH_AS: {
                  int o_bco  = BCO_NEXT;
                  int o_itbl = BCO_NEXT;
-                 StackWord(-1) = BCO_LIT(o_itbl);
-                 StackWord(-2) = BCO_PTR(o_bco);
+                 StackWord(-2) = BCO_LIT(o_itbl);
+                 StackWord(-1) = BCO_PTR(o_bco);
                  iSp -= 2;
                  goto nextInsn;
               }
               case bci_PUSH_UBX: {
+                 int i;
                  int o_lits = BCO_NEXT;
                  int n_words = BCO_NEXT;
-                 for (; n_words > 0; n_words--) {
-                    iSp --;
-                    StackWord(0) = BCO_LIT(o_lits);
-                    o_lits++;
-                 }
+                 iSp -= n_words;
+                 for (i = 0; i < n_words; i++)
+                    StackWord(i) = BCO_LIT(o_lits+i);
+                 do_print_stack = 0;
                  goto nextInsn;
               }
               case bci_PUSH_TAG: {
@@ -236,14 +550,19 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                     StackWord(n+by) = StackWord(n);
                  }
                  iSp += by;
+#                ifdef INTERP_STATS
+                 it_slides++;
+#                endif
                  goto nextInsn;
               }
               case bci_ALLOC: {
+                 StgAP_UPD* ap; 
                  int n_payload = BCO_NEXT - 1;
-                 StgAP_UPD* ap = (StgAP_UPD*)allocate(AP_sizeW(n_payload));
+                 int request   = AP_sizeW(n_payload);
+                 ap = (StgAP_UPD*)allocate_UPD(request);
                  StackWord(-1) = (W_)ap;
                  ap->n_args = n_payload;
-                 SET_HDR(ap, &stg_AP_UPD_info, ??)
+                 SET_HDR(ap, &stg_AP_UPD_info, CCS_SYSTEM/*ToDo*/)
                  iSp --;
                  goto nextInsn;
               }
@@ -252,11 +571,15 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                  int stkoff = BCO_NEXT;
                  int n_payload = BCO_NEXT - 1;
                  StgAP_UPD* ap = (StgAP_UPD*)StackWord(stkoff);
-                 ASSERT(ap->n_args == n_payload);
+                 ASSERT((int)ap->n_args == n_payload);
                  ap->fun = (StgClosure*)StackWord(0);
                  for (i = 0; i < n_payload; i++)
                     ap->payload[i] = (StgClosure*)StackWord(i+1);
                  iSp += n_payload+1;
+                IF_DEBUG(evaluator,
+                          fprintf(stderr,"\tBuilt "); 
+                          printObj((StgClosure*)ap);
+                        );
                  goto nextInsn;
               }
               case bci_UNPACK: {
@@ -291,23 +614,28 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                  int i;
                  int o_itbl         = BCO_NEXT;
                  int n_words        = BCO_NEXT;
-                 StgInfoTable* itbl = BCO_ITBL(o_itbl);
-                 /* A bit of a kludge since n_words = n_p + n_np */
-                 int request        = CONSTR_sizeW( n_words, 0 );
-                 StgClosure* con = (StgClosure*)allocate(request);
-                 SET_HDR(con, itbl, CCS_SYSTEM/*ToDo*/);
+                 StgInfoTable* itbl = INFO_PTR_TO_STRUCT(BCO_ITBL(o_itbl));
+                 int request        = CONSTR_sizeW( itbl->layout.payload.ptrs, 
+                                                    itbl->layout.payload.nptrs );
+                 StgClosure* con = (StgClosure*)allocate_NONUPD(request);
+                 ASSERT( itbl->layout.payload.ptrs + itbl->layout.payload.nptrs > 0);
+                 SET_HDR(con, BCO_ITBL(o_itbl), CCS_SYSTEM/*ToDo*/);
                  for (i = 0; i < n_words; i++)
                     con->payload[i] = (StgClosure*)StackWord(i);
                  iSp += n_words;
                  iSp --;
                  StackWord(0) = (W_)con;
+                IF_DEBUG(evaluator,
+                          fprintf(stderr,"\tBuilt "); 
+                          printObj((StgClosure*)con);
+                        );
                  goto nextInsn;
               }
               case bci_TESTLT_P: {
                  int discr  = BCO_NEXT;
                  int failto = BCO_NEXT;
                  StgClosure* con = (StgClosure*)StackWord(0);
-                 if (constrTag(con) < discr)
+                 if (constrTag(con) >= discr)
                     bciPtr = failto;
                  goto nextInsn;
               }
@@ -319,6 +647,74 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                     bciPtr = failto;
                  goto nextInsn;
               }
+              case bci_TESTLT_I: {
+                 /* The top thing on the stack should be a tagged int. */
+                 int discr   = BCO_NEXT;
+                 int failto  = BCO_NEXT;
+                 I_ stackInt = (I_)StackWord(1);
+                 ASSERT(1 == StackWord(0));
+                 if (stackInt >= (I_)BCO_LIT(discr))
+                    bciPtr = failto;
+                 goto nextInsn;
+              }
+              case bci_TESTEQ_I: {
+                 /* The top thing on the stack should be a tagged int. */
+                 int discr   = BCO_NEXT;
+                 int failto  = BCO_NEXT;
+                 I_ stackInt = (I_)StackWord(1);
+                 ASSERT(1 == StackWord(0));
+                 if (stackInt != (I_)BCO_LIT(discr))
+                    bciPtr = failto;
+                 goto nextInsn;
+              }
+              case bci_TESTLT_D: {
+                 /* The top thing on the stack should be a tagged double. */
+                 int discr   = BCO_NEXT;
+                 int failto  = BCO_NEXT;
+                 StgDouble stackDbl, discrDbl;
+                 ASSERT(sizeofW(StgDouble) == StackWord(0));
+                 stackDbl = PK_DBL( & StackWord(1) );
+                 discrDbl = PK_DBL( & BCO_LIT(discr) );
+                 if (stackDbl >= discrDbl)
+                    bciPtr = failto;
+                 goto nextInsn;
+              }
+              case bci_TESTEQ_D: {
+                 /* The top thing on the stack should be a tagged double. */
+                 int discr   = BCO_NEXT;
+                 int failto  = BCO_NEXT;
+                 StgDouble stackDbl, discrDbl;
+                 ASSERT(sizeofW(StgDouble) == StackWord(0));
+                 stackDbl = PK_DBL( & StackWord(1) );
+                 discrDbl = PK_DBL( & BCO_LIT(discr) );
+                 if (stackDbl != discrDbl)
+                    bciPtr = failto;
+                 goto nextInsn;
+              }
+              case bci_TESTLT_F: {
+                 /* The top thing on the stack should be a tagged float. */
+                 int discr   = BCO_NEXT;
+                 int failto  = BCO_NEXT;
+                 StgFloat stackFlt, discrFlt;
+                 ASSERT(sizeofW(StgFloat) == StackWord(0));
+                 stackFlt = PK_FLT( & StackWord(1) );
+                 discrFlt = PK_FLT( & BCO_LIT(discr) );
+                 if (stackFlt >= discrFlt)
+                    bciPtr = failto;
+                 goto nextInsn;
+              }
+              case bci_TESTEQ_F: {
+                 /* The top thing on the stack should be a tagged float. */
+                 int discr   = BCO_NEXT;
+                 int failto  = BCO_NEXT;
+                 StgFloat stackFlt, discrFlt;
+                 ASSERT(sizeofW(StgFloat) == StackWord(0));
+                 stackFlt = PK_FLT( & StackWord(1) );
+                 discrFlt = PK_FLT( & BCO_LIT(discr) );
+                 if (stackFlt != discrFlt)
+                    bciPtr = failto;
+                 goto nextInsn;
+              }
 
               /* Control-flow ish things */
               case bci_ENTER: {
@@ -329,14 +725,16 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                     compiled code. */
                  int           o_itoc_itbl = BCO_NEXT;
                  int           tag         = StackWord(0);
-                 StgInfoTable* ret_itbl    = (StgInfoTable*)StackWord(tag+1 +1);
+                 StgInfoTable* ret_itbl    = (StgInfoTable*)StackWord(tag +1);
                  ASSERT(tag <= 2); /* say ... */
-                 if (ret_itbl == (StgInfoTable*)&stg_ctoi_ret_R1_info
-                     /* || ret_itbl == stg_ctoi_ret_F1_info
-                        || ret_itbl == stg_ctoi_ret_D1_info */) {
+                 if (ret_itbl == (StgInfoTable*)&stg_ctoi_ret_R1p_info
+                     || ret_itbl == (StgInfoTable*)&stg_ctoi_ret_R1n_info
+                     || ret_itbl == (StgInfoTable*)&stg_ctoi_ret_F1_info
+                     || ret_itbl == (StgInfoTable*)&stg_ctoi_ret_D1_info
+                     || ret_itbl == (StgInfoTable*)&stg_ctoi_ret_V_info) {
                      /* Returning to interpreted code.  Interpret the BCO 
                         immediately underneath the itbl. */
-                     StgBCO* ret_bco = (StgBCO*)StackWord(tag+1 +1+1);
+                     StgBCO* ret_bco = (StgBCO*)StackWord(tag +1+1);
                      iSp --;
                      StackWord(0) = (W_)ret_bco;
                      goto nextEnter;
@@ -347,22 +745,37 @@ fprintf(stderr, "home-grown AP_UPD code\n");
                         the TOS value into R1/F1/D1 and do a standard
                         compiled-code return. */
                      StgInfoTable* magic_itbl = BCO_ITBL(o_itoc_itbl);
-                     StackWord(0) = (W_)magic_itbl;
-                     RETURN(ThreadRunGHC);
+                     if (magic_itbl != NULL) {
+                        StackWord(0) = (W_)magic_itbl;
+                        cap->rCurrentTSO->what_next = ThreadRunGHC;
+                        RETURN(ThreadYielding);
+                     } else {
+                        /* Special case -- returning a VoidRep to
+                           compiled code.  T.O.S is the VoidRep tag,
+                           and underneath is the return itbl.  Zap the
+                           tag and enter the itbl. */
+                       ASSERT(StackWord(0) == (W_)NULL);
+                       iSp ++;
+                        cap->rCurrentTSO->what_next = ThreadRunGHC;
+                        RETURN(ThreadYielding);
+                     }
                  }
               }
-        
+              case bci_CCALL: {
+                 int o_itbl                = BCO_NEXT;
+                 void(*marshall_fn)(void*) = (void (*)(void*))BCO_LIT(o_itbl);
+                 marshall_fn ( (void*)(& StackWord(0) ) );
+                 goto nextInsn;
+              }
+              case bci_JMP: {
+                 /* BCO_NEXT modifies bciPtr, so be conservative. */
+                 int nextpc = BCO_NEXT;
+                 bciPtr     = nextpc;
+                 goto nextInsn;
+              }
               case bci_CASEFAIL:
                  barf("interpretBCO: hit a CASEFAIL");
 
-              /* As yet unimplemented */
-              case bci_TESTLT_I:
-              case bci_TESTEQ_I:
-              case bci_TESTLT_F:
-              case bci_TESTEQ_F:
-              case bci_TESTLT_D:
-              case bci_TESTEQ_D:
-
               /* Errors */
               default: 
                  barf("interpretBCO: unknown or unimplemented opcode");
@@ -376,17 +789,26 @@ fprintf(stderr, "home-grown AP_UPD code\n");
        /* End of the bytecode interpreter                      */
        /* ---------------------------------------------------- */
 
+       defer_to_sched:
        default: {
+#         ifdef INTERP_STATS
+          { int j = get_itbl(obj)->type;
+            ASSERT(j >= 0 && j < N_CLOSURE_TYPES);
+            it_unknown_entries[j]++;
+            it_total_unknown_entries++;
+          }
+#         endif
+
           /* Can't handle this object; yield to sched. */
-          fprintf(stderr, "entering unknown closure -- yielding to sched\n"); 
-          printObj(obj);
-          cap->rCurrentTSO->what_next = ThreadEnterGHC;
+          IF_DEBUG(evaluator,
+                   fprintf(stderr, "entering unknown closure -- yielding to sched\n"); 
+                   printObj(obj);
+                  );
           iSp--; StackWord(0) = (W_)obj;
+          cap->rCurrentTSO->what_next = ThreadEnterGHC;
           RETURN(ThreadYielding);
        }
     } /* switch on object kind */
 
     barf("fallen off end of object-type switch in interpretBCO()");
 }
-
-#endif /* GHCI */