StgStartup.lhc 17.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
%/****************************************************************
%*								*
%*   Basic Continuations required by the STG Machine runtime    *
%*								*
%****************************************************************/


First continuation called by the mini-interpreter is
evaluateTopClosure.  It has to set up return and jump to the user's
@main@ closure.  If @errorIO@ is called, we will be back here, doing
the same thing for the specified continuation.

\begin{code}
#define MAIN_REG_MAP	    /* STG world */
#include "rtsdefs.h"

#if 0
#ifdef PAR
#include "Statistics.h"
#endif
#endif

/* ptr to the user's "main" closure (or "errorIO" arg closure),
   to which we hope to be linked
*/
extern P_ TopClosure;

EXTFUN(stopThreadDirectReturn);
UNVECTBL(,vtbl_stopStgWorld,stopThreadDirectReturn)

/* Well, we have to put the ArrayOfData and ArrayOfPtrs info tables
   somewhere...
*/

/* Array of data -- mutable */
STATICFUN(ArrayOfData_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered a primitive array (of data)---this shouldn't happen!\n");
    abort();
    FE_
}

DATA_ITBL(ArrayOfData_info,ArrayOfData_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"DATA-ARRAY","ARRAY");
/* ToDo: could put a useful tag in there!!! */

/* Array of pointers -- mutable */
STATICFUN(ArrayOfPtrs_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered a primitive array (of pointers)---this shouldn't happen!\n");
    abort();
    FE_
}

MUTUPLE_ITBL(ArrayOfPtrs_info,ArrayOfPtrs_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"PTR-ARRAY(mut)","ARRAY");
/* ToDo: could put a useful tag in there!!! */

STATICFUN(FullSVar_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered a full SVar---this shouldn't happen!\n");
    abort();
    FE_
}

MUTUPLE_ITBL(FullSVar_info,FullSVar_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"FullSVar","ARRAY");
/* ToDo: could put a useful tag in there!!! */

STATICFUN(EmptySVar_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered an empty SVar---this shouldn't happen!\n");
    abort();
    FE_
}

MUTUPLE_ITBL(EmptySVar_info,EmptySVar_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"EmptySVar","ARRAY");
/* ToDo: could put a useful tag in there!!! */

/* Array of pointers -- immutable */
STATICFUN(ImMutArrayOfPtrs_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered a primitive array (immutable, pointers)---this shouldn't happen!\n");
    abort();
    FE_
}

IMMUTUPLE_ITBL(ImMutArrayOfPtrs_info,ImMutArrayOfPtrs_entry,UpdErr,0,INFO_OTHER_TAG,,,const,IF_,ARR_K,"PTR-ARRAY(immut)","ARRAY");
/* ToDo: could put a useful tag in there!!! */

/* (end of Array whatnot) */

/* Question for Will: There seem to be a lot of these static things
now - worth putting them in a file by themselves?? [ADR] */


109
#if !defined(PAR) /* && !defined(GRAN) */
110

111
/* Ditto for Foreign Objectr entry point and info tables. [ADR]
112 113 114 115 116

   BTW Will, I copied most of this blindly from above - what's with
   this TAG stuff? And what kind of description/ type is wanted here?
*/

117
STATICFUN(ForeignObj_entry)
118 119 120 121
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
122
    fprintf(stderr, "Compiler bug: Entered a ForeignObj---this shouldn't happen!\n");
123 124 125 126
    abort();
    FE_
}

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 132 133

/* Ditto for the unused Stable Pointer info table. [ADR]
*/

134 135
void raiseError PROTO((StgStablePtr));
extern StgStablePtr errorHandler; /* NB: prone to magic-value-ery (WDP 95/12) */
136 137 138 139 140 141 142 143 144 145 146 147

/* Unused Stable Pointer (ie unused slot in a stable pointer table) */
STATICFUN(UnusedSP_entry)
{
    FB_
    (void) SAFESTGCALL1(I_,(void *, FILE *),fflush,stdout);
    (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");

    (void) STGCALL1(void,(void *, StgStablePtr), raiseError, errorHandler);
    FE_
}

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 154
};

/* Entry point and Info table for Stable Pointer Table. */

155 156 157 158 159 160 161 162 163 164
STATICFUN(EmptyStablePointerTable_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered *empty* stable pointer table---this shouldn't happen!\n");
    abort();
    FE_
}

165 166 167 168 169 170 171 172 173 174
STATICFUN(StablePointerTable_entry)
{
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered the stable pointer table---this shouldn't happen!\n");
    abort();
    FE_
}

175
STATIC_ITBL(EmptyStablePointerTable_info,EmptyStablePointerTable_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,SPT_K,"SP_TABLE","SP_TABLE");
176 177 178 179 180 181 182 183 184 185 186
/* ToDo: could put a useful tag in there!!! */

