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