[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / rts / Updates.hc
1 /* -----------------------------------------------------------------------------
2  * $Id: Updates.hc,v 1.2 1998/12/02 13:29:00 simonm Exp $
3  *
4  * Code to perform updates.
5  *
6  * ---------------------------------------------------------------------------*/
7
8 #include "Rts.h"
9 #include "RtsUtils.h"
10 #include "HeapStackCheck.h"
11
12 /*
13   The update frame return address must be *polymorphic*, that means
14   we have to cope with both vectored and non-vectored returns.  This
15   is done by putting the return vector right before the info table, and
16   having a standard direct return address after the info table (pointed
17   to by the return address itself, as usual).
18
19   Each entry in the vector table points to a specialised entry code fragment
20   that knows how to return after doing the update.  It would be possible to
21   use a single generic piece of code that simply entered the return value
22   to return, but it's quicker this way.  The direct return code of course
23   just does another direct return when it's finished.
24
25   Why is there necessarily an activation underneath us on the stack?
26   Because if we're returning, that means we've got a constructor in
27   our hands.  If there were any arguments to be applied to it, that
28   would be a type error.  We don't ever return a PAP to an update frame,
29   the update is handled manually by stg_update_PAP.
30 */
31
32 /* on entry to the update code
33    (1) R1 points to the closure being returned
34    (2) R2 contains the tag (if we returned directly, non-vectored)
35    (3) Sp points to the update frame
36    */
37
38 /* Why updatee is placed in a temporary variable here: this helps
39    gcc's aliasing by indicating that the location of the updatee
40    doesn't change across assignments.  Saves one instruction in the
41    update code. 
42    */
43
44 #define UPD_FRAME_ENTRY_TEMPLATE(label,ret)                             \
45         STGFUN(label);                                                  \
46         STGFUN(label)                                                   \
47         {                                                               \
48           StgClosure *updatee;                                          \
49           FB_                                                           \
50           /* tick - ToDo: check this is right */                        \
51           TICK_UPD_EXISTING();                                          \
52                                                                         \
53           updatee = ((StgUpdateFrame *)Sp)->updatee;                    \
54                                                                         \
55           /* update the updatee with an indirection to the return value */\
56           UPD_IND(updatee,R1.p);                                        \
57                                                                         \
58           /* reset Su to the next update frame */                       \
59           Su = ((StgUpdateFrame *)Sp)->link;                            \
60                                                                         \
61           /* remove the update frame from the stack */                  \
62           Sp += sizeofW(StgUpdateFrame);                                \
63                                                                         \
64           JMP_(ret);                                                    \
65           FE_                                                           \
66         }
67
68 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_entry,ENTRY_CODE(Sp[0]));
69 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_0_entry,RET_VEC(Sp[0],0));
70 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_1_entry,RET_VEC(Sp[0],1));
71 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_2_entry,RET_VEC(Sp[0],2));
72 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_3_entry,RET_VEC(Sp[0],3));
73 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_4_entry,RET_VEC(Sp[0],4));
74 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_5_entry,RET_VEC(Sp[0],5));
75 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_6_entry,RET_VEC(Sp[0],6));
76 UPD_FRAME_ENTRY_TEMPLATE(Upd_frame_7_entry,RET_VEC(Sp[0],7));
77
78
79 /*
80   Make sure this table is big enough to handle the maximum vectored
81   return size!
82   */
83
84 #ifdef PROFILING
85 #define UPD_FRAME_BITMAP 3
86 #else
87 #define UPD_FRAME_BITMAP 1
88 #endif
89
90 /* this bitmap indicates that the first word of an update frame is a
91  * non-pointer - this is the update frame link.  (for profiling,
92  * there's a cost-centre-stack in there too).
93  */
94
95 VEC_POLY_INFO_TABLE(Upd_frame,UPD_FRAME_BITMAP, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, UPDATE_FRAME);
96
97 /* -----------------------------------------------------------------------------
98    Entry Code for a PAP.
99
100    The idea is to copy the chunk of stack from the PAP object and then
101    re-enter the function closure that failed it's args check in the
102    first place.
103
104    In fact, we do a little optimisation too, by performing the updates
105    for any update frames sitting on top of the stack. (ToDo: is this
106    really an optimisation? --SDM)
107    -------------------------------------------------------------------------- */
108
109 INFO_TABLE(PAP_info,PAP_entry,/*special layout*/0,0,PAP,const,EF_,0,0);
110 STGFUN(PAP_entry)
111 {
112   nat Words;
113 #ifdef PROFILING
114   CostCentreStack *CCS_pap;
115 #endif
116   P_ p;
117   nat i;
118   StgPAP *pap;
119
120   FB_
121     
122   pap = (StgPAP *) R1.p;
123   
124   /*
125    * remove any update frames on the top of the stack, by just
126    * performing the update here.
127    */
128   while ((W_)Su - (W_)Sp == 0) {
129
130     switch (get_itbl(Su)->type) {
131
132     case UPDATE_FRAME:
133       /* We're sitting on top of an update frame, so let's do the business */
134       UPD_IND(Su->updatee, pap);
135
136 #if defined(PROFILING)
137       /* 
138        * Restore the Cost Centre too (if required); again see Sansom
139        * thesis p 183.  Take the CC out of the update frame if a
140        * CAF/DICT.
141        */
142       
143       CCS_pap = pap->header.prof.ccs;
144       CCCS = (IS_CAF_OR_DICT_OR_SUB_CCS(CCS_pap)) 
145                 ? Su->header.prof.ccs 
146                 : CCS_pap;
147 #endif /* PROFILING */
148       
149       Su = Su->link;
150       Sp += sizeofW(StgUpdateFrame);
151       continue;
152
153     case SEQ_FRAME:
154       /* Just pop the seq frame and return to the activation record
155        * underneath us - R1 already contains the address of the PAP.
156        */
157       Su = ((StgSeqFrame *)Su)->link;
158       Sp += sizeofW(StgSeqFrame);
159       JMP_(ENTRY_CODE(*Sp));
160
161     case CATCH_FRAME:
162       /* can't happen, see stg_update_PAP */
163       barf("PAP_entry: CATCH_FRAME");
164
165     default:
166       barf("PAP_entry: strange activation record");
167     }
168
169   }
170
171   Words = pap->n_args;
172
173   /* 
174    * Check for stack overflow.
175    */
176   STK_CHK(Words,PAP_entry,R2.p,1,);
177   Sp -= Words;
178
179   TICK_ENT_PAP(pap);
180
181   /* Enter PAP cost centre -- lexical scoping only */
182   ENTER_CCS_PAP_CL(pap);
183
184   R1.cl = pap->fun;
185   p = (P_)(pap->payload);
186
187   /* Reload the stack */
188   for (i=0; i<Words; i++) Sp[i] = (W_) *p++;
189
190   /* Off we go! */
191   TICK_ENT_VIA_NODE();
192   JMP_(GET_ENTRY(R1.cl));
193   FE_
194 }
195
196 /* -----------------------------------------------------------------------------
197    stg_update_PAP: Update the current closure with a partial application.
198
199    This function is called whenever an argument satisfaction check fails.
200    -------------------------------------------------------------------------- */
201
202 EXTFUN(stg_update_PAP)
203 {
204   nat Words, PapSize;
205 #ifdef PROFILING
206   CostCentreStack *CCS_pap;
207 #endif
208   StgPAP* PapClosure;
209   StgClosure *Fun, *Updatee;
210   P_ p;
211   I_ i;
212   
213   FB_
214
215     /* Save the pointer to the function closure that just failed the
216        argument satisfaction check
217        */
218     Fun = R1.cl;
219
220 #if defined(GRAN_COUNT)
221 #error Fixme.
222       ++nPAPs;
223 #endif
224
225     /* Just copy the whole block of stack between the stack pointer
226      * and the update frame pointer for now.  This might include some
227      * tagging, which the garbage collector will have to pay attention
228      * to, but it's much easier than sorting the words into pointers
229      * and non-pointers.
230      */
231
232     Words    = (P_)Su - (P_)Sp;
233     ASSERT((int)Words >= 0);
234
235 #if defined(PROFILING)
236     /* set "CC_pap" to go in the updatee (see Sansom thesis, p 183) */
237
238     CCS_pap = (CostCentreStack *) Fun->header.prof.ccs;
239     if (IS_CAF_OR_DICT_OR_SUB_CCS(CCS_pap)) {
240         CCS_pap = CCCS;
241     }
242 #endif
243
244     if (Words == 0) { 
245
246         /* 
247          * No arguments, only Node.  Skip building the PAP and
248          * just plan to update with an indirection.
249          */
250
251         PapClosure = (StgPAP *)Fun;
252
253     } else {
254            /* Build the PAP */
255
256         PapSize = Words + sizeofW(StgPAP);
257     
258         /*
259          * First we need to do a heap check, which involves saving
260          * everything on the stack.  We only have one live pointer:
261          * Fun, the function closure that was passed to us.  If the
262          * heap check fails, we push the function closure on the stack
263          * and instruct the scheduler to try entering it again when
264          * the garbage collector has run.
265          *
266          * It's done this way because there's a possibility that the
267          * garbage collector might have messed around with the stack,
268          * such as removing the update frame.
269          */
270         if ((Hp += PapSize) > HpLim) {
271           Sp -= 1;
272           Sp[0] = (W_)Fun;          
273           JMP_(stg_gc_entertop);
274         }
275
276         TICK_ALLOC_UPD_PAP(DYN_HS, NArgWords, 0, PapSize);
277 #ifdef PROFILING
278         CCS_ALLOC(CCS_pap, PapSize);
279 #endif
280     
281         PapClosure = (StgPAP *)(Hp + 1 - PapSize); /* The new PapClosure */
282
283         SET_HDR(PapClosure,&PAP_info,CCS_pap);
284         PapClosure->n_args = Words;
285         PapClosure->fun = Fun;
286
287         /* Now fill in the closure fields */
288
289         p = Hp;
290         for (i = Words-1; i >= 0; i--) {
291            *p-- = (W_) Sp[i];
292         }
293     }
294
295     /* 
296      * Finished constructing PAP closure; now update the updatee. 
297      */
298
299     /* ToDo: we'd like to just jump to the code for PAP_entry here,
300      * which deals with a stack of update frames in one go.  What to
301      * do about the special ticky and profiling stuff here?
302      */
303
304     switch (get_itbl(Su)->type) {
305
306     case SEQ_FRAME:
307       /* Set Sp to just above the SEQ frame (should be an activation rec.)*/
308       Sp = stgCast(StgPtr,Su) + sizeofW(StgSeqFrame);
309
310       /* restore Su */
311       Su = stgCast(StgSeqFrame*,Su)->link;
312         
313       /* return to the activation record, with the address of the PAP in R1 */
314       R1.p = (P_)PapClosure;
315       JMP_(ENTRY_CODE(*Sp));
316       
317     case CATCH_FRAME:
318       /* Set Sp to just above the CATCH frame (should be an activation rec.)*/
319       Sp = stgCast(StgPtr,Su) + sizeofW(StgCatchFrame);
320
321       /* restore Su */
322       Su = stgCast(StgCatchFrame*,Su)->link;
323         
324       /* restart by entering the PAP */
325       R1.p = (P_)PapClosure;
326       JMP_(GET_ENTRY(R1.cl));
327       
328     case UPDATE_FRAME:
329       /* 
330        * Now we have a standard update frame, so we update the updatee with 
331        * either the new PAP or Node.
332        */
333       
334       Updatee = Su->updatee; 
335       UPD_IND(Updatee,PapClosure);
336       
337       if (Words != 0) {
338         TICK_UPD_PAP_IN_NEW(NArgWords);
339         
340       } else {
341         TICK_UPD_PAP_IN_PLACE();
342         
343 #if defined(PROFILING)
344         /* 
345          * Lexical scoping requires a *permanent* indirection, and we
346          * also have to set the cost centre for the indirection.
347          */
348         SET_INFO(Updatee, &IND_PERM_info);
349         Updatee->header.prof.ccs = CCS_pap;
350 #endif /* PROFILING */
351       }
352       
353 #if defined(PROFILING)
354       /* 
355        * Restore the Cost Centre too (if required); again see Sansom
356        * thesis p 183.  Take the CC out of the update frame if a CAF/DICT.
357        */
358       CCCS = IS_CAF_OR_DICT_OR_SUB_CCS(CCS_pap)
359                 ? Su->header.prof.ccs 
360                 : CCS_pap;
361 #endif /* PROFILING */
362       
363       /* Restore Su */
364       Su = Su->link;
365       
366       /* 
367        * Squeeze out update frame from stack.
368        */
369       for (i = Words-1; i >= 0; i--) {
370         Sp[i+(sizeofW(StgUpdateFrame))] = Sp[i];
371       }
372       Sp += sizeofW(StgUpdateFrame);
373       break;
374       
375     default:
376       barf("stg_update_PAP: strange activation record");
377     }   
378
379     /* 
380      * All done!  Restart by re-entering Node
381      * Don't count this entry for ticky-ticky profiling. 
382      */
383     JMP_(GET_ENTRY(R1.cl));
384     FE_
385
386
387
388 /* -----------------------------------------------------------------------------
389    Entry Code for an AP_UPD.
390
391    The idea is to copy the chunk of stack from the AP object and then
392    enter the function closure.
393
394    (This code is a simplified copy of the PAP code - with all the 
395     update frame code stripped out.)
396    -------------------------------------------------------------------------- */
397
398
399 INFO_TABLE(AP_UPD_info,AP_UPD_entry,/*special layout*/0,0,AP_UPD,const,EF_,0,0);
400 STGFUN(AP_UPD_entry)
401 {
402   nat Words;
403   P_ p;
404   nat i;
405   StgAP_UPD *ap;
406
407   FB_
408     
409   ap = (StgAP_UPD *) R1.p;
410   
411   Words = ap->n_args;
412
413   /* 
414    * Check for stack overflow.
415    */
416   STK_CHK(Words+sizeofW(StgUpdateFrame),AP_UPD_entry,R2.p,1,);
417
418   PUSH_UPD_FRAME(R1.p, 0);
419   Sp -= sizeofW(StgUpdateFrame) + Words;
420
421   TICK_ENT_PAP(ap);  /* ToDo: TICK_ENT_AP_UPD */
422
423   /* Enter PAP cost centre -- lexical scoping only */
424   ENTER_CCS_PAP_CL(ap);   /* ToDo: ENTER_CC_AP_UPD_CL */
425
426   R1.cl = ap->fun;
427   p = (P_)(ap->payload);
428
429   /* Reload the stack */
430   for (i=0; i<Words; i++) Sp[i] = (W_) *p++;
431
432   /* Off we go! */
433   TICK_ENT_VIA_NODE();
434   JMP_(GET_ENTRY(R1.cl));
435   FE_
436 }
437
438
439 /*-----------------------------------------------------------------------------
440   Seq frames 
441
442   We don't have a primitive seq# operator: it is just a 'case'
443   expression whose scrutinee has either a polymorphic or function type
444   (constructor types can be handled by normal 'case' expressions).
445
446   To handle a polymorphic/function typed seq, we push a SEQ_FRAME on
447   the stack.  This is a polymorphic activation record that just pops
448   itself and returns when entered.  The purpose of the SEQ_FRAME is to
449   act as a barrier in case the scrutinee is a partial application - in
450   this way it is just like an update frame, except that it doesn't
451   update anything.
452   -------------------------------------------------------------------------- */
453
454 #define SEQ_FRAME_ENTRY_TEMPLATE(label,ret)     \
455    IFN_(label)                                  \
456    {                                            \
457       FB_                                       \
458       Su = stgCast(StgSeqFrame*,Sp)->link;      \
459       Sp += sizeofW(StgSeqFrame);               \
460       JMP_(ret);                                \
461       FE_                                       \
462    }
463
464 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_entry,  ENTRY_CODE(Sp[0]));
465 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_0_entry,ENTRY_CODE(Sp[0]));
466 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_1_entry,ENTRY_CODE(Sp[0]));
467 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_2_entry,ENTRY_CODE(Sp[0]));
468 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_3_entry,ENTRY_CODE(Sp[0]));
469 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_4_entry,ENTRY_CODE(Sp[0]));
470 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_5_entry,ENTRY_CODE(Sp[0]));
471 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_6_entry,ENTRY_CODE(Sp[0]));
472 SEQ_FRAME_ENTRY_TEMPLATE(seq_frame_7_entry,ENTRY_CODE(Sp[0]));
473
474 VEC_POLY_INFO_TABLE(seq_frame,1, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, SEQ_FRAME);
475
476 /* -----------------------------------------------------------------------------
477  * The seq infotable
478  *
479  * This closure takes one argument, which it evaluates and returns the
480  * result with a direct return (never a vectored return!) in R1.  It
481  * does this by pushing a SEQ_FRAME on the stack and
482  * entering its argument.
483  *
484  * It is used in deleteThread when reverting blackholes.
485  * -------------------------------------------------------------------------- */
486
487 INFO_TABLE(seq_info,seq_entry,1,0,FUN,const,EF_,0,0);
488 STGFUN(seq_entry)
489 {
490   FB_
491   STK_CHK_GEN(sizeofW(StgSeqFrame), NO_PTRS, seq_entry, );
492   Sp -= sizeof(StgSeqFrame);
493   PUSH_SEQ_FRAME(Sp);
494   R1.cl = R1.cl->payload[0];
495   JMP_(ENTRY_CODE(*R1.p));         
496   FE_
497 }
498
499
500 /* -----------------------------------------------------------------------------
501    Exception Primitives
502    -------------------------------------------------------------------------- */
503
504 FN_(catchZh_fast);
505 FN_(raiseZh_fast);
506
507 #define CATCH_FRAME_ENTRY_TEMPLATE(label,ret)   \
508    FN_(label);                                  \
509    FN_(label)                                   \
510    {                                            \
511       FB_                                       \
512       Su = ((StgCatchFrame *)Sp)->link;         \
513       Sp += sizeofW(StgCatchFrame);             \
514       JMP_(ret);                                \
515       FE_                                       \
516    }
517
518 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_entry,ENTRY_CODE(Sp[0]));
519 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_0_entry,RET_VEC(Sp[0],0));
520 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_1_entry,RET_VEC(Sp[0],1));
521 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_2_entry,RET_VEC(Sp[0],2));
522 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_3_entry,RET_VEC(Sp[0],3));
523 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_4_entry,RET_VEC(Sp[0],4));
524 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_5_entry,RET_VEC(Sp[0],5));
525 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_6_entry,RET_VEC(Sp[0],6));
526 CATCH_FRAME_ENTRY_TEMPLATE(catch_frame_7_entry,RET_VEC(Sp[0],7));
527
528 #ifdef PROFILING
529 #define CATCH_FRAME_BITMAP 3
530 #else
531 #define CATCH_FRAME_BITMAP 1
532 #endif
533
534 /* Catch frames are very similar to update frames, but when entering
535  * one we just pop the frame off the stack and perform the correct
536  * kind of return to the activation record underneath us on the stack.
537  */
538
539 VEC_POLY_INFO_TABLE(catch_frame, CATCH_FRAME_BITMAP, NULL/*srt*/, 0/*srt_off*/, 0/*srt_len*/, CATCH_FRAME);
540
541 /* -----------------------------------------------------------------------------
542  * The catch infotable
543  *
544  * This should be exactly the same as would be generated by this STG code
545  *
546  * catch = {x,h} \n {} -> catch#{x,h}
547  *
548  * It is used in deleteThread when reverting blackholes.
549  * -------------------------------------------------------------------------- */
550
551 INFO_TABLE(catch_info,catch_entry,2,0,FUN,const,EF_,0,0);
552 STGFUN(catch_entry)
553 {
554   FB_
555   R2.cl = payloadCPtr(R1.cl,1); /* h */
556   R1.cl = payloadCPtr(R1.cl,0); /* x */
557   JMP_(catchZh_fast);
558   FE_
559 }
560
561 FN_(catchZh_fast)
562 {
563   StgCatchFrame *fp;
564   FB_
565
566     /* args: R1 = m, R2 = k */
567     STK_CHK_GEN(sizeofW(StgCatchFrame), R1_PTR | R2_PTR, catchZh_fast, );
568     Sp -= sizeofW(StgCatchFrame);
569     fp = stgCast(StgCatchFrame*,Sp);
570     SET_HDR(fp,(StgInfoTable *)&catch_frame_info,CCCS);
571     fp -> handler = R2.cl;
572     fp -> link = Su;
573     Su = stgCast(StgUpdateFrame*,fp);
574     TICK_ENT_VIA_NODE();
575     JMP_(ENTRY_CODE(*R1.p));         
576     
577   FE_
578 }      
579
580 /* -----------------------------------------------------------------------------
581  * The raise infotable
582  * 
583  * This should be exactly the same as would be generated by this STG code
584  *
585  *   raise = {err} \n {} -> raise#{err}
586  *
587  * It is used in raiseZh_fast to update thunks on the update list
588  * -------------------------------------------------------------------------- */
589
590 INFO_TABLE(raise_info,raise_entry,1,0,FUN,const,EF_,0,0);
591 STGFUN(raise_entry)
592 {
593   FB_
594   R1.cl = payloadCPtr(R1.cl,0);
595   JMP_(raiseZh_fast);
596   FE_
597 }
598
599 FN_(raiseZh_fast)
600 {
601   StgClosure *handler;
602   StgUpdateFrame *p;
603   FB_
604     /* args : R1 = error */
605
606     p = Su;
607
608     while (1) {
609
610       switch (get_itbl(p)->type) {
611
612       case UPDATE_FRAME:
613         UPD_INPLACE1(p->updatee,&raise_info,R1.cl);
614         p = p->link;
615         continue;
616
617       case SEQ_FRAME:
618         p = stgCast(StgSeqFrame*,p)->link;
619         continue;
620
621       case CATCH_FRAME:
622         /* found it! */
623         break;
624
625       case STOP_FRAME:
626         barf("raiseZh_fast: STOP_FRAME");
627
628       default:
629         barf("raiseZh_fast: weird activation record");
630       }
631       
632       break;
633
634     }
635     
636     /* Ok, p points to the enclosing CATCH_FRAME.  Pop everything down to
637      * and including this frame, update Su, push R1, and enter the handler.
638      */
639     Su = ((StgCatchFrame *)p)->link; 
640     handler = ((StgCatchFrame *)p)->handler;
641     
642     Sp = stgCast(StgPtr,p) + sizeofW(StgCatchFrame) - 1;
643     *Sp = R1.w;
644
645     TICK_ENT_VIA_NODE();
646     R1.cl = handler;
647     JMP_(ENTRY_CODE(handler->header.info));
648     
649   FE_
650 }
651