DYN_ITBL(StablePointerTable_info,StablePointerTable_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,IF_,SPT_K,"SP_TABLE","SP_TABLE");
/* ToDo: could put a useful tag in there!!! */


/* To ease initialisation of the heap, we start with an empty stable
   pointer table.  When we try to create the first stable pointer, the
   overflow will trigger creation of a table of useful size.
*/

187
SET_STATIC_HDR(EmptySPTable_closure,EmptyStablePointerTable_info,CC_SUBSUMED,,ED_RO_)
188 189 190 191 192 193 194 195 196 197 198 199 200
, (W_) DYN_VHS + 0 + 1 + 0  /* size = DYN_VHS + n + 1 + n with n = 0 */
, (W_) 0   /* number of ptrs */
, (W_) 0   /* top of stack */
};

/* End of SP stuff */
#endif /* !PAR */


/* the IoWorld token to start the whole thing off */
/* Question: this is just an amusing hex code isn't it
   -- or does it mean something? ADR */
P_ realWorldZh_closure = (P_) 0xbadbadbaL;
201
P_ GHC_void_closure = (P_) 0xbadbadbaL;
202

203
SET_STATIC_HDR(WorldStateToken_closure,STBase_SZh_static_info,CC_SUBSUMED/*harmless*/,,ED_RO_)
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
, (W_) 0xbadbadbaL
};

#ifndef CONCURRENT

STGFUN(startStgWorld)
{
    FB_
    /* At this point we are in the threaded-code world.

       TopClosure points to a closure of type PrimIO (), which should be
       performed (by applying it to the state of the world).

       The smInfo storage-management info block is assumed to be
       up to date, and is used to load the STG registers.
    */

    RestoreAllStgRegs();    /* inline! */

    /* ------- STG registers are now valid! -------------------------*/

    /* Put a suitable return address on the B stack */
    RetReg = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld); 

    /* Put an IoWorld token on the A stack */
    SpA -= AREL(1);
    *SpA = (P_) WorldStateToken_closure;

    Node = (P_) TopClosure; /* Point to the closure for main/errorIO-arg */
    ENT_VIA_NODE();
    InfoPtr=(D_)(INFO_PTR(Node));
    JMP_(ENTRY_CODE(InfoPtr));
    FE_
}
#endif	/* ! CONCURRENT */

\end{code}

%************************************************************************
%*                                                                      *
\subsection[thread-return]{Polymorphic end-of-thread code}
%*									*
%************************************************************************

\begin{code}

/* 
   Here's the polymorphic return for the end of a thread.

   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_stopThread[] = {
  /* at least "MAX_VECTORED_RTN" elements (see GhcConstants.lh) */
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn,
  (W_) stopThreadDirectReturn
};

STGFUN(stopThreadDirectReturn)
{
    FB_
    /* The final exit.

       The top-top-level closures (e.g., "main") are of type "IO ()".
       When entered, they perform an IO action and return a () --
       essentially, TagReg is set to 1.  Here, we don't need to do
       anything with that.

       We just tidy up the register stuff (real regs in *_SAVE, then 
       *_SAVE -> smInfo locs).
    */

#ifdef CONCURRENT
    SET_TASK_ACTIVITY(ST_OVERHEAD);
#endif

    SaveAllStgRegs();	/* inline! */

#ifdef CONCURRENT
    EndThread();
#else
    RESUME_(miniInterpretEnd);
#endif
    FE_
}

\end{code}  

\begin{code}
I_ ErrorIO_call_count = 0;

#ifdef CONCURRENT
EXTFUN(EnterNodeCode);

