[project @ 1996-07-25 20:43:49 by partain]
[ghc-hetmet.git] / ghc / runtime / main / StgUpdate.lhc
1 %************************************************************************
2 %*                                                                      *
3 \section[update-code]{Code required for update abstraction}
4 %*                                                                      *
5 %************************************************************************
6
7 This code is required by the update interface which sits on top of the
8 storage manager interface (See \tr{SMupdate.lh}).
9
10 \begin{itemize}
11 \item Indirection entry code and info table.
12 \item Black Hole entry code and info table.
13 \item Update frame code and return vectors.
14 \item PAP update code.
15 \item PAP entry code and info table.
16 \end{itemize}
17
18 System-wide constants need to be included:
19 \begin{code}
20 #define MAIN_REG_MAP        /* STG world */
21
22 #include "rtsdefs.h"
23 #include "SMupdate.h"
24 #if 0
25 #ifdef PAR
26 # include "Statistics.h"
27 #endif
28 #endif
29
30 EXTDATA(Prelude_Z91Z93_closure);
31
32 #if defined(TICKY_TICKY)
33 void PrintTickyInfo(STG_NO_ARGS);
34 #endif
35 \end{code}
36
37 %************************************************************************
38 %*                                                                      *
39 \subsection[indirection-code]{Indirection code}
40 %*                                                                      *
41 %************************************************************************
42
43 The entry code for indirections and the indirection info-table.
44 \begin{code}
45 STGFUN(Ind_entry)
46 {
47     FB_
48     ENT_IND(Node);      /* Ticky-ticky profiling info */
49
50     Node = (P_) IND_CLOSURE_PTR((P_) Node);
51     ENT_VIA_NODE();
52     InfoPtr=(D_)(INFO_PTR(Node));
53     JMP_(ENTRY_CODE(InfoPtr));
54     FE_
55 }
56
57 IND_ITBL(Ind_info,Ind_entry,const,EF_);
58 \end{code}
59
60 We also need a special @CAF@ indirection info table which is used to
61 indirect @CAF@s to evaluated results in the heap.
62 \begin{code}
63 STGFUN(Caf_entry)       /* same as Ind_entry */
64 {
65     FB_
66     ENT_IND(Node);
67
68     Node = (P_) IND_CLOSURE_PTR((P_) Node);
69     ENT_VIA_NODE();
70     InfoPtr=(D_)(INFO_PTR(Node));
71     JMP_(ENTRY_CODE(InfoPtr));
72     FE_
73 }
74
75 CAF_ITBL(Caf_info,Caf_entry,const,EF_);
76 \end{code}
77
78 %************************************************************************
79 %*                                                                      *
80 \subsection[black-hole-code]{Black Hole code}
81 %*                                                                      *
82 %************************************************************************
83
84 The entry code for black holes abort indicating a cyclic data dependency.
85 It is used to overwrite closures currently being evaluated.
86
87 In the concurrent world, black holes are synchronization points, and they
88 are turned into blocking queues when there are threads waiting for the 
89 evaluation of the closure to finish.
90
91 \begin{code}
92 #ifdef CONCURRENT
93 EXTFUN(EnterNodeCode);
94 EXTFUN(StackUnderflowEnterNode);
95 EXTDATA_RO(BQ_info);
96 #else
97 void raiseError PROTO((StgStablePtr));
98 extern StgStablePtr errorHandler; /* NB: prone to magic-value-ery (WDP 95/12) */
99 #endif
100
101 STGFUN(BH_UPD_entry)
102 {
103 #ifndef CONCURRENT
104     FB_
105     (void) STGCALL1(int,(void *, FILE *),fflush,stdout);
106     (void) STGCALL2(int,(),fprintf,stderr,"Entered a `black hole': the program has a cyclic data dependency.\n");
107
108 # if defined(PROFILING)
109     {
110         CostCentre cc = (CostCentre) CC_HDR(Node);
111         (void) STGCALL5(int,(),fprintf,stderr,"Cost Centre: %s  Module: %s  Group %s\n",cc->label, cc->module, cc->group);
112     }
113 # endif    
114
115 # if defined(TICKY_TICKY)
116     if (RTSflags.TickyFlags.showTickyStats) {
117         (void) STGCALL0(void,(),PrintTickyInfo);
118     }
119 # endif
120
121     (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
122     FE_
123
124 #else /* threads! */
125
126     FB_
127
128 # if 0
129     if ( RTSflags.GranFlags.debug & 0x80 ) 
130       (void) STGCALL4(int,(),fprintf,stderr,"GRAN_CHECK in BH_UPD_entry: Entered a `black hole' @ 0x%x (CurrentTSO @ 0x%x\n ",Node,CurrentTSO);
131 # endif
132
133 # if defined(GRAN)
134     /* Do this before losing its TSO_LINK */
135     STGCALL3(void,(),GranSimBlock,CurrentTSO,CurrentProc,Node); 
136 # endif
137
138     TSO_LINK(CurrentTSO) = Prelude_Z91Z93_closure;
139     SET_INFO_PTR(Node, BQ_info);
140     BQ_ENTRIES(Node) = (W_) CurrentTSO;
141
142 # if defined(GCap) || defined(GCgn)
143     /* If we modify a black hole in the old generation,
144        we have to make sure it goes on the mutables list */
145
146     if(Node <= StorageMgrInfo.OldLim) {
147         MUT_LINK(Node) = (W_) StorageMgrInfo.OldMutables;
148         StorageMgrInfo.OldMutables = Node;
149     } else
150         MUT_LINK(Node) = MUT_NOT_LINKED;
151 # endif
152
153     LivenessReg = LIVENESS_R1;
154     SaveAllStgRegs();
155     TSO_PC1(CurrentTSO) = EnterNodeCode;
156
157     if (DO_QP_PROF) {
158         QP_Event1("GR", CurrentTSO);
159     }
160
161 # ifdef PAR
162     if(RTSflags.ParFlags.granSimStats) {
163         TIME now = CURRENT_TIME;
164         TSO_EXECTIME(CurrentTSO) += now - TSO_BLOCKEDAT(CurrentTSO);
165         TSO_BLOCKCOUNT(CurrentTSO)++;
166         TSO_QUEUE(CurrentTSO) = Q_BLOCKED;
167         TSO_BLOCKEDAT(CurrentTSO) = now;
168         DumpGranEvent(GR_BLOCK, CurrentTSO);
169     }
170 # endif
171
172 # if defined(GRAN)
173     /* CurrentTSO = Prelude_Z91Z93_closure; */
174     ReSchedule(SAME_THREAD);
175 # else
176     ReSchedule(0);
177 # endif
178
179     FE_
180
181 #endif /* threads */
182 }
183
184 /* made external so that debugger can get at it more effectively */
185 STGFUN(BH_SINGLE_entry)
186 {
187     FB_
188
189     (void) STGCALL1(int,(void *, FILE *),fflush,stdout);
190     (void) STGCALL2(int,(),fprintf,stderr,"Entered a single-entry `black hole' --\n");
191     (void) STGCALL2(int,(),fprintf,stderr,"either the compiler made a mistake on single-entryness,\n");
192     (void) STGCALL2(int,(),fprintf,stderr,"or the program has a cyclic data dependency.\n");
193
194 #if defined(PROFILING)
195     {
196         CostCentre cc = (CostCentre) CC_HDR(Node);
197         (void) STGCALL5(int,(),fprintf,stderr, "Cost Centre: %s  Module: %s  Group %s\n",cc->label, cc->module, cc->group);
198     }
199 #endif    
200
201 # if defined(TICKY_TICKY)
202     if (RTSflags.TickyFlags.showTickyStats) {
203         (void) STGCALL0(void,(),PrintTickyInfo);
204     }
205 # endif
206
207 #ifndef CONCURRENT
208     (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
209 #else
210     EXIT(EXIT_FAILURE);
211 #endif
212
213     FE_
214 }
215 \end{code}
216
217 Updatable closures are overwritten with a black hole of a fixed size,
218 @MIN_UPD_SIZE@.
219
220 \begin{code}
221 CAT_DECLARE(BH,BH_K,"BH","BH")  /* just one, shared */
222
223 BH_ITBL(BH_UPD_info,BH_UPD_entry,U,const,EF_);
224 \end{code}
225
226 Single-Entry closures, which are not updated, are also overwritten
227 with a black hole. They have size @MIN_NONUPD_SIZE@.
228
229 \begin{code}
230 BH_ITBL(BH_SINGLE_info,BH_SINGLE_entry,N,const,EF_);
231 \end{code}
232
233 %************************************************************************
234 %*                                                                      *
235 \subsection[static-update-code]{Static update code in update frames}
236 %*                                                                      *
237 %************************************************************************
238
239 This code is pointed to from update frames.  It has to cope with
240 any kind of algebraic return: vectored or unvectored.
241
242 See \tr{SMupdate.lh} for a description of the various update frames
243 and the macros defining their layout.
244
245 On entry to this code:
246 \begin{itemize}
247 \item @R1@ points to a recently created heap object (return in heap) or
248 is dead (return in regs).
249 \item @R2@ points to the info table for the constructor.
250 \item When returning in regs, any of the return-regs (@R3@...) may be live,
251 but aren't used by this code.  They must be preserved.
252 \item @SpB@ points to the topmost word of the update frame.
253 \end{itemize}
254
255 NEW update mechanism (Jan '94):
256
257 When returning to an update frame, we want to jump directly to the
258 update code for the constructor in hand.  Because of the various
259 possible return conventions (all of which must be handled by the
260 generic update frame), we actually end up with a somewhat indirect
261 jump.
262
263 \begin{code}
264
265 STGFUN(StdUpdFrameDirectReturn)
266 {
267     FB_
268     JMP_(UPDATE_CODE(InfoPtr));
269     FE_
270 }
271
272 /*
273    NB: For direct returns to work properly, the name of the routine must be
274    the same as the name of the vector table with vtbl_ removed and DirectReturn
275    appended.  This is all the mangler understands.
276 */
277
278 const
279 W_
280 vtbl_StdUpdFrame[] = {
281     /* at least "MAX_VECTORED_RTN" elements (see GhcConstants.lh) */
282     (W_) StdUpdFrameDirectReturn/*0*/,
283     (W_) StdUpdFrameDirectReturn/*1*/,
284     (W_) StdUpdFrameDirectReturn/*2*/,
285     (W_) StdUpdFrameDirectReturn/*3*/,
286     (W_) StdUpdFrameDirectReturn/*4*/,
287     (W_) StdUpdFrameDirectReturn/*5*/,
288     (W_) StdUpdFrameDirectReturn/*6*/,
289     (W_) StdUpdFrameDirectReturn/*7*/
290 };
291
292 \end{code}
293
294 %************************************************************************
295 %*                                                                      *
296 \subsection[existing-con-update-code]{Update code for existing constructors}
297 %*                                                                      *
298 %************************************************************************
299
300 Here is the standard update code for objects that are returned in the
301 heap (or those which are initially returned in registers, but have
302 already been allocated in the heap earlier in the update chain).  In
303 either case, @Node@ points to the heap object.  The update code grabs
304 the address of the updatee out of the partial update frame (the return
305 address has already been popped), makes the updatee an indirection to
306 @Node@, and returns according to the convention for the constructor.
307
308 \begin{code}
309 #define IND_UPD_TEMPLATE(label, retvector)                      \
310   STGFUN(label)                                                 \
311   {                                                             \
312     FB_                                                         \
313     UPD_EXISTING();     /* Ticky-ticky profiling info */        \
314     /* Update thing off stk with an indirection to Node */      \
315     UPD_IND(GRAB_UPDATEE(SpB), Node);                           \
316     /* Pop the standard update frame */                         \
317     POP_STD_UPD_FRAME()                                         \
318                                                                 \
319     JMP_(retvector);                                            \
320     FE_                                                         \
321   }
322
323 IND_UPD_TEMPLATE(IndUpdRetDir, DIRECT(((P_)RetReg)))
324 IND_UPD_TEMPLATE(IndUpdRetV0, ((P_)RetReg)[RVREL(0)])
325 IND_UPD_TEMPLATE(IndUpdRetV1, ((P_)RetReg)[RVREL(1)])
326 IND_UPD_TEMPLATE(IndUpdRetV2, ((P_)RetReg)[RVREL(2)])
327 IND_UPD_TEMPLATE(IndUpdRetV3, ((P_)RetReg)[RVREL(3)])
328 IND_UPD_TEMPLATE(IndUpdRetV4, ((P_)RetReg)[RVREL(4)])
329 IND_UPD_TEMPLATE(IndUpdRetV5, ((P_)RetReg)[RVREL(5)])
330 IND_UPD_TEMPLATE(IndUpdRetV6, ((P_)RetReg)[RVREL(6)])
331 IND_UPD_TEMPLATE(IndUpdRetV7, ((P_)RetReg)[RVREL(7)])
332 \end{code}
333
334 %************************************************************************
335 %*                                                                      *
336 \subsection[no-update-code]{Code for Erroneous Updates}
337 %*                                                                      *
338 %************************************************************************
339
340 \begin{code}
341
342 STGFUN(UpdErr)
343 {
344     FB_
345
346     fflush(stdout);
347     fprintf(stderr, "Update error: not a constructor!\n");
348     abort();
349
350     FE_
351 }
352
353 STGFUN(StdErrorCode)
354 {
355     FB_
356
357     fflush(stdout);
358     fprintf(stderr, "Standard error: should never happen!\n");
359     abort();
360
361     FE_
362 }
363 \end{code}
364
365 %************************************************************************
366 %*                                                                      *
367 \subsection[permanent-indirections]{Lexical Scoping Updates}
368 %*                                                                      *
369 %************************************************************************
370
371 A function entered without any arguments is updated with an
372 indirection. For lexically scoped profiling we still need to set the
373 cost centre if we enter the PAP. As the indirection is removed by the
374 garbage collector this would not be possible.
375
376 To solve this problem we introduce a permanent indirection which sets
377 the cost centre when entered. The heap profiler ignores the space
378 occupied by it as it would not reside in the heap during normal
379 execution.
380
381 In ticky-land: If we are trying to collect update-entry counts
382 (controlled by an RTS flag), then we must use permanent indirections
383 (the shorting-out of regular indirections loses the counts).
384
385 \begin{code}
386 #if defined(PROFILING) || defined(TICKY_TICKY)
387
388 STGFUN(Perm_Ind_entry)
389 {
390     FB_
391
392     /* Don't add INDs to granularity cost */
393
394     /* Dont: ENT_IND(Node); for ticky-ticky; this ind is here only to help profiling */
395
396     /* Enter PAP cost centre -- lexical scoping only */
397     ENTER_CC_PAP_CL(Node);
398
399     Node = (P_) IND_CLOSURE_PTR((P_) Node);
400
401     /* Dont: ENT_VIA_NODE(); for ticky-ticky; as above */
402
403     InfoPtr=(D_)(INFO_PTR(Node));
404
405     JMP_(ENTRY_CODE(InfoPtr));
406     FE_
407 }
408
409 PERM_IND_ITBL(Perm_Ind_info,Perm_Ind_entry,const,EF_);
410
411 #endif /* PROFILING or TICKY */
412 \end{code}
413
414 %************************************************************************
415 %*                                                                      *
416 \subsection[partial-application-updates]{Partial applications}
417 %*                                                                      *
418 %************************************************************************
419
420 See STG paper implementation section of Partial application updates.
421
422 We jump here when the current function fails an argument satisfaction
423 check.  There can be two reasons for this.  In the usual case, there
424 is an update frame blocking our access to anything deeper on the
425 stack.  We then update the updatee in the frame with a partial
426 application node and squeeze out the update frame.  The other
427 possibility is that we are running threaded code, and we are sitting
428 on the bottom of a stack chunk.  In this case, we still build the
429 partial application, but we have nothing in our hands to update, so we
430 underflow the stack (awakening the previous chunk) and enter the
431 partial application node just built.
432
433 On entry to @UpdatePAP@, we assume the following:
434 \begin{itemize}
435 \item SuB points to topmost word of an update frame or to the bottom of a 
436 stack chunk.
437 \item SpA and SpB point to the topmost words of their respective stacks.
438 \item Node points to the closure which needs more arguments than are there.
439 \end{itemize}
440
441 \begin{code}
442 STGFUN(UpdatePAP)
443 {
444     /* 
445      * Use STG registers for these locals which must survive the HEAP_CHK.
446      * Don't squash Node (R1), because it's an implicit argument.
447      */
448
449 #define NNonPtrWords    (R2.i)
450 #define NPtrWords       (R3.i)
451 #define NArgWords       (R4.i)
452 #define PapSize         (R5.i)
453 #if defined(PROFILING)
454 # define CC_pap ((CostCentre)(R7.p))
455 #endif
456
457     /* These other locals do not have to survive a HEAP_CHK */
458
459     P_ PapClosure;
460     P_ Updatee;
461     P_ p;
462     I_ i;
463
464     FB_
465
466 #if defined(GRAN_COUNT)
467       ++nPAPs;
468 #endif
469
470     NPtrWords    = AREL(SuA - SpA);
471     NNonPtrWords = BREL(SuB - SpB);
472
473     ASSERT(NPtrWords >= 0);
474     ASSERT(NNonPtrWords >= 0);
475
476     NArgWords = NPtrWords + NNonPtrWords + 1;   /* +1 for Node */
477
478 #if defined(PROFILING)
479       /* set "CC_pap" to go in the updatee (see Sansom thesis, p 183) */
480
481     CC_pap /*really cc_enter*/ = (CostCentre) CC_HDR(Node);
482     if (IS_CAF_OR_DICT_OR_SUB_CC(CC_pap) /*really cc_enter*/)
483         CC_pap = CCC;
484 #endif
485
486     if (NArgWords == 1) { 
487
488         /* 
489          * No arguments, only Node.  Skip building the PAP and
490          * just plan to update with an indirection.
491          */
492
493         PapClosure = Node;
494
495     } else {
496    
497         /* Build the PAP.  A generic PAP closure is laid out thus:
498          *      code ptr, size, no of words of ptrs, Node, ptrs, non-ptrs 
499          * (i.e. a DYN closure)
500          * ToDo: add stuff for special cases, to omit size and no. of ptrs 
501          *      (Still ToDo?  (JSM))
502          */
503
504         PapSize = NArgWords + DYN_HS;
505     
506         ALLOC_UPD_PAP(DYN_HS, NArgWords, 0, PapSize);
507         CC_ALLOC(CC_pap, PapSize, PAP_K);
508     
509         /* Allocate PapClosure -- Only Node (R1) is live */
510         HEAP_CHK(LIVENESS_R1, PapSize, 0);
511
512         PapClosure = Hp + 1 - PapSize;  /* The new PapClosure */
513
514         SET_DYN_HDR(PapClosure, PAP_info, CC_pap, NArgWords + DYN_VHS, NPtrWords + 1);
515
516         /* Now fill in the closure fields */
517
518         p = Hp;
519         for (i = NNonPtrWords - 1; i >= 0; i--) *p-- = (W_) SpB[BREL(i)];
520         for (i = NPtrWords    - 1; i >= 0; i--) *p-- = (W_) SpA[AREL(i)];
521         *p = (W_) Node;
522         }
523
524     /* 
525      * Finished constructing PAP closure; now update the updatee.  But
526      * wait!  What if there is no updatee?  Then we fall off the
527      * stack.
528      */
529
530 #ifdef CONCURRENT
531     if (SuB < STKO_BSTK_BOT(StkOReg)) {
532             Node = PapClosure;
533 # ifdef PAR
534             LivenessReg = LIVENESS_R1;
535 # endif
536         JMP_(StackUnderflowEnterNode);
537         }
538 #endif
539
540     /* 
541      * Now we have a standard update frame, so we update the updatee with 
542      * either the new PAP or Node.
543      *
544      * Supposedly, it is not possible to get a constructor update frame,
545      * (Why not?  (JSM))
546      * (Because they have *never* been implemented.  (WDP))
547      */
548
549     Updatee = GRAB_UPDATEE(SuB); 
550     UPD_IND(Updatee, PapClosure);   /* Indirect Updatee to PapClosure */
551
552     if (NArgWords != 1) {
553         UPD_PAP_IN_NEW(NArgWords);
554
555     } else {
556         UPD_PAP_IN_PLACE();     
557
558 #if defined(PROFILING)
559         /* 
560          * Lexical scoping requires a *permanent* indirection, and we
561          * also have to set the cost centre for the indirection.
562          */
563         INFO_PTR(Updatee) = (W_) Perm_Ind_info;
564         SET_CC_HDR(Updatee, CC_pap);
565
566 #endif /* PROFILING */
567     }
568
569 #if defined(PROFILING)
570     /* 
571      * Restore the Cost Centre too (if required); again see Sansom thesis p 183.
572      * Take the CC out of the update frame if a CAF/DICT.
573      */
574
575     CCC = (IS_CAF_OR_DICT_OR_SUB_CC(CC_pap)) ? GRAB_COST_CENTRE(SuB) : CC_pap;
576
577 #endif /* PROFILING */
578
579     /* Restore SuA, SuB, RetReg */
580     RetReg = GRAB_RET(SuB);
581     SuA = GRAB_SuA(SuB);
582     SuB = GRAB_SuB(SuB);
583
584     /* 
585      * Squeeze out update frame from B stack.  Note that despite our best
586      * efforts with [AB]REL and friends, the loop order depends on the B
587      * stack growing up.
588      */
589     for (i = NNonPtrWords - 1; i >= 0; i--) 
590         SpB[BREL(i+STD_UF_SIZE)] = SpB[BREL(i)];
591
592     SpB += BREL(STD_UF_SIZE);
593
594     /* 
595      * All done!  Restart by re-entering Node
596      * Don't count this entry for ticky-ticky profiling. 
597     */
598
599 #if 0 /* defined(GRAN) */
600     GRAN_EXEC(16,4,7,4,0);
601 #endif
602     InfoPtr=(D_)(INFO_PTR(Node));
603     JMP_(ENTRY_CODE(InfoPtr));
604     FE_
605
606 #undef NNonPtrWords
607 #undef NPtrWords
608 #undef NArgWords
609 #undef PapSize
610 #ifdef PROFILING
611 # undef CC_pap
612 #endif
613 }
614 \end{code}
615
616 The entry code for a generic PAP. @Node@ points to the PAP closure.
617 Reload the stacks from the PAP, and enter the closure stored in the
618 PAP. PAPs are in HNF so no update frame is needed.
619
620 \begin{code}
621 STGFUN(PAP_entry)
622 {
623     /* Use STG registers for these locals which must survive the STK_CHK */
624 #define NPtrWords       (R2.i)
625 #define NNonPtrWords    (R3.i)
626 #if defined(PROFILING)
627 # define CC_pap ((CostCentre)(R7.p))
628 #endif
629
630     /* These locals don't have to survive the STK_CHK */
631     P_ Updatee;
632     P_ p;
633     I_ i;
634     I_ aWords, bWords;
635
636     FB_
637
638     while (AREL(SuA - SpA) == 0 && BREL(SuB - SpB) == 0) {
639 #ifdef CONCURRENT
640         if (SuB < STKO_BSTK_BOT(StkOReg)) {
641 # ifdef PAR
642             LivenessReg = LIVENESS_R1;
643 # endif
644             JMP_(StackUnderflowEnterNode);
645         }
646 #endif
647
648         /* We're sitting on top of an update frame, so let's do the business */
649
650         Updatee = GRAB_UPDATEE(SuB);
651         UPD_IND(Updatee, Node);
652
653 #if defined(PROFILING)
654         /* 
655          * Restore the Cost Centre too (if required); again see Sansom
656          * thesis p 183.  Take the CC out of the update frame if a
657          * CAF/DICT.
658          */
659
660         CC_pap = (CostCentre) CC_HDR(Node);
661         CCC = (IS_CAF_OR_DICT_OR_SUB_CC(CC_pap)) ? GRAB_COST_CENTRE(SuB) : CC_pap;
662
663 #endif /* PROFILING */
664
665         RetReg = GRAB_RET(SuB);
666         SuA = GRAB_SuA(SuB);
667         SuB = GRAB_SuB(SuB);
668         SpB += BREL(STD_UF_SIZE);
669     }
670
671     NPtrWords    = DYN_CLOSURE_NoPTRS(Node) - 1; /* The saved Node counts as one */
672     NNonPtrWords = DYN_CLOSURE_NoNONPTRS(Node);
673
674     /* Ticky-ticky profiling info */
675     ENT_PAP(Node);
676
677     /* Enter PAP cost centre -- lexical scoping only */
678     ENTER_CC_PAP_CL(Node);
679
680     /* 
681      * Check for stack overflow.  Ask to take all of the current frame with
682      * us to the new world.  If there is no update frame on the current stack,
683      * bWords will exceed the size of the B stack, but StackOverflow will deal 
684      * with it.
685      */
686
687     aWords = AREL(SuA - SpA);
688     bWords = BREL(SuB - SpB) + STD_UF_SIZE;
689
690     STK_CHK(LIVENESS_R1, NPtrWords, NNonPtrWords, aWords, bWords, 0, 0);
691
692     SpA -= AREL(NPtrWords);
693     SpB -= BREL(NNonPtrWords);
694
695     /* Reload Node */
696     p = Node + DYN_HS;     /* Point to first pointer word */
697     Node = (P_) *p++;
698
699     /* Reload the stacks */
700
701     for (i=0; i<NPtrWords;    i++) SpA[AREL(i)] = (P_) *p++;
702     for (i=0; i<NNonPtrWords; i++) SpB[BREL(i)] = *p++;
703
704     /* Off we go! */
705     ENT_VIA_NODE();
706     InfoPtr=(D_)(INFO_PTR(Node));
707     JMP_(ENTRY_CODE(InfoPtr));
708     FE_
709
710 #undef NPtrWords
711 #undef NNonPtrWords
712 #ifdef PROFILING
713 # undef CC_pap
714 #endif
715 }
716 \end{code}
717
718 The info table for a generic PAP:
719 \begin{code}
720 DYN_ITBL(PAP_info,PAP_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,EF_,PAP_K,"PAP","->");
721 \end{code}