[project @ 1997-10-30 22:29:59 by sof]
[ghc-hetmet.git] / ghc / runtime / main / StgStartup.lhc
1 %/****************************************************************
2 %*                                                              *
3 %*   Basic Continuations required by the STG Machine runtime    *
4 %*                                                              *
5 %****************************************************************/
6
7
8 First continuation called by the mini-interpreter is
9 evaluateTopClosure.  It has to set up return and jump to the user's
10 @main@ closure.  If @errorIO@ is called, we will be back here, doing
11 the same thing for the specified continuation.
12
13 \begin{code}
14 #define MAIN_REG_MAP        /* STG world */
15 #include "rtsdefs.h"
16
17 #if 0
18 #ifdef PAR
19 #include "Statistics.h"
20 #endif
21 #endif
22
23 /* ptr to the user's "main" closure (or "errorIO" arg closure),
24    to which we hope to be linked
25 */
26 extern P_ TopClosure;
27
28 EXTFUN(stopThreadDirectReturn);
29 UNVECTBL(,vtbl_stopStgWorld,stopThreadDirectReturn)
30
31 /* Well, we have to put the ArrayOfData and ArrayOfPtrs info tables
32    somewhere...
33 */
34
35 /* Array of data -- mutable */
36 STATICFUN(ArrayOfData_entry)
37 {
38     FB_
39     /* Don't wrap the calls; we're done with STG land */
40     fflush(stdout);
41     fprintf(stderr, "Entered a primitive array (of data)---this shouldn't happen!\n");
42     abort();
43     FE_
44 }
45
46 DATA_ITBL(ArrayOfData_info,ArrayOfData_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"DATA-ARRAY","ARRAY");
47 /* ToDo: could put a useful tag in there!!! */
48
49 /* Array of pointers -- mutable */
50 STATICFUN(ArrayOfPtrs_entry)
51 {
52     FB_
53     /* Don't wrap the calls; we're done with STG land */
54     fflush(stdout);
55     fprintf(stderr, "Entered a primitive array (of pointers)---this shouldn't happen!\n");
56     abort();
57     FE_
58 }
59
60 MUTUPLE_ITBL(ArrayOfPtrs_info,ArrayOfPtrs_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"PTR-ARRAY(mut)","ARRAY");
61 /* ToDo: could put a useful tag in there!!! */
62
63 STATICFUN(FullSVar_entry)
64 {
65     FB_
66     /* Don't wrap the calls; we're done with STG land */
67     fflush(stdout);
68     fprintf(stderr, "Entered a full SVar---this shouldn't happen!\n");
69     abort();
70     FE_
71 }
72
73 MUTUPLE_ITBL(FullSVar_info,FullSVar_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"FullSVar","ARRAY");
74 /* ToDo: could put a useful tag in there!!! */
75
76 STATICFUN(EmptySVar_entry)
77 {
78     FB_
79     /* Don't wrap the calls; we're done with STG land */
80     fflush(stdout);
81     fprintf(stderr, "Entered an empty SVar---this shouldn't happen!\n");
82     abort();
83     FE_
84 }
85
86 MUTUPLE_ITBL(EmptySVar_info,EmptySVar_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"EmptySVar","ARRAY");
87 /* ToDo: could put a useful tag in there!!! */
88
89 /* Array of pointers -- immutable */
90 STATICFUN(ImMutArrayOfPtrs_entry)
91 {
92     FB_
93     /* Don't wrap the calls; we're done with STG land */
94     fflush(stdout);
95     fprintf(stderr, "Entered a primitive array (immutable, pointers)---this shouldn't happen!\n");
96     abort();
97     FE_
98 }
99
100 IMMUTUPLE_ITBL(ImMutArrayOfPtrs_info,ImMutArrayOfPtrs_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"PTR-ARRAY(immut)","ARRAY");
101 /* ToDo: could put a useful tag in there!!! */
102
103 /* (end of Array whatnot) */
104
105 /* Question for Will: There seem to be a lot of these static things
106 now - worth putting them in a file by themselves?? [ADR] */
107
108
109 #if !defined(PAR) /* && !defined(GRAN) */
110
111 /* Ditto for Foreign Object entry point and info tables. [ADR]
112
113    BTW Will, I copied most of this blindly from above - what's with
114    this TAG stuff? And what kind of description/ type is wanted here?
115 */
116
117 STATICFUN(ForeignObj_entry)
118 {
119     FB_
120     /* Don't wrap the calls; we're done with STG land */
121     fflush(stdout);
122     fprintf(stderr, "Compiler bug: Entered a ForeignObj---this shouldn't happen!\n");
123     abort();
124     FE_
125 }
126
127 ForeignObj_ITBL(ForeignObj_info,ForeignObj_entry,UpdErr,0,INFO_OTHER_TAG,,,const,EF_,ForeignObj_K,"FOREIGN_OBJ","ForeignObj");
128
129 /* End of ForeignObj stuff */
130
131 /* Ditto for the unused Stable Pointer info table. [ADR]
132 */
133
134 void raiseError PROTO((StgStablePtr));
135 extern StgStablePtr errorHandler; /* NB: prone to magic-value-ery (WDP 95/12) */
136
137 /* Unused Stable Pointer (ie unused slot in a stable pointer table) */
138 STATICFUN(UnusedSP_entry)
139 {
140     FB_
141     (void) SAFESTGCALL1(I_,(void *, FILE *),fflush,stdout);
142     (void) SAFESTGCALL2(I_,(void *, FILE *, char *),fprintf,stderr, "Entered an unused Stable Pointer---this shouldn't happen!\n(This could be program error (using stable pointer after freeing) or compiler bug.)\n");
143
144     (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
145     FE_
146 }
147
148 STATIC_ITBL(UnusedSP_info,UnusedSP_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,CON_K,"UNUSED_STABLE_PTR","USP");
149
150 SET_STATIC_HDR(UnusedSP_closure,UnusedSP_info,CC_SUBSUMED,,ED_RO_)
151 };
152
153 /* Entry point and Info table for Stable Pointer Table. */
154
155 STATICFUN(EmptyStablePointerTable_entry)
156 {
157     FB_
158     /* Don't wrap the calls; we're done with STG land */
159     fflush(stdout);
160     fprintf(stderr, "Entered *empty* stable pointer table---this shouldn't happen!\n");
161     abort();
162     FE_
163 }
164
165 STATICFUN(StablePointerTable_entry)
166 {
167     FB_
168     /* Don't wrap the calls; we're done with STG land */
169     fflush(stdout);
170     fprintf(stderr, "Entered the stable pointer table---this shouldn't happen!\n");
171     abort();
172     FE_
173 }
174
175 STATIC_ITBL(EmptyStablePointerTable_info,EmptyStablePointerTable_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,SPT_K,"SP_TABLE","SP_TABLE");
176 /* ToDo: could put a useful tag in there!!! */
177
178 DYN_ITBL(StablePointerTable_info,StablePointerTable_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,SPT_K,"SP_TABLE","SP_TABLE");
179 /* ToDo: could put a useful tag in there!!! */
180
181
182 /* To ease initialisation of the heap, we start with an empty stable
183    pointer table.  When we try to create the first stable pointer, the
184    overflow will trigger creation of a table of useful size.
185 */
186
187 SET_STATIC_HDR(EmptySPTable_closure,EmptyStablePointerTable_info,CC_SUBSUMED,,ED_RO_)
188 , (W_) DYN_VHS + 0 + 1 + 0  /* size = DYN_VHS + n + 1 + n with n = 0 */
189 , (W_) 0   /* number of ptrs */
190 , (W_) 0   /* top of stack */
191 };
192
193 /* End of SP stuff */
194 #endif /* !PAR */
195
196
197 /* the IoWorld token to start the whole thing off */
198 /* Question: this is just an amusing hex code isn't it
199    -- or does it mean something? ADR */
200 P_ realWorldZh_closure = (P_) 0xbadbadbaL;
201 P_ GHC_void_closure = (P_) 0xbadbadbaL;
202
203 #ifndef CONCURRENT
204
205 STGFUN(startStgWorld)
206 {
207     FB_
208     /* At this point we are in the threaded-code world.
209
210        TopClosure points to a closure of type PrimIO (), which should be
211        performed (by applying it to the state of the world).
212
213        The smInfo storage-management info block is assumed to be
214        up to date, and is used to load the STG registers.
215     */
216
217     RestoreAllStgRegs();    /* inline! */
218
219     /* ------- STG registers are now valid! -------------------------*/
220
221     /* Put a suitable return address on the B stack */
222     RetReg = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld); 
223
224     /* Put an IoWorld token on the A stack */
225     SpB -= BREL(1);
226     *SpB = (P_) realWorldZh_closure;
227
228     Node = (P_) TopClosure; /* Point to the closure for main/errorIO-arg */
229     ENT_VIA_NODE();
230     InfoPtr=(D_)(INFO_PTR(Node));
231     JMP_(ENTRY_CODE(InfoPtr));
232     FE_
233 }
234 #endif  /* ! CONCURRENT */
235
236 \end{code}
237
238 %************************************************************************
239 %*                                                                      *
240 \subsection[thread-return]{Polymorphic end-of-thread code}
241 %*                                                                      *
242 %************************************************************************
243
244 \begin{code}
245
246 /* 
247    Here's the polymorphic return for the end of a thread.
248
249    NB: For direct returns to work properly, the name of the routine must be
250    the same as the name of the vector table with vtbl_ removed and DirectReturn
251    appended.  This is all the mangler understands.
252 */
253
254 const W_
255 vtbl_stopThread[] = {
256   /* at least "MAX_VECTORED_RTN" elements (see GhcConstants.lh) */
257   (W_) stopThreadDirectReturn,
258   (W_) stopThreadDirectReturn,
259   (W_) stopThreadDirectReturn,
260   (W_) stopThreadDirectReturn,
261   (W_) stopThreadDirectReturn,
262   (W_) stopThreadDirectReturn,
263   (W_) stopThreadDirectReturn,
264   (W_) stopThreadDirectReturn
265 };
266
267 STGFUN(stopThreadDirectReturn)
268 {
269     FB_
270     /* The final exit.
271
272        The top-top-level closures (e.g., "main") are of type "IO ()".
273        When entered, they perform an IO action and return a () --
274        essentially, TagReg is set to 1.  Here, we don't need to do
275        anything with that.
276
277        We just tidy up the register stuff (real regs in *_SAVE, then 
278        *_SAVE -> smInfo locs).
279     */
280
281 #ifdef CONCURRENT
282     SET_TASK_ACTIVITY(ST_OVERHEAD);
283 #endif
284
285     SaveAllStgRegs();   /* inline! */
286
287 #ifdef CONCURRENT
288     EndThread();
289 #else
290     RESUME_(miniInterpretEnd);
291 #endif
292     FE_
293 }
294
295 \end{code}  
296
297 \begin{code}
298 I_ ErrorIO_call_count = 0;
299
300 #ifdef CONCURRENT
301 EXTFUN(EnterNodeCode);
302
303 STGFUN(ErrorIO_innards)
304     /* Assumes that "TopClosure" has been set already */
305 {
306     FB_
307     if (ErrorIO_call_count >= 16 /* MAGIC CONSTANT */ ) {
308         /* Don't wrap the calls; we're done with STG land */
309         fflush(stdout);
310         fprintf(stderr, "too many nested calls to `error'\n");
311         EXIT(EXIT_FAILURE);
312     }
313     ErrorIO_call_count++; /* NB: undo later if decide to let someone else handle it */
314
315     /* Unlock all global closures held by this thread! (ToDo) --JSM */
316
317     switch(TSO_TYPE(CurrentTSO)) {
318     case T_MAIN:
319         /* Re-initialize stack pointers (cf. NewThread) */
320 #ifdef PAR
321         SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
322         SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
323 #else
324         SuA = stackInfo.botA + AREL(1);
325         SuB = stackInfo.botB + BREL(1);
326         /* HWL */
327         /* 
328         SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
329         SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
330         */
331    
332 #endif
333         break;
334
335     case T_REQUIRED:
336         /* Re-initialize stack pointers (cf. NewThread) */
337         SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
338         SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
339         break;
340
341     case T_ADVISORY:
342         ErrorIO_call_count--; /* undo the damage, as someone else will deal with it */
343         /* Let the main thread eventually handle it */
344         JMP_(stopThreadDirectReturn);
345
346     case T_FAIL:
347         EXIT(EXIT_FAILURE);
348
349     default:
350         /* Don't wrap the calls; we're done with STG land */
351         fflush(stdout);
352         fprintf(stderr,"ErrorIO: %lx unknown\n", TSO_TYPE(CurrentTSO));
353         EXIT(EXIT_FAILURE);
354     }
355
356     /* Finish stack setup as if for a top-level task and enter the error node */
357
358     /* Put an IoWorld token on the B stack */
359     SpB -= BREL(1);
360     *SpB = (P_) realWorldZh_closure;
361 /*
362     SpA = SuA - AREL(1);
363     *SpA = (P_) realWorldZh_closure;
364 */
365     STKO_LINK(StkOReg) = PrelBase_Z91Z93_closure;
366     STKO_RETURN(StkOReg) = NULL;
367
368 #ifdef TICKY_TICKY
369     STKO_ADEP(StkOReg) = STKO_BDEP(StkOReg) = 0;
370 #endif
371
372     /* Go! */
373     Node = (P_) TopClosure;
374     RetReg = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld);
375     JMP_(EnterNodeCode);
376
377     FE_
378 }
379 \end{code}
380
381 We cannot afford to call @error@ too many times
382 (e.g., \tr{error x where x = error x}), so we keep count.
383
384 \begin{code}
385 #else   /* !CONCURRENT */
386
387 StgFunPtr
388 ErrorIO_innards(STG_NO_ARGS)
389     /* Assumes that "TopClosure" has been set already */
390 {
391     FB_
392     if (ErrorIO_call_count >= 16 /* MAGIC CONSTANT */ ) {
393         /* Don't wrap the calls; we're done with STG land */
394         fflush(stdout);
395         fprintf(stderr, "too many nested calls to `error'\n");
396         EXIT(EXIT_FAILURE);
397     }
398     ErrorIO_call_count++;
399
400     /* Copy the heap-related registers into smInfo.  (Other registers get
401        saved in this process, but we aren't interested in them.)
402
403        Get a new stack (which re-initialises the smInfo stack stuff),
404        and start the world again.
405     */
406     /* ToDo: chk this has been handled in parallel world */
407
408     SaveAllStgRegs();   /* inline! */
409
410     if (! initStacks( &StorageMgrInfo )) {
411         /* Don't wrap the calls; we're done with STG land */
412         fflush(stdout);
413         fprintf(stderr, "initStacks failed!\n");
414         EXIT(EXIT_FAILURE);
415     }
416
417     JMP_( startStgWorld );
418     FE_
419 }
420
421 #endif  /* !CONCURRENT */
422 \end{code}  
423
424 \begin{code}
425 #if defined(PAR) || defined(GRAN) 
426
427 STATICFUN(RBH_Save_0_entry)
428 {
429   FB_
430   fprintf(stderr,"Oops, entered an RBH save\n");
431   EXIT(EXIT_FAILURE);
432   FE_
433 }
434
435 STATICFUN(RBH_Save_1_entry)
436 {
437   FB_
438   fprintf(stderr,"Oops, entered an RBH save\n");
439   EXIT(EXIT_FAILURE);
440   FE_
441 }
442
443 STATICFUN(RBH_Save_2_entry)
444 {
445   FB_
446   fprintf(stderr,"Oops, entered an RBH save\n");
447   EXIT(EXIT_FAILURE);
448   FE_
449 }
450
451 SPEC_N_ITBL(RBH_Save_0_info,RBH_Save_0_entry,UpdErr,0,INFO_OTHER_TAG,2,0,,IF_,INTERNAL_KIND,"RBH-SAVE","RBH_Save_0");
452 SPEC_N_ITBL(RBH_Save_1_info,RBH_Save_1_entry,UpdErr,0,INFO_OTHER_TAG,2,1,,IF_,INTERNAL_KIND,"RBH-SAVE","RBH_Save_1");
453 SPEC_N_ITBL(RBH_Save_2_info,RBH_Save_2_entry,UpdErr,0,INFO_OTHER_TAG,2,2,,IF_,INTERNAL_KIND,"RBH-SAVE","RBH_Save_2");
454
455 #endif /* PAR || GRAN */
456 \end{code}
457
458
459 %/****************************************************************
460 %*                                                              *
461 %*              Other Bits and Pieces                           *
462 %*                                                              *
463 %****************************************************************/
464
465 \begin{code}
466 /* If we don't need the slow entry code for a closure, we put in a
467    pointer to this in the closure's slow entry code pointer instead.
468  */
469
470 STGFUN(__std_entry_error__) {
471     FB_
472     /* Don't wrap the calls; we're done with STG land */
473     fflush(stdout);
474     fprintf(stderr, "Called non-existent slow-entry code!!!\n");
475     abort();
476     JMP_(0);
477     FE_
478 }
479
480 /* entry code */
481 STGFUN(STK_STUB_entry) {
482     FB_
483     /* Don't wrap the calls; we're done with STG land */
484     fflush(stdout);
485     fprintf(stderr, "Entered from a stubbed stack slot!\n");
486     abort();
487     JMP_(0);
488     FE_
489 }
490
491 /* info table */
492 STATIC_ITBL(STK_STUB_info,STK_STUB_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,EF_,INTERNAL_KIND,"STK_STUB","STK_STUB");
493
494 /* closure */
495 SET_STATIC_HDR(STK_STUB_closure,STK_STUB_info,CC_SUBSUMED,,EXTDATA_RO)
496   , (W_)0, (W_)0
497 };
498 \end{code}
499
500 %/****************************************************************
501 %*                                                              *
502 %*              Some GC info tables                           *
503 %*                                                              *
504 %****************************************************************/
505
506 These have to be in a .lhc file, so they will be reversed correctly.
507
508 \begin{code}
509 #include "../storage/SMinternal.h"
510
511 #if defined(_INFO_COPYING)
512
513 STGFUN(Caf_Evac_Upd_entry) {
514     FB_
515     /* Don't wrap the calls; we're done with STG land */
516     fflush(stdout);
517     fprintf(stderr,"Entered Caf_Evac_Upd %lx: Should never occur!\n", (W_) Node);
518     abort();
519     FE_
520 }
521
522 CAF_EVAC_UPD_ITBL(Caf_Evac_Upd_info,Caf_Evac_Upd_entry,const/*not static*/);
523
524 #if defined(GCgn)
525
526 STGFUN(Forward_Ref_New_entry) {
527     FB_
528     /* Don't wrap the calls; we're done with STG land */
529     fflush(stdout);
530     fprintf(stderr,"Entered Forward_Ref_New %lx: Should never occur!\n", (W_) Node);
531     EXIT(EXIT_FAILURE); /* abort(); */
532     FE_
533 }
534 FORWARDREF_ITBL(Forward_Ref_New_info,Forward_Ref_New_entry,const/*not static*/,_Evacuate_Old_Forward_Ref);
535
536 STGFUN(Forward_Ref_Old_entry) {
537     FB_
538     /* Don't wrap the calls; we're done with STG land */
539     fflush(stdout);
540     fprintf(stderr,"Entered Forward_Ref_Old %lx: Should never occur!\n", (W_) Node);
541     EXIT(EXIT_FAILURE); /*    abort(); */
542     FE_
543 }
544 FORWARDREF_ITBL(Forward_Ref_Old_info,Forward_Ref_Old_entry,const/*not static*/,_Evacuate_New_Forward_Ref);
545
546 STGFUN(OldRoot_Forward_Ref_entry) {
547     FB_
548     /* Don't wrap the calls; we're done with STG land */
549     fflush(stdout);
550     fprintf(stderr,"Entered OldRoot_Forward_Ref %lx: Should never occur!\n", (W_) Node);
551     EXIT(EXIT_FAILURE); /*    abort(); */
552     FE_
553 }
554 FORWARDREF_ITBL(OldRoot_Forward_Ref_info,OldRoot_Forward_Ref_entry,const/*not static*/,_Evacuate_OldRoot_Forward);
555 #else /* ! GCgn */
556
557 STGFUN(Forward_Ref_entry) {
558     FB_
559     /* Don't wrap the calls; we're done with STG land */
560     fflush(stdout);
561     fprintf(stderr,"Entered Forward_Ref %lx: Should never occur!\n", (W_) Node);
562     EXIT(EXIT_FAILURE); /*    abort(); */
563     FE_
564 }
565 FORWARDREF_ITBL(Forward_Ref_info,Forward_Ref_entry,const/*not static*/,_Evacuate_Forward_Ref);
566 #endif /* ! GCgn */
567
568 #endif /* _INFO_COPYING */
569
570 #if defined(GCgn)
571 OLDROOT_ITBL(OldRoot_info,Ind_Entry,const,EF_);
572 #endif /* GCgn */
573 \end{code}
574
575
576 %/***************************************************************
577 %*                                                              *
578 %*              Cost Centre stuff ...                           *
579 %*                                                              *
580 %****************************************************************/
581
582 For cost centres we need prelude cost centres and register routine.
583
584 N.B. ALL prelude cost centres should be declared here as none will
585      be declared when the prelude is compiled.
586
587 ToDo: Explicit cost centres in prelude for Input and Output costs.
588
589 \begin{code}
590 #if defined(PROFILING)
591
592 STGFUN(startCcRegisteringWorld)
593 {
594     FB_
595     /* 
596      * We used to push miniInterpretEnd on the register stack, but
597      * miniInterpretEnd must only be entered with the RESUME_ macro,
598      * whereas the other addresses on the register stack must only be
599      * entered with the JMP_ macro.  Now, we push NULL and test for 
600      * it explicitly at each pop.
601      */
602     PUSH_REGISTER_STACK(NULL);
603     JMP_(_regMain);
604     FE_
605 }
606
607 CC_DECLARE(CC_CAFs,  "CAFs_in_...",  "PRELUDE", "PRELUDE", CC_IS_CAF,/*not static*/);
608 CC_DECLARE(CC_DICTs, "DICTs_in_...", "PRELUDE", "PRELUDE", CC_IS_DICT,/*not static*/);
609
610 START_REGISTER_PRELUDE(_regPrel);
611 REGISTER_CC(CC_CAFs);
612 REGISTER_CC(CC_DICTs);
613 END_REGISTER_CCS()
614
615 \end{code}
616
617 We also need cost centre declarations and registering routines for other
618 built-in prelude-like modules.
619
620 ToDo: What built-in prelude-like modules exist ?
621
622 \begin{code}
623 START_REGISTER_PRELUDE(_regByteOps);    /* used in Glasgow tests only? */
624 END_REGISTER_CCS()
625
626 /* _regPrelude is above */
627
628 START_REGISTER_PRELUDE(_regGHCbase);
629 END_REGISTER_CCS()
630
631 /* OLD: START_REGISTER_PRELUDE(_regGHCerr); */
632 START_REGISTER_PRELUDE(_regGHC);
633 END_REGISTER_CCS()
634
635 START_REGISTER_PRELUDE(_regPreludeGlaST);
636 END_REGISTER_CCS()
637
638 #endif
639 \end{code}