STGFUN(ErrorIO_innards)
    /* Assumes that "TopClosure" has been set already */
{
    FB_
    if (ErrorIO_call_count >= 16 /* MAGIC CONSTANT */ ) {
        /* Don't wrap the calls; we're done with STG land */
        fflush(stdout);
	fprintf(stderr, "too many nested calls to `error'\n");
	EXIT(EXIT_FAILURE);
    }
    ErrorIO_call_count++; /* NB: undo later if decide to let someone else handle it */

    /* Unlock all global closures held by this thread! (ToDo) --JSM */

    switch(TSO_TYPE(CurrentTSO)) {
    case T_MAIN:
    	/* Re-initialize stack pointers (cf. NewThread) */
#ifdef PAR
        SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
        SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
#else
    	SuA = stackInfo.botA + AREL(1);
    	SuB = stackInfo.botB + BREL(1);
330 331 332 333 334 335
        /* HWL */
        /* 
        SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
        SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
	*/
   
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
#endif
    	break;

    case T_REQUIRED:
    	/* Re-initialize stack pointers (cf. NewThread) */
        SpB = SuB = STKO_BSTK_BOT(StkOReg) + BREL(1);
        SuA = STKO_ASTK_BOT(StkOReg) + AREL(1);
    	break;

    case T_ADVISORY:
	ErrorIO_call_count--; /* undo the damage, as someone else will deal with it */
    	/* Let the main thread eventually handle it */
    	JMP_(stopThreadDirectReturn);

    case T_FAIL:
    	EXIT(EXIT_FAILURE);

    default:
        /* Don't wrap the calls; we're done with STG land */
        fflush(stdout);
356
	fprintf(stderr,"ErrorIO: %lx unknown\n", TSO_TYPE(CurrentTSO));
357 358 359 360 361 362 363 364 365
    	EXIT(EXIT_FAILURE);
    }

    /* Finish stack setup as if for a top-level task and enter the error node */

    SpA = SuA - AREL(1);

    *SpA = (P_) WorldStateToken_closure;

sof's avatar
sof committed
366
    STKO_LINK(StkOReg) = PrelBase_Z91Z93_closure;
367 368
    STKO_RETURN(StkOReg) = NULL;

369
#ifdef TICKY_TICKY
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
    STKO_ADEP(StkOReg) = STKO_BDEP(StkOReg) = 0;
#endif

    /* Go! */
    Node = (P_) TopClosure;
    RetReg = (StgRetAddr) UNVEC(stopThreadDirectReturn,vtbl_stopStgWorld);
    JMP_(EnterNodeCode);

    FE_
}
\end{code}

We cannot afford to call @error@ too many times
(e.g., \tr{error x where x = error x}), so we keep count.

\begin{code}
#else	/* !CONCURRENT */

StgFunPtr
ErrorIO_innards(STG_NO_ARGS)
    /* Assumes that "TopClosure" has been set already */
{
    FB_
    if (ErrorIO_call_count >= 16 /* MAGIC CONSTANT */ ) {
        /* Don't wrap the calls; we're done with STG land */
        fflush(stdout);
	fprintf(stderr, "too many nested calls to `error'\n");
	EXIT(EXIT_FAILURE);
    }
    ErrorIO_call_count++;

    /* Copy the heap-related registers into smInfo.  (Other registers get
       saved in this process, but we aren't interested in them.)

       Get a new stack (which re-initialises the smInfo stack stuff),
       and start the world again.
    */
    /* ToDo: chk this has been handled in parallel world */

    SaveAllStgRegs();	/* inline! */

411
    if (! initStacks( &StorageMgrInfo )) {
412 413 414 415 416 417 418 419 420 421 422 423 424 425
        /* Don't wrap the calls; we're done with STG land */
        fflush(stdout);
	fprintf(stderr, "initStacks failed!\n");
	EXIT(EXIT_FAILURE);
    }

    JMP_( startStgWorld );
    FE_
}

#endif	/* !CONCURRENT */
\end{code}  

\begin{code}
426
#if defined(PAR) || defined(GRAN) 
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455

STATICFUN(RBH_Save_0_entry)
{
  FB_
  fprintf(stderr,"Oops, entered an RBH save\n");
  EXIT(EXIT_FAILURE);
  FE_
}

STATICFUN(RBH_Save_1_entry)
{
  FB_
  fprintf(stderr,"Oops, entered an RBH save\n");
  EXIT(EXIT_FAILURE);
  FE_
}

STATICFUN(RBH_Save_2_entry)
{
  FB_
  fprintf(stderr,"Oops, entered an RBH save\n");
  EXIT(EXIT_FAILURE);
  FE_
}

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");
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");
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");

456
#endif /* PAR || GRAN */
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
\end{code}


%/****************************************************************
%*								*
%*		Other Bits and Pieces                           *
%*								*
%****************************************************************/

\begin{code}
/* If we don't need the slow entry code for a closure, we put in a
   pointer to this in the closure's slow entry code pointer instead.
 */

STGFUN(__std_entry_error__) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Called non-existent slow-entry code!!!\n");
    abort();
    JMP_(0);
    FE_
}

/* entry code */
STGFUN(STK_STUB_entry) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr, "Entered from a stubbed stack slot!\n");
    abort();
    JMP_(0);
    FE_
}

/* info table */
493
STATIC_ITBL(STK_STUB_info,STK_STUB_entry,UpdErr,0,INFO_OTHER_TAG,0,0,const,EF_,INTERNAL_KIND,"STK_STUB","STK_STUB");
494 495

/* closure */
496
SET_STATIC_HDR(STK_STUB_closure,STK_STUB_info,CC_SUBSUMED,,EXTDATA_RO)
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
  , (W_)0, (W_)0
};
\end{code}

%/****************************************************************
%*								*
%*		Some GC info tables                           *
%*								*
%****************************************************************/

These have to be in a .lhc file, so they will be reversed correctly.

\begin{code}
#include "../storage/SMinternal.h"

#if defined(_INFO_COPYING)

