[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / runtime / main / StgUpdate.lhc
diff --git a/ghc/runtime/main/StgUpdate.lhc b/ghc/runtime/main/StgUpdate.lhc
deleted file mode 100644 (file)
index e91a169..0000000
+++ /dev/null
@@ -1,768 +0,0 @@
-%************************************************************************
-%*                                                                     *
-\section[update-code]{Code required for update abstraction}
-%*                                                                     *
-%************************************************************************
-
-This code is required by the update interface which sits on top of the
-storage manager interface (See \tr{SMupdate.lh}).
-
-\begin{itemize}
-\item Indirection entry code and info table.
-\item Black Hole entry code and info table.
-\item Update frame code and return vectors.
-\item PAP update code.
-\item PAP entry code and info table.
-\end{itemize}
-
-System-wide constants need to be included:
-\begin{code}
-#define MAIN_REG_MAP       /* STG world */
-
-#include "rtsdefs.h"
-#include "SMupdate.h"
-#if 0
-#ifdef PAR
-# include "Statistics.h"
-#endif
-#endif
-
-EXTDATA(PrelBase_Z91Z93_closure);
-
-#if defined(TICKY_TICKY)
-void PrintTickyInfo(STG_NO_ARGS);
-#endif
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[indirection-code]{Indirection code}
-%*                                                                     *
-%************************************************************************
-
-The entry code for indirections and the indirection info-table.
-\begin{code}
-STGFUN(Ind_entry)
-{
-    FB_
-    ENT_IND(Node);     /* Ticky-ticky profiling info */
-
-    Node = (P_) IND_CLOSURE_PTR((P_) Node);
-    ENT_VIA_NODE();
-    InfoPtr=(D_)(INFO_PTR(Node));
-    JMP_(ENTRY_CODE(InfoPtr));
-    FE_
-}
-
-IND_ITBL(Ind_info,Ind_entry,const,EF_);
-\end{code}
-
-We also need a special @CAF@ indirection info table which is used to
-indirect @CAF@s to evaluated results in the heap.
-\begin{code}
-STGFUN(Caf_entry)      /* same as Ind_entry */
-{
-    FB_
-    ENT_IND(Node);
-
-    Node = (P_) IND_CLOSURE_PTR((P_) Node);
-    ENT_VIA_NODE();
-    InfoPtr=(D_)(INFO_PTR(Node));
-    JMP_(ENTRY_CODE(InfoPtr));
-    FE_
-}
-
-CAF_ITBL(Caf_info,Caf_entry,const,EF_);
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[black-hole-code]{Black Hole code}
-%*                                                                     *
-%************************************************************************
-
-The entry code for black holes abort indicating a cyclic data dependency.
-It is used to overwrite closures currently being evaluated.
-
-In the concurrent world, black holes are synchronization points, and they
-are turned into blocking queues when there are threads waiting for the 
-evaluation of the closure to finish.
-
-\begin{code}
-#ifdef CONCURRENT
-EXTFUN(EnterNodeCode);
-EXTFUN(StackUnderflowEnterNode);
-EXTDATA_RO(BQ_info);
-#else
-void raiseError PROTO((StgStablePtr));
-extern StgStablePtr errorHandler; /* NB: prone to magic-value-ery (WDP 95/12) */
-#endif
-
-STGFUN(BH_UPD_entry)
-{
-#ifndef CONCURRENT
-    FB_
-    (void) STGCALL1(int,(void *, FILE *),fflush,stdout);
-    (void) STGCALL2(int,(),fprintf,stderr,"Entered a `black hole': the program has a cyclic data dependency.\n");
-
-# if defined(PROFILING)
-    {
-       CostCentre cc = (CostCentre) CC_HDR(Node);
-       (void) STGCALL5(int,(),fprintf,stderr,"Cost Centre: %s  Module: %s  Group %s\n",cc->label, cc->module, cc->group);
-    }
-# endif    
-
-# if defined(TICKY_TICKY)
-    if (RTSflags.TickyFlags.showTickyStats) {
-       (void) STGCALL0(void,(),PrintTickyInfo);
-    }
-# endif
-
-    (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
-    FE_
-
-#else /* threads! */
-
-    FB_
-
-# if 0
-    if ( RTSflags.GranFlags.debug & 0x80 ) 
-      (void) STGCALL4(int,(),fprintf,stderr,"GRAN_CHECK in BH_UPD_entry: Entered a `black hole' @ 0x%x (CurrentTSO @ 0x%x\n ",Node,CurrentTSO);
-# endif
-
-# if defined(GRAN)
-    /* Do this before losing its TSO_LINK */
-    STGCALL3(void,(),GranSimBlock,CurrentTSO,CurrentProc,Node);        
-# endif
-
-    TSO_LINK(CurrentTSO) = PrelBase_Z91Z93_closure;
-    SET_INFO_PTR(Node, BQ_info);
-    BQ_ENTRIES(Node) = (W_) CurrentTSO;
-
-# if defined(GCap) || defined(GCgn)
-    /* If we modify a black hole in the old generation,
-       we have to make sure it goes on the mutables list */
-
-    if(Node <= StorageMgrInfo.OldLim) {
-       MUT_LINK(Node) = (W_) StorageMgrInfo.OldMutables;
-        StorageMgrInfo.OldMutables = Node;
-    } else
-        MUT_LINK(Node) = MUT_NOT_LINKED;
-# endif
-
-    LivenessReg = LIVENESS_R1;
-    SaveAllStgRegs();
-    TSO_PC1(CurrentTSO) = EnterNodeCode;
-
-    if (DO_QP_PROF) {
-       QP_Event1("GR", CurrentTSO);
-    }
-
-# ifdef PAR
-    if(RTSflags.ParFlags.granSimStats) {
-       TIME now = CURRENT_TIME;
-        TSO_EXECTIME(CurrentTSO) += now - TSO_BLOCKEDAT(CurrentTSO);
-        TSO_BLOCKCOUNT(CurrentTSO)++;
-       TSO_QUEUE(CurrentTSO) = Q_BLOCKED;
-        TSO_BLOCKEDAT(CurrentTSO) = now;
-        DumpGranEvent(GR_BLOCK, CurrentTSO);
-    }
-# endif
-
-# if defined(GRAN)
-    /* CurrentTSO = PrelBase_Z91Z93_closure; */
-    ReSchedule(SAME_THREAD);
-# else
-    ReSchedule(0);
-# endif
-
-    FE_
-
-#endif /* threads */
-}
-
-/* made external so that debugger can get at it more effectively */
-STGFUN(BH_SINGLE_entry)
-{
-    FB_
-
-    (void) STGCALL1(int,(void *, FILE *),fflush,stdout);
-    (void) STGCALL2(int,(),fprintf,stderr,"Entered a single-entry `black hole' --\n");
-    (void) STGCALL2(int,(),fprintf,stderr,"either the compiler made a mistake on single-entryness,\n");
-    (void) STGCALL2(int,(),fprintf,stderr,"or the program has a cyclic data dependency.\n");
-
-#if defined(PROFILING)
-    {
-       CostCentre cc = (CostCentre) CC_HDR(Node);
-       (void) STGCALL5(int,(),fprintf,stderr, "Cost Centre: %s  Module: %s  Group %s\n",cc->label, cc->module, cc->group);
-    }
-#endif    
-
-# if defined(TICKY_TICKY)
-    if (RTSflags.TickyFlags.showTickyStats) {
-       (void) STGCALL0(void,(),PrintTickyInfo);
-    }
-# endif
-
-#ifndef CONCURRENT
-    (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
-#else
-    EXIT(EXIT_FAILURE);
-#endif
-
-    FE_
-}
-\end{code}
-
-Updatable closures are overwritten with a black hole of a fixed size,
-@MIN_UPD_SIZE@.
-
-\begin{code}
-CAT_DECLARE(BH,BH_K,"BH","BH") /* just one, shared */
-
-BH_ITBL(BH_UPD_info,BH_UPD_entry,U,const,EF_);
-\end{code}
-
-Single-Entry closures, which are not updated, are also overwritten
-with a black hole. They have size @MIN_NONUPD_SIZE@.
-
-\begin{code}
-BH_ITBL(BH_SINGLE_info,BH_SINGLE_entry,N,const,EF_);
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[static-update-code]{Static update code in update frames}
-%*                                                                     *
-%************************************************************************
-
-This code is pointed to from update frames.  It has to cope with
-any kind of algebraic return: vectored or unvectored.
-
-See \tr{SMupdate.lh} for a description of the various update frames
-and the macros defining their layout.
-
-On entry to this code:
-\begin{itemize}
-\item @R1@ points to a recently created heap object (return in heap) or
-is dead (return in regs).
-\item @R2@ points to the info table for the constructor.
-\item When returning in regs, any of the return-regs (@R3@...) may be live,
-but aren't used by this code.  They must be preserved.
-\item @SpB@ points to the topmost word of the update frame.
-\end{itemize}
-
-NEW update mechanism (Jan '94):
-
-When returning to an update frame, we want to jump directly to the
-update code for the constructor in hand.  Because of the various
-possible return conventions (all of which must be handled by the
-generic update frame), we actually end up with a somewhat indirect
-jump.
-
-\begin{code}
-
-STGFUN(StdUpdFrameDirectReturn)
-{
-    FB_
-    JMP_(UPDATE_CODE(InfoPtr));
-    FE_
-}
-
-/*
-   NB: For direct returns to work properly, the name of the routine must be
-   the same as the name of the vector table with vtbl_ removed and DirectReturn
-   appended.  This is all the mangler understands.
-*/
-
-const
-W_
-vtbl_StdUpdFrame[] = {
-    /* at least "MAX_VECTORED_RTN" elements (see GhcConstants.lh) */
-    (W_) StdUpdFrameDirectReturn/*0*/,
-    (W_) StdUpdFrameDirectReturn/*1*/,
-    (W_) StdUpdFrameDirectReturn/*2*/,
-    (W_) StdUpdFrameDirectReturn/*3*/,
-    (W_) StdUpdFrameDirectReturn/*4*/,
-    (W_) StdUpdFrameDirectReturn/*5*/,
-    (W_) StdUpdFrameDirectReturn/*6*/,
-    (W_) StdUpdFrameDirectReturn/*7*/
-};
-
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[seq-update-code]{Update code for seq}
-%*                                                                     *
-%************************************************************************
-
-
-\begin{code}
-
-IFN_(seqDirectReturn) {
-    void *cont;
-
-    FB_
-    RetReg = (StgRetAddr) SpB[BREL(0)];
-    cont = (void *) SpB[BREL(1)];
-    /* SpB += BREL(2); */
-    JMP_(cont);
-    FE_
-}
-
-/*
-   NB: For direct returns to work properly, the name of the routine must be
-   the same as the name of the vector table with vtbl_ removed and DirectReturn
-   appended.  This is all the mangler understands.
- */
-
-const W_
-vtbl_seq[] = {
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn,
-    (W_) seqDirectReturn
-};
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[existing-con-update-code]{Update code for existing constructors}
-%*                                                                     *
-%************************************************************************
-
-Here is the standard update code for objects that are returned in the
-heap (or those which are initially returned in registers, but have
-already been allocated in the heap earlier in the update chain).  In
-either case, @Node@ points to the heap object.  The update code grabs
-the address of the updatee out of the partial update frame (the return
-address has already been popped), makes the updatee an indirection to
-@Node@, and returns according to the convention for the constructor.
-
-\begin{code}
-#define IND_UPD_TEMPLATE(label, retvector)                     \
-  STGFUN(label)                                                \
-  {                                                            \
-    FB_                                                                \
-    UPD_EXISTING();    /* Ticky-ticky profiling info */        \
-    /* Update thing off stk with an indirection to Node */     \
-    UPD_IND(GRAB_UPDATEE(SpB), Node);                           \
-    /* Pop the standard update frame */                         \
-    POP_STD_UPD_FRAME()                                                \
-                                                               \
-    JMP_(retvector);                                           \
-    FE_                                                        \
-  }
-
-IND_UPD_TEMPLATE(IndUpdRetDir, DIRECT(((P_)RetReg)))
-IND_UPD_TEMPLATE(IndUpdRetV0, ((P_)RetReg)[RVREL(0)])
-IND_UPD_TEMPLATE(IndUpdRetV1, ((P_)RetReg)[RVREL(1)])
-IND_UPD_TEMPLATE(IndUpdRetV2, ((P_)RetReg)[RVREL(2)])
-IND_UPD_TEMPLATE(IndUpdRetV3, ((P_)RetReg)[RVREL(3)])
-IND_UPD_TEMPLATE(IndUpdRetV4, ((P_)RetReg)[RVREL(4)])
-IND_UPD_TEMPLATE(IndUpdRetV5, ((P_)RetReg)[RVREL(5)])
-IND_UPD_TEMPLATE(IndUpdRetV6, ((P_)RetReg)[RVREL(6)])
-IND_UPD_TEMPLATE(IndUpdRetV7, ((P_)RetReg)[RVREL(7)])
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[no-update-code]{Code for Erroneous Updates}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-
-STGFUN(UpdErr)
-{
-    FB_
-
-    fflush(stdout);
-    fprintf(stderr, "Update error: not a constructor!\n");
-    abort();
-
-    FE_
-}
-
-STGFUN(StdErrorCode)
-{
-    FB_
-
-    fflush(stdout);
-    fprintf(stderr, "Standard error: should never happen!\n");
-    abort();
-
-    FE_
-}
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[permanent-indirections]{Lexical Scoping Updates}
-%*                                                                     *
-%************************************************************************
-
-A function entered without any arguments is updated with an
-indirection. For lexically scoped profiling we still need to set the
-cost centre if we enter the PAP. As the indirection is removed by the
-garbage collector this would not be possible.
-
-To solve this problem we introduce a permanent indirection which sets
-the cost centre when entered. The heap profiler ignores the space
-occupied by it as it would not reside in the heap during normal
-execution.
-
-In ticky-land: If we are trying to collect update-entry counts
-(controlled by an RTS flag), then we must use permanent indirections
-(the shorting-out of regular indirections loses the counts).
-
-\begin{code}
-#if defined(PROFILING) || defined(TICKY_TICKY)
-
-STGFUN(Perm_Ind_entry)
-{
-    FB_
-
-    /* Don't add INDs to granularity cost */
-
-    /* Dont: ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
-
-    /* Enter PAP cost centre -- lexical scoping only */
-    ENTER_CC_PAP_CL(Node);
-
-    Node = (P_) IND_CLOSURE_PTR((P_) Node);
-
-    /* Dont: ENT_VIA_NODE(); for ticky-ticky; as above */
-
-    InfoPtr=(D_)(INFO_PTR(Node));
-
-    JMP_(ENTRY_CODE(InfoPtr));
-    FE_
-}
-
-PERM_IND_ITBL(Perm_Ind_info,Perm_Ind_entry,const,EF_);
-
-#endif /* PROFILING or TICKY */
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection[partial-application-updates]{Partial applications}
-%*                                                                     *
-%************************************************************************
-
-See STG paper implementation section of Partial application updates.
-
-We jump here when the current function fails an argument satisfaction
-check.  There can be two reasons for this.  In the usual case, there
-is an update frame blocking our access to anything deeper on the
-stack.  We then update the updatee in the frame with a partial
-application node and squeeze out the update frame.  The other
-possibility is that we are running threaded code, and we are sitting
-on the bottom of a stack chunk.  In this case, we still build the
-partial application, but we have nothing in our hands to update, so we
-underflow the stack (awakening the previous chunk) and enter the
-partial application node just built.
-
-On entry to @UpdatePAP@, we assume the following:
-\begin{itemize}
-\item SuB points to topmost word of an update frame or to the bottom of a 
-stack chunk.
-\item SpA and SpB point to the topmost words of their respective stacks.
-\item Node points to the closure which needs more arguments than are there.
-\end{itemize}
-
-\begin{code}
-STGFUN(UpdatePAP)
-{
-    /* 
-     * Use STG registers for these locals which must survive the HEAP_CHK.
-     * Don't squash Node (R1), because it's an implicit argument.
-     */
-
-#define NNonPtrWords   (R2.i)
-#define NPtrWords      (R3.i)
-#define NArgWords      (R4.i)
-#define PapSize                (R5.i)
-#if defined(PROFILING)
-# define CC_pap        ((CostCentre)(R7.p))
-#endif
-
-    /* These other locals do not have to survive a HEAP_CHK */
-
-    P_ PapClosure;
-    P_ Updatee;
-    P_ p;
-    I_ i;
-
-    FB_
-
-#if defined(GRAN_COUNT)
-      ++nPAPs;
-#endif
-
-    NPtrWords    = AREL(SuA - SpA);
-    NNonPtrWords = BREL(SuB - SpB);
-
-    ASSERT(NPtrWords >= 0);
-    ASSERT(NNonPtrWords >= 0);
-
-    NArgWords = NPtrWords + NNonPtrWords + 1;  /* +1 for Node */
-
-#if defined(PROFILING)
-      /* set "CC_pap" to go in the updatee (see Sansom thesis, p 183) */
-
-    CC_pap /*really cc_enter*/ = (CostCentre) CC_HDR(Node);
-    if (IS_CAF_OR_DICT_OR_SUB_CC(CC_pap) /*really cc_enter*/)
-       CC_pap = CCC;
-#endif
-
-    if (NArgWords == 1) { 
-
-        /* 
-         * No arguments, only Node.  Skip building the PAP and
-         * just plan to update with an indirection.
-         */
-
-       PapClosure = Node;
-
-    } else {
-   
-        /* Build the PAP.  A generic PAP closure is laid out thus:
-         *     code ptr, size, no of words of ptrs, Node, ptrs, non-ptrs 
-         * (i.e. a DYN closure)
-         * ToDo: add stuff for special cases, to omit size and no. of ptrs 
-         *     (Still ToDo?  (JSM))
-         */
-
-       PapSize = NArgWords + DYN_HS;
-    
-       ALLOC_UPD_PAP(DYN_HS, NArgWords, 0, PapSize);
-       CC_ALLOC(CC_pap, PapSize, PAP_K);
-    
-       /* Allocate PapClosure -- Only Node (R1) is live */
-       HEAP_CHK(LIVENESS_R1, PapSize, 0);
-
-       PapClosure = Hp + 1 - PapSize;  /* The new PapClosure */
-
-       SET_DYN_HDR(PapClosure, PAP_info, CC_pap, NArgWords + DYN_VHS, NPtrWords + 1);
-
-       /* Now fill in the closure fields */
-
-       p = Hp;
-        for (i = NNonPtrWords - 1; i >= 0; i--) *p-- = (W_) SpB[BREL(i)];
-        for (i = NPtrWords    - 1; i >= 0; i--) *p-- = (W_) SpA[AREL(i)];
-       *p = (W_) Node;
-       }
-
-    /* 
-     * Finished constructing PAP closure; now update the updatee.  But
-     * wait!  What if there is no updatee?  Then we fall off the
-     * stack.
-     */
-
-#ifdef CONCURRENT
-    if (SuB < STKO_BSTK_BOT(StkOReg)) {
-           Node = PapClosure;
-# ifdef PAR
-           LivenessReg = LIVENESS_R1;
-# endif
-        JMP_(StackUnderflowEnterNode);
-       }
-#endif
-
-    /* 
-     * Now we have a standard update frame, so we update the updatee with 
-     * either the new PAP or Node.
-     *
-     * Supposedly, it is not possible to get a constructor update frame,
-     * (Why not?  (JSM))
-     * (Because they have *never* been implemented.  (WDP))
-     */
-
-    Updatee = GRAB_UPDATEE(SuB); 
-    UPD_IND(Updatee, PapClosure);   /* Indirect Updatee to PapClosure */
-
-    if (NArgWords != 1) {
-       UPD_PAP_IN_NEW(NArgWords);
-
-    } else {
-       UPD_PAP_IN_PLACE();     
-
-#if defined(PROFILING)
-       /* 
-         * Lexical scoping requires a *permanent* indirection, and we
-         * also have to set the cost centre for the indirection.
-         */
-       INFO_PTR(Updatee) = (W_) Perm_Ind_info;
-       SET_CC_HDR(Updatee, CC_pap);
-
-#endif /* PROFILING */
-    }
-
-#if defined(PROFILING)
-    /* 
-     * Restore the Cost Centre too (if required); again see Sansom thesis p 183.
-     * Take the CC out of the update frame if a CAF/DICT.
-     */
-
-    CCC = (IS_CAF_OR_DICT_OR_SUB_CC(CC_pap)) ? GRAB_COST_CENTRE(SuB) : CC_pap;
-
-#endif /* PROFILING */
-
-    /* Restore SuA, SuB, RetReg */
-    RetReg = GRAB_RET(SuB);
-    SuA = GRAB_SuA(SuB);
-    SuB = GRAB_SuB(SuB);
-
-    /* 
-     * Squeeze out update frame from B stack.  Note that despite our best
-     * efforts with [AB]REL and friends, the loop order depends on the B
-     * stack growing up.
-     */
-    for (i = NNonPtrWords - 1; i >= 0; i--) 
-       SpB[BREL(i+STD_UF_SIZE)] = SpB[BREL(i)];
-
-    SpB += BREL(STD_UF_SIZE);
-
-    /* 
-     * All done!  Restart by re-entering Node
-     * Don't count this entry for ticky-ticky profiling. 
-    */
-
-#if 0 /* defined(GRAN) */
-    GRAN_EXEC(16,4,7,4,0);
-#endif
-    InfoPtr=(D_)(INFO_PTR(Node));
-    JMP_(ENTRY_CODE(InfoPtr));
-    FE_
-
-#undef NNonPtrWords
-#undef NPtrWords
-#undef NArgWords
-#undef PapSize
-#ifdef PROFILING
-# undef CC_pap
-#endif
-}
-\end{code}
-
-The entry code for a generic PAP. @Node@ points to the PAP closure.
-Reload the stacks from the PAP, and enter the closure stored in the
-PAP. PAPs are in HNF so no update frame is needed.
-
-\begin{code}
-STGFUN(PAP_entry)
-{
-    /* Use STG registers for these locals which must survive the STK_CHK */
-#define NPtrWords      (R2.i)
-#define NNonPtrWords   (R3.i)
-#if defined(PROFILING)
-# define CC_pap        ((CostCentre)(R7.p))
-#endif
-
-    /* These locals don't have to survive the STK_CHK */
-    P_ Updatee;
-    P_ p;
-    I_ i;
-    I_ aWords, bWords;
-
-    FB_
-
-      /* Concurrent World:
-        If we come from StackUnderflowEnterNode the old StkO has been
-        nuked and the PAP carries over data from the old StkO.
-        The underflow code must restore RetReg to the right value 
-        because it is not grabbed from the update frame if there is data
-        on one of the two stacks.
-          -- HWL
-      */
-    while (AREL(SuA - SpA) == 0 && BREL(SuB - SpB) == 0) {
-#ifdef CONCURRENT
-        if (SuB < STKO_BSTK_BOT(StkOReg)) {
-# ifdef PAR
-            LivenessReg = LIVENESS_R1;
-# endif
-           JMP_(StackUnderflowEnterNode);
-        }
-#endif
-
-       /* We're sitting on top of an update frame, so let's do the business */
-
-        Updatee = GRAB_UPDATEE(SuB);
-       UPD_IND(Updatee, Node);
-
-#if defined(PROFILING)
-        /* 
-         * Restore the Cost Centre too (if required); again see Sansom
-         * thesis p 183.  Take the CC out of the update frame if a
-         * CAF/DICT.
-         */
-
-        CC_pap = (CostCentre) CC_HDR(Node);
-        CCC = (IS_CAF_OR_DICT_OR_SUB_CC(CC_pap)) ? GRAB_COST_CENTRE(SuB) : CC_pap;
-
-#endif /* PROFILING */
-
-        RetReg = GRAB_RET(SuB);
-        SuA = GRAB_SuA(SuB);
-        SuB = GRAB_SuB(SuB);
-        SpB += BREL(STD_UF_SIZE);
-    }
-
-    NPtrWords    = DYN_CLOSURE_NoPTRS(Node) - 1; /* The saved Node counts as one */
-    NNonPtrWords = DYN_CLOSURE_NoNONPTRS(Node);
-
-    /* Ticky-ticky profiling info */
-    ENT_PAP(Node);
-
-    /* Enter PAP cost centre -- lexical scoping only */
-    ENTER_CC_PAP_CL(Node);
-
-    /* 
-     * Check for stack overflow.  Ask to take all of the current frame with
-     * us to the new world.  If there is no update frame on the current stack,
-     * bWords will exceed the size of the B stack, but StackOverflow will deal 
-     * with it.
-     */
-
-    aWords = AREL(SuA - SpA);
-    bWords = BREL(SuB - SpB) + STD_UF_SIZE;
-
-    STK_CHK(LIVENESS_R1, NPtrWords, NNonPtrWords, aWords, bWords, 0, 0);
-
-    SpA -= AREL(NPtrWords);
-    SpB -= BREL(NNonPtrWords);
-
-    /* Reload Node */
-    p = Node + DYN_HS;     /* Point to first pointer word */
-    Node = (P_) *p++;
-
-    /* Reload the stacks */
-
-    for (i=0; i<NPtrWords;    i++) SpA[AREL(i)] = (P_) *p++;
-    for (i=0; i<NNonPtrWords; i++) SpB[BREL(i)] = *p++;
-
-    /* Off we go! */
-    ENT_VIA_NODE();
-    InfoPtr=(D_)(INFO_PTR(Node));
-    JMP_(ENTRY_CODE(InfoPtr));
-    FE_
-
-#undef NPtrWords
-#undef NNonPtrWords
-#ifdef PROFILING
-# undef CC_pap
-#endif
-}
-\end{code}
-
-The info table for a generic PAP:
-\begin{code}
-DYN_ITBL(PAP_info,PAP_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,EF_,PAP_K,"PAP","->");
-\end{code}