STGFUN(Caf_Evac_Upd_entry) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr,"Entered Caf_Evac_Upd %lx: Should never occur!\n", (W_) Node);
    abort();
    FE_
}

CAF_EVAC_UPD_ITBL(Caf_Evac_Upd_info,Caf_Evac_Upd_entry,const/*not static*/);

#if defined(GCgn)

STGFUN(Forward_Ref_New_entry) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr,"Entered Forward_Ref_New %lx: Should never occur!\n", (W_) Node);
532
    EXIT(EXIT_FAILURE); /* abort(); */
533 534 535 536 537 538 539 540 541
    FE_
}
FORWARDREF_ITBL(Forward_Ref_New_info,Forward_Ref_New_entry,const/*not static*/,_Evacuate_Old_Forward_Ref);

STGFUN(Forward_Ref_Old_entry) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr,"Entered Forward_Ref_Old %lx: Should never occur!\n", (W_) Node);
542
    EXIT(EXIT_FAILURE); /*    abort(); */
543 544 545 546 547 548 549 550 551
    FE_
}
FORWARDREF_ITBL(Forward_Ref_Old_info,Forward_Ref_Old_entry,const/*not static*/,_Evacuate_New_Forward_Ref);

STGFUN(OldRoot_Forward_Ref_entry) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr,"Entered OldRoot_Forward_Ref %lx: Should never occur!\n", (W_) Node);
552
    EXIT(EXIT_FAILURE); /*    abort(); */
553 554 555 556 557 558 559 560 561 562
    FE_
}
FORWARDREF_ITBL(OldRoot_Forward_Ref_info,OldRoot_Forward_Ref_entry,const/*not static*/,_Evacuate_OldRoot_Forward);
#else /* ! GCgn */

STGFUN(Forward_Ref_entry) {
    FB_
    /* Don't wrap the calls; we're done with STG land */
    fflush(stdout);
    fprintf(stderr,"Entered Forward_Ref %lx: Should never occur!\n", (W_) Node);
563
    EXIT(EXIT_FAILURE); /*    abort(); */
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
    FE_
}
FORWARDREF_ITBL(Forward_Ref_info,Forward_Ref_entry,const/*not static*/,_Evacuate_Forward_Ref);
#endif /* ! GCgn */

#endif /* _INFO_COPYING */

#if defined(GCgn)
OLDROOT_ITBL(OldRoot_info,Ind_Entry,const,EF_);
#endif /* GCgn */
\end{code}


%/***************************************************************
%*								*
%*		Cost Centre stuff ...                           *
%*								*
%****************************************************************/

For cost centres we need prelude cost centres and register routine.

N.B. ALL prelude cost centres should be declared here as none will
     be declared when the prelude is compiled.

ToDo: Explicit cost centres in prelude for Input and Output costs.

\begin{code}
591
#if defined(PROFILING)
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606

STGFUN(startCcRegisteringWorld)
{
    FB_
    /* 
     * We used to push miniInterpretEnd on the register stack, but
     * miniInterpretEnd must only be entered with the RESUME_ macro,
     * whereas the other addresses on the register stack must only be
     * entered with the JMP_ macro.  Now, we push NULL and test for 
     * it explicitly at each pop.
     */
    PUSH_REGISTER_STACK(NULL);
    JMP_(_regMain);
    FE_
}
sof's avatar
sof committed
607 608 609
/* SOF: Prelude supplies these for you
CC_DECLARE(CC_CAFs,  "CAFs_in_...",  "PRELUDE", "PRELUDE", CC_IS_CAF,*not static*);
CC_DECLARE(CC_DICTs, "DICTs_in_...", "PRELUDE", "PRELUDE", CC_IS_DICT,*not static*);
610 611 612 613 614

START_REGISTER_PRELUDE(_regPrelude);
REGISTER_CC(CC_CAFs);
REGISTER_CC(CC_DICTs);
END_REGISTER_CCS()
sof's avatar
sof committed
615
*/
616 617 618 619 620 621 622 623 624 625 626 627 628
\end{code}

We also need cost centre declarations and registering routines for other
built-in prelude-like modules.

ToDo: What built-in prelude-like modules exist ?

\begin{code}
START_REGISTER_PRELUDE(_regByteOps);    /* used in Glasgow tests only? */
END_REGISTER_CCS()

/* _regPrelude is above */

629
START_REGISTER_PRELUDE(_regGHCbase);
630 631
END_REGISTER_CCS()

sof's avatar
sof committed
632 633
/* OLD: START_REGISTER_PRELUDE(_regGHCerr); */
START_REGISTER_PRELUDE(_regGHC);
634 635 636 637 638 639 640
END_REGISTER_CCS()

START_REGISTER_PRELUDE(_regPreludeGlaST);
END_REGISTER_CCS()

#endif
\end{code}