2 /* -----------------------------------------------------------------------------
5 * Copyright (c) 1994-1998.
7 * $RCSfile: Evaluator.c,v $
9 * $Date: 1999/11/08 15:30:33 $
10 * ---------------------------------------------------------------------------*/
20 #include "SchedAPI.h" /* for createGenThread */
21 #include "Schedule.h" /* for context_switch */
22 #include "Bytecodes.h"
23 #include "Assembler.h" /* for CFun stuff */
24 #include "ForeignCall.h"
25 #include "PrimOps.h" /* for __{encode,decode}{Float,Double} */
26 #include "Evaluator.h"
30 #include "Disassembler.h"
35 #include <math.h> /* These are for primops */
36 #include <limits.h> /* These are for primops */
37 #include <float.h> /* These are for primops */
39 #include <ieee754.h> /* These are for primops */
42 #ifdef STANDALONE_INTEGER
43 #include "sainteger.h"
45 #error Non-standalone integer not yet supported
48 /* An incredibly useful abbreviation.
49 * Interestingly, there are some uses of END_TSO_QUEUE_closure that
50 * can't use it because they use the closure at type StgClosure* or
51 * even StgPtr*. I suspect they should be changed. -- ADR
53 #define EndTSOQueue stgCast(StgTSO*,(void*)&END_TSO_QUEUE_closure)
55 /* These macros are rather delicate - read a good ANSI C book carefully
59 #define mycat(x,y) x##y
60 #define mycat2(x,y) mycat(x,y)
61 #define mycat3(x,y,z) mycat2(x,mycat2(y,z))
63 #if defined(__GNUC__) && !defined(DEBUG)
64 #define USE_GCC_LABELS 1
66 #define USE_GCC_LABELS 0
69 /* Make it possible for the evaluator to get hold of bytecode
70 for a given function by name. Useful but a hack. Sigh.
72 extern void* getHugs_AsmObject_for ( char* s );
75 /* --------------------------------------------------------------------------
76 * Crude profiling stuff (mainly to assess effect of optimiser)
77 * ------------------------------------------------------------------------*/
79 #ifdef CRUDE_PROFILING
88 struct { int /*StgVar*/ who;
96 CPRecord cpTab[M_CPTAB];
103 for (i = 0; i < M_CPTAB; i++)
104 cpTab[i].who = CP_NIL;
108 void cp_enter ( StgBCO* b )
112 int /*StgVar*/ v = b->stgexpr;
113 if ((void*)v == NULL) return;
122 h = (-v) % M_CPTAB; else
125 assert (h >= 0 && h < M_CPTAB);
126 while (cpTab[h].who != v && cpTab[h].who != CP_NIL) {
127 h++; if (h == M_CPTAB) h = 0;
130 if (cpTab[cpCurr].who == CP_NIL) {
131 cpTab[cpCurr].who = v;
132 if (!is_ret_cont) cpTab[cpCurr].enters = 1;
133 cpTab[cpCurr].bytes = cpTab[cpCurr].insns = 0;
135 if (cpInUse * 2 > M_CPTAB) {
136 fprintf(stderr, "\nCRUDE_PROFILING hash table is too full\n" );
140 if (!is_ret_cont) cpTab[cpCurr].enters++;
146 void cp_bill_words ( int nw )
148 if (cpCurr == CP_NIL) return;
149 cpTab[cpCurr].bytes += sizeof(StgWord)*nw;
153 void cp_bill_insns ( int ni )
155 if (cpCurr == CP_NIL) return;
156 cpTab[cpCurr].insns += ni;
160 static double percent ( double a, double b )
162 return (100.0 * a) / b;
166 void cp_show ( void )
168 int i, j, max, maxN, totE, totB, totI, cumE, cumB, cumI;
171 if (cpInUse == -1) return;
173 fflush(stdout);fflush(stderr);
176 totE = totB = totI = 0;
177 for (i = 0; i < M_CPTAB; i++) {
178 cpTab[i].twho = cpTab[i].who;
179 if (cpTab[i].who != CP_NIL) {
180 totE += cpTab[i].enters;
181 totB += cpTab[i].bytes;
182 totI += cpTab[i].insns;
187 "%6d (%7.3f M) enters, "
188 "%6d (%7.3f M) insns, "
189 "%6d (%7.3f M) bytes\n\n",
190 totE, totE/1000000.0, totI, totI/1000000.0, totB, totB/1000000.0 );
192 cumE = cumB = cumI = 0;
193 for (j = 0; j < 32; j++) {
196 for (i = 0; i < M_CPTAB; i++)
197 if (cpTab[i].who != CP_NIL &&
198 cpTab[i].enters > maxN) {
199 maxN = cpTab[i].enters;
202 if (max == -1) break;
204 cumE += cpTab[max].enters;
205 cumB += cpTab[max].bytes;
206 cumI += cpTab[max].insns;
208 strcpy(nm, maybeName(cpTab[max].who));
209 if (strcmp(nm, "(unknown)")==0)
210 sprintf ( nm, "id%d", -cpTab[max].who);
212 printf ( "%20s %7d es (%4.1f%%, %4.1f%% c) "
213 "%7d bs (%4.1f%%, %4.1f%% c) "
214 "%7d is (%4.1f%%, %4.1f%% c)\n",
216 cpTab[max].enters, percent(cpTab[max].enters,totE), percent(cumE,totE),
217 cpTab[max].bytes, percent(cpTab[max].bytes,totB), percent(cumB,totB),
218 cpTab[max].insns, percent(cpTab[max].insns,totI), percent(cumI,totI)
221 cpTab[max].twho = cpTab[max].who;
222 cpTab[max].who = CP_NIL;
225 for (i = 0; i < M_CPTAB; i++)
226 cpTab[i].who = cpTab[i].twho;
234 /* --------------------------------------------------------------------------
235 * Hugs Hooks - a bit of a hack
236 * ------------------------------------------------------------------------*/
238 void setRtsFlags( int x );
239 void setRtsFlags( int x )
241 unsigned int w = 0x12345678;
242 unsigned char* pw = (unsigned char *)&w;
245 *(int*)(&(RtsFlags.DebugFlags)) = x;
250 w2 |= (w1 && 0xFF); w2 <<= 8; w1 >>= 8;
251 w2 |= (w1 && 0xFF); w2 <<= 8; w1 >>= 8;
252 w2 |= (w1 && 0xFF); w2 <<= 8; w1 >>= 8;
253 w2 |= (w1 && 0xFF); w2 <<= 8; w1 >>= 8;
254 *(int*)(&(RtsFlags.DebugFlags)) = (int)w2;
259 /* --------------------------------------------------------------------------
260 * Entering-objects and bytecode interpreter part of evaluator
261 * ------------------------------------------------------------------------*/
263 /* The primop (and all other) parts of this evaluator operate upon the
264 machine state which lives in MainRegTable. enter is different:
265 to make its closure- and bytecode-interpreting loops go fast, some of that
266 state is pulled out into local vars (viz, registers, if we are lucky).
267 That means that we need to save(load) the local state at every exit(reentry)
268 into enter. That is, around every procedure call it makes. Blargh!
269 If you modify this code, __be warned__ it will fail in mysterious ways if
270 you fail to preserve this property.
272 Currently the pulled-out state is Sp in xSp, Su in xSu and SpLim in xSpLim.
273 The SSS macros saves the state back in MainRegTable, and LLL loads it from
274 MainRegTable. RETURN(v) does SSS and then returns v; all exits should
275 be via RETURN and not plain return.
277 Since xSp, xSu and xSpLim are local vars in enter, they are not visible
278 in procedures called from enter. To fix this, either (1) turn the
279 procedures into macros, so they get copied inline, or (2) bracket
280 the procedure call with SSS and LLL so that the local and global
281 machine states are synchronised for the duration of the call.
285 /* Forward decls ... */
286 static void* enterBCO_primop1 ( int );
287 static void* enterBCO_primop2 ( int , int* /*StgThreadReturnCode* */,
288 StgBCO**, Capability* );
289 static inline void PopUpdateFrame ( StgClosure* obj );
290 static inline void PopCatchFrame ( void );
291 static inline void PopSeqFrame ( void );
292 static inline void PopStopFrame( StgClosure* obj );
293 static inline void PushTaggedRealWorld( void );
294 /* static inline void PushTaggedInteger ( mpz_ptr ); */
295 static inline StgPtr grabHpUpd( nat size );
296 static inline StgPtr grabHpNonUpd( nat size );
297 static StgClosure* raiseAnError ( StgClosure* errObj );
299 static int enterCountI = 0;
301 #ifdef STANDALONE_INTEGER
302 StgDouble B__encodeDouble (B* s, I_ e);
303 void B__decodeDouble (B* man, I_* exp, StgDouble dbl);
304 #if ! FLOATS_AS_DOUBLES
305 StgFloat B__encodeFloat (B* s, I_ e);
306 void B__decodeFloat (B* man, I_* exp, StgFloat flt);
307 StgPtr CreateByteArrayToHoldInteger ( int );
308 B* IntegerInsideByteArray ( StgPtr );
309 void SloppifyIntegerEnd ( StgPtr );
316 #define gSp MainRegTable.rSp
317 #define gSu MainRegTable.rSu
318 #define gSpLim MainRegTable.rSpLim
321 /* Macros to save/load local state. */
323 #define SSS { tSp=gSp = xSp; tSu=gSu = xSu; tSpLim=gSpLim = xSpLim; }
324 #define LLL { tSp=xSp = gSp; tSu=xSu = gSu; tSpLim=xSpLim = gSpLim; }
326 #define SSS { gSp = xSp; gSu = xSu; gSpLim = xSpLim; }
327 #define LLL { xSp = gSp; xSu = gSu; xSpLim = gSpLim; }
330 #define RETURN(vvv) { \
331 StgThreadReturnCode retVal=(vvv); \
333 cap->rCurrentTSO->sp = gSp; \
334 cap->rCurrentTSO->su = gSu; \
335 cap->rCurrentTSO->splim = gSpLim; \
340 /* Macros to operate directly on the pulled-out machine state.
341 These mirror some of the small procedures used in the primop code
342 below, except you have to be careful about side effects,
343 ie xPushPtr(xStackPtr(n)) won't work! It certainly isn't the
344 same as PushPtr(StackPtr(n)). Also note that (1) some of
345 the macros, in particular xPopTagged*, do not make the tag
346 sanity checks that their non-x cousins do, and (2) some of
347 the macros depend critically on the semantics of C comma
348 expressions to work properly.
350 #define xPushPtr(ppp) { xSp--; *xSp=(StgWord)(ppp); }
351 #define xPopPtr() ((StgPtr)(*xSp++))
353 #define xPushCPtr(ppp) { xSp--; *xSp=(StgWord)(ppp); }
354 #define xPopCPtr() ((StgClosure*)(*xSp++))
356 #define xPushWord(ppp) { xSp--; *xSp=(StgWord)(ppp); }
357 #define xPopWord() ((StgWord)(*xSp++))
359 #define xStackPtr(nnn) ((StgPtr)(*(xSp+(nnn))))
360 #define xStackWord(nnn) ((StgWord)(*(xSp+(nnn))))
361 #define xSetStackWord(iii,www) xSp[iii]=(StgWord)(www)
363 #define xPushTag(ttt) { xSp--; *xSp=(StgWord)(ttt); }
364 #define xPopTag(ttt) { StackTag t = (StackTag)(*xSp++); \
367 #define xPushTaggedInt(xxx) { xSp -= sizeofW(StgInt); \
368 *xSp = (xxx); xPushTag(INT_TAG); }
369 #define xTaggedStackInt(iii) ((StgInt)(*(xSp+1+(iii))))
370 #define xPopTaggedInt() ((xSp++,xSp+=sizeofW(StgInt), \
371 (StgInt)(*(xSp-sizeofW(StgInt)))))
373 #define xPushTaggedWord(xxx) { xSp -= sizeofW(StgWord); \
374 *xSp = (xxx); xPushTag(WORD_TAG); }
375 #define xTaggedStackWord(iii) ((StgWord)(*(xSp+1+(iii))))
376 #define xPopTaggedWord() ((xSp++,xSp+=sizeofW(StgWord), \
377 (StgWord)(*(xSp-sizeofW(StgWord)))))
379 #define xPushTaggedAddr(xxx) { xSp -= sizeofW(StgAddr); \
380 *xSp = (StgWord)(xxx); xPushTag(ADDR_TAG); }
381 #define xTaggedStackAddr(iii) ((StgAddr)(*(xSp+1+(iii))))
382 #define xPopTaggedAddr() ((xSp++,xSp+=sizeofW(StgAddr), \
383 (StgAddr)(*(xSp-sizeofW(StgAddr)))))
385 #define xPushTaggedStable(xxx) { xSp -= sizeofW(StgStablePtr); \
386 *xSp = (StgWord)(xxx); xPushTag(STABLE_TAG); }
387 #define xTaggedStackStable(iii) ((StgStablePtr)(*(xSp+1+(iii))))
388 #define xPopTaggedStable() ((xSp++,xSp+=sizeofW(StgStablePtr), \
389 (StgStablePtr)(*(xSp-sizeofW(StgStablePtr)))))
391 #define xPushTaggedChar(xxx) { xSp -= sizeofW(StgChar); \
392 *xSp = (StgWord)(xxx); xPushTag(CHAR_TAG); }
393 #define xTaggedStackChar(iii) ((StgChar)(*(xSp+1+(iii))))
394 #define xPopTaggedChar() ((xSp++,xSp+=sizeofW(StgChar), \
395 (StgChar)(*(xSp-sizeofW(StgChar)))))
397 #define xPushTaggedFloat(xxx) { xSp -= sizeofW(StgFloat); \
398 ASSIGN_FLT(xSp,xxx); xPushTag(FLOAT_TAG); }
399 #define xTaggedStackFloat(iii) PK_FLT(xSp+1+(iii))
400 #define xPopTaggedFloat() ((xSp++,xSp+=sizeofW(StgFloat), \
401 PK_FLT(xSp-sizeofW(StgFloat))))
403 #define xPushTaggedDouble(xxx) { xSp -= sizeofW(StgDouble); \
404 ASSIGN_DBL(xSp,xxx); xPushTag(DOUBLE_TAG); }
405 #define xTaggedStackDouble(iii) PK_DBL(xSp+1+(iii))
406 #define xPopTaggedDouble() ((xSp++,xSp+=sizeofW(StgDouble), \
407 PK_DBL(xSp-sizeofW(StgDouble))))
410 #define xPushUpdateFrame(target, xSp_offset) \
412 StgUpdateFrame *__frame; \
413 __frame = (StgUpdateFrame *)(xSp + (xSp_offset)) - 1; \
414 SET_INFO(__frame, (StgInfoTable *)&Upd_frame_info); \
415 __frame->link = xSu; \
416 __frame->updatee = (StgClosure *)(target); \
420 #define xPopUpdateFrame(ooo) \
422 /* NB: doesn't assume that Sp == Su */ \
423 IF_DEBUG(evaluator, \
424 fprintf(stderr, "Updating "); \
425 printPtr(stgCast(StgPtr,xSu->updatee)); \
426 fprintf(stderr, " with "); \
428 fprintf(stderr,"xSp = %p\txSu = %p\n\n", xSp, xSu); \
430 UPD_IND(xSu->updatee,ooo); \
431 xSp = stgCast(StgStackPtr,xSu) + sizeofW(StgUpdateFrame); \
437 /* Instruction stream macros */
438 #define BCO_INSTR_8 *bciPtr++
439 #define BCO_INSTR_16 ((bciPtr += 2, (*(bciPtr-2) << 8) + *(bciPtr-1)))
440 #define PC (bciPtr - &(bcoInstr(bco,0)))
443 /* State on entry to enter():
444 * - current thread is in cap->rCurrentTSO;
445 * - allocation area is in cap->rCurrentNursery & cap->rNursery
448 StgThreadReturnCode enter( Capability* cap, StgClosure* obj0 )
450 /* use of register here is primarily to make it clear to compilers
451 that these entities are non-aliasable.
453 register StgPtr xSp; /* local state -- stack pointer */
454 register StgUpdateFrame* xSu; /* local state -- frame pointer */
455 register StgPtr xSpLim; /* local state -- stack lim pointer */
456 register StgClosure* obj; /* object currently under evaluation */
457 char eCount; /* enter counter, for context switching */
460 StgPtr tSp; StgUpdateFrame* tSu; StgPtr tSpLim;
463 gSp = cap->rCurrentTSO->sp;
464 gSu = cap->rCurrentTSO->su;
465 gSpLim = cap->rCurrentTSO->splim;
468 /* use the t values to check that Su/Sp/SpLim do not change unexpectedly */
469 tSp = gSp; tSu = gSu; tSpLim = gSpLim;
475 /* Load the local state from global state, and Party On, Dudes! */
476 /* From here onwards, we operate with the local state and
477 save/reload it as necessary.
486 assert(gSpLim == tSpLim);
490 ASSERT(xSpLim <= xSp && xSp <= stgCast(StgPtr,xSu));
492 "\n---------------------------------------------------------------\n");
493 fprintf(stderr,"(%d) Entering: ",enterCountI); printObj(obj);
494 fprintf(stderr,"xSp = %p\txSu = %p\n", xSp, xSu);
495 fprintf(stderr, "\n" );
496 printStack(xSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,xSu);
497 fprintf(stderr, "\n\n");
507 if (context_switch) {
508 xPushCPtr(obj); /* code to restart with */
509 RETURN(ThreadYielding);
513 switch ( get_itbl(obj)->type ) {
515 barf("Invalid object %p",obj);
519 /* ---------------------------------------------------- */
520 /* Start of the bytecode evaluator */
521 /* ---------------------------------------------------- */
524 # define Ins(x) &&l##x
525 static void *labs[] = { INSTRLIST };
527 # define LoopTopLabel
528 # define Case(x) l##x
529 # define Continue goto *labs[BCO_INSTR_8]
530 # define Dispatch Continue;
533 # define LoopTopLabel insnloop:
534 # define Case(x) case x
535 # define Continue goto insnloop
536 # define Dispatch switch (BCO_INSTR_8) {
537 # define EndDispatch }
540 register StgWord8* bciPtr; /* instruction pointer */
541 register StgBCO* bco = (StgBCO*)obj;
544 /* Don't need to SSS ... LLL around doYouWantToGC */
545 wantToGC = doYouWantToGC();
547 xPushCPtr((StgClosure*)bco); /* code to restart with */
548 RETURN(HeapOverflow);
556 bciPtr = &(bcoInstr(bco,0));
560 ASSERT((StgWord)(PC) < bco->n_instrs);
562 fprintf(stderr,"Sp = %p\tSu = %p\tpc = %d\t", xSp, xSu, PC);
566 fprintf(stderr,"\n");
567 for (i = 8; i >= 0; i--)
568 fprintf(stderr, "%d %p\n", i, (StgPtr)(*(gSp+i)));
570 fprintf(stderr,"\n");
575 SSS; cp_bill_insns(1); LLL;
580 Case(i_INTERNAL_ERROR):
581 barf("INTERNAL_ERROR at %p:%d",bco,PC-1);
583 barf("PANIC at %p:%d",bco,PC-1);
587 if (xSp - n < xSpLim) {
588 xPushCPtr((StgClosure*)bco); /* code to restart with */
589 RETURN(StackOverflow);
593 Case(i_STK_CHECK_big):
595 int n = BCO_INSTR_16;
596 if (xSp - n < xSpLim) {
597 xPushCPtr((StgClosure*)bco); /* code to restart with */
598 RETURN(StackOverflow);
605 if ((StgPtr*)(xSp + n) > (StgPtr*)xSu) {
606 StgWord words = (P_)xSu - xSp;
608 /* first build a PAP */
609 ASSERT((P_)xSu >= xSp); /* was (words >= 0) but that's always true */
610 if (words == 0) { /* optimisation */
611 /* Skip building the PAP and update with an indirection. */
614 /* In the evaluator, we avoid the need to do
615 * a heap check here by including the size of
616 * the PAP in the heap check we performed
617 * when we entered the BCO.
621 SSS; pap = (StgPAP*)grabHpNonUpd(PAP_sizeW(words)); LLL;
622 SET_HDR(pap,&PAP_info,CC_pap);
625 for (i = 0; i < (I_)words; ++i) {
626 payloadWord(pap,i) = xSp[i];
629 obj = stgCast(StgClosure*,pap);
632 /* now deal with "update frame" */
633 /* as an optimisation, we process all on top of stack */
634 /* instead of just the top one */
635 ASSERT(xSp==(P_)xSu);
637 switch (get_itbl(xSu)->type) {
639 /* Hit a catch frame during an arg satisfaction check,
640 * so the thing returning (1) has not thrown an
641 * exception, and (2) is of functional type. Just
642 * zap the catch frame and carry on down the stack
643 * (looking for more arguments, basically).
645 SSS; PopCatchFrame(); LLL;
648 xPopUpdateFrame(obj);
651 SSS; PopStopFrame(obj); LLL;
652 RETURN(ThreadFinished);
654 SSS; PopSeqFrame(); LLL;
655 ASSERT(xSp != (P_)xSu);
656 /* Hit a SEQ frame during an arg satisfaction check.
657 * So now return to bco_info which is under the
658 * SEQ frame. The following code is copied from a
659 * case RET_BCO further down. (The reason why we're
660 * here is that something of functional type has
661 * been seq-d on, and we're now returning to the
662 * algebraic-case-continuation which forced the
663 * evaluation in the first place.)
675 barf("Invalid update frame during argcheck");
677 } while (xSp==(P_)xSu);
685 int words = BCO_INSTR_8;
686 SSS; p = grabHpUpd(AP_sizeW(words)); LLL;
690 Case(i_ALLOC_CONSTR):
693 StgInfoTable* info = bcoConstAddr(bco,BCO_INSTR_8);
694 SSS; p = grabHpNonUpd(sizeW_fromITBL(info)); LLL;
695 SET_HDR((StgClosure*)p,info,??);
701 int x = BCO_INSTR_8; /* ToDo: Word not Int! */
703 StgAP_UPD* o = stgCast(StgAP_UPD*,xStackPtr(x));
704 SET_HDR(o,&AP_UPD_info,??);
706 o->fun = stgCast(StgClosure*,xPopPtr());
707 for(x=0; x < y; ++x) {
708 payloadWord(o,x) = xPopWord();
711 fprintf(stderr,"\tBuilt ");
713 printObj(stgCast(StgClosure*,o));
724 o = stgCast(StgAP_UPD*,xStackPtr(x));
725 SET_HDR(o,&AP_UPD_info,??);
727 o->fun = stgCast(StgClosure*,xPopPtr());
728 for(x=0; x < y; ++x) {
729 payloadWord(o,x) = xPopWord();
732 fprintf(stderr,"\tBuilt ");
734 printObj(stgCast(StgClosure*,o));
743 StgPAP* o = stgCast(StgPAP*,xStackPtr(x));
744 SET_HDR(o,&PAP_info,??);
746 o->fun = stgCast(StgClosure*,xPopPtr());
747 for(x=0; x < y; ++x) {
748 payloadWord(o,x) = xPopWord();
751 fprintf(stderr,"\tBuilt ");
753 printObj(stgCast(StgClosure*,o));
760 int offset = BCO_INSTR_8;
761 StgClosure* o = stgCast(StgClosure*,xStackPtr(offset));
762 const StgInfoTable* info = get_itbl(o);
763 nat p = info->layout.payload.ptrs;
764 nat np = info->layout.payload.nptrs;
766 for(i=0; i < p; ++i) {
767 payloadCPtr(o,i) = xPopCPtr();
769 for(i=0; i < np; ++i) {
770 payloadWord(o,p+i) = 0xdeadbeef;
773 fprintf(stderr,"\tBuilt ");
775 printObj(stgCast(StgClosure*,o));
782 int offset = BCO_INSTR_16;
783 StgClosure* o = stgCast(StgClosure*,xStackPtr(offset));
784 const StgInfoTable* info = get_itbl(o);
785 nat p = info->layout.payload.ptrs;
786 nat np = info->layout.payload.nptrs;
788 for(i=0; i < p; ++i) {
789 payloadCPtr(o,i) = xPopCPtr();
791 for(i=0; i < np; ++i) {
792 payloadWord(o,p+i) = 0xdeadbeef;
795 fprintf(stderr,"\tBuilt ");
797 printObj(stgCast(StgClosure*,o));
806 ASSERT(xSp+x+y <= stgCast(StgPtr,xSu));
807 /* a_1, .. a_x, b_1, .. b_y, s => a_1, .. a_x, s */
809 xSetStackWord(x+y,xStackWord(x));
819 ASSERT(xSp+x+y <= stgCast(StgPtr,xSu));
820 /* a_1, .. a_x, b_1, .. b_y, s => a_1, .. a_x, s */
822 xSetStackWord(x+y,xStackWord(x));
834 xPushPtr(bcoConstPtr(bco,BCO_INSTR_8));
835 xPushPtr(stgCast(StgPtr,&ret_bco_info));
840 int tag = BCO_INSTR_8;
841 StgWord offset = BCO_INSTR_16;
842 if (constrTag(stgCast(StgClosure*,xStackPtr(0))) != tag) {
849 StgClosure* o = stgCast(StgClosure*,xStackPtr(0));
850 const StgInfoTable* itbl = get_itbl(o);
851 int i = itbl->layout.payload.ptrs;
852 ASSERT( itbl->type == CONSTR
853 || itbl->type == CONSTR_STATIC
854 || itbl->type == CONSTR_NOCAF_STATIC
855 || itbl->type == CONSTR_1_0
856 || itbl->type == CONSTR_0_1
857 || itbl->type == CONSTR_2_0
858 || itbl->type == CONSTR_1_1
859 || itbl->type == CONSTR_0_2
862 xPushCPtr(payloadCPtr(o,i));
868 int n = BCO_INSTR_16;
869 StgPtr p = xStackPtr(n);
875 StgPtr p = xStackPtr(BCO_INSTR_8);
881 xPushPtr(stgCast(StgPtr,bcoConstPtr(bco,BCO_INSTR_8)));
886 int n = BCO_INSTR_16;
887 xPushPtr(stgCast(StgPtr,bcoConstPtr(bco,n)));
892 SSS; PushTaggedRealWorld(); LLL;
897 StgInt i = xTaggedStackInt(BCO_INSTR_8);
903 xPushTaggedInt(bcoConstInt(bco,BCO_INSTR_8));
909 SSS; o = (StgClosure*)grabHpNonUpd(Izh_sizeW); LLL;
910 SET_HDR(o,&Izh_con_info,??);
911 payloadWord(o,0) = xPopTaggedInt();
913 fprintf(stderr,"\tBuilt ");
915 printObj(stgCast(StgClosure*,o));
918 xPushPtr(stgCast(StgPtr,o));
923 StgClosure* con = stgCast(StgClosure*,xStackPtr(0));
924 /* ASSERT(isIntLike(con)); */
925 xPushTaggedInt(payloadWord(con,0));
930 StgWord offset = BCO_INSTR_16;
931 StgInt x = xPopTaggedInt();
932 StgInt y = xPopTaggedInt();
938 Case(i_CONST_INTEGER):
942 char* s = bcoConstAddr(bco,BCO_INSTR_8);
945 p = CreateByteArrayToHoldInteger(n);
946 do_fromStr ( s, n, IntegerInsideByteArray(p));
947 SloppifyIntegerEnd(p);
954 StgWord w = xTaggedStackWord(BCO_INSTR_8);
960 xPushTaggedWord(bcoConstWord(bco,BCO_INSTR_8));
966 SSS; o = (StgClosure*)grabHpNonUpd(Wzh_sizeW); LLL;
967 SET_HDR(o,&Wzh_con_info,??);
968 payloadWord(o,0) = xPopTaggedWord();
970 fprintf(stderr,"\tBuilt ");
972 printObj(stgCast(StgClosure*,o));
975 xPushPtr(stgCast(StgPtr,o));
980 StgClosure* con = stgCast(StgClosure*,xStackPtr(0));
981 /* ASSERT(isWordLike(con)); */
982 xPushTaggedWord(payloadWord(con,0));
987 StgAddr a = xTaggedStackAddr(BCO_INSTR_8);
993 xPushTaggedAddr(bcoConstAddr(bco,BCO_INSTR_8));
999 SSS; o = (StgClosure*)grabHpNonUpd(Azh_sizeW); LLL;
1000 SET_HDR(o,&Azh_con_info,??);
1001 payloadPtr(o,0) = xPopTaggedAddr();
1003 fprintf(stderr,"\tBuilt ");
1005 printObj(stgCast(StgClosure*,o));
1008 xPushPtr(stgCast(StgPtr,o));
1011 Case(i_UNPACK_ADDR):
1013 StgClosure* con = (StgClosure*)xStackPtr(0);
1014 /* ASSERT(isAddrLike(con)); */
1015 xPushTaggedAddr(payloadPtr(con,0));
1020 StgChar c = xTaggedStackChar(BCO_INSTR_8);
1026 xPushTaggedChar(bcoConstChar(bco,BCO_INSTR_8));
1032 SSS; o = (StgClosure*)grabHpNonUpd(Czh_sizeW); LLL;
1033 SET_HDR(o,&Czh_con_info,??);
1034 payloadWord(o,0) = xPopTaggedChar();
1035 xPushPtr(stgCast(StgPtr,o));
1037 fprintf(stderr,"\tBuilt ");
1039 printObj(stgCast(StgClosure*,o));
1044 Case(i_UNPACK_CHAR):
1046 StgClosure* con = stgCast(StgClosure*,xStackPtr(0));
1047 /* ASSERT(isCharLike(con)); */
1048 xPushTaggedChar(payloadWord(con,0));
1053 StgFloat f = xTaggedStackFloat(BCO_INSTR_8);
1054 xPushTaggedFloat(f);
1057 Case(i_CONST_FLOAT):
1059 xPushTaggedFloat(bcoConstFloat(bco,BCO_INSTR_8));
1065 SSS; o = (StgClosure*)grabHpNonUpd(Fzh_sizeW); LLL;
1066 SET_HDR(o,&Fzh_con_info,??);
1067 ASSIGN_FLT(&payloadWord(o,0),xPopTaggedFloat());
1069 fprintf(stderr,"\tBuilt ");
1071 printObj(stgCast(StgClosure*,o));
1074 xPushPtr(stgCast(StgPtr,o));
1077 Case(i_UNPACK_FLOAT):
1079 StgClosure* con = stgCast(StgClosure*,xStackPtr(0));
1080 /* ASSERT(isFloatLike(con)); */
1081 xPushTaggedFloat(PK_FLT(&payloadWord(con,0)));
1086 StgDouble d = xTaggedStackDouble(BCO_INSTR_8);
1087 xPushTaggedDouble(d);
1090 Case(i_CONST_DOUBLE):
1092 xPushTaggedDouble(bcoConstDouble(bco,BCO_INSTR_8));
1095 Case(i_CONST_DOUBLE_big):
1097 int n = BCO_INSTR_16;
1098 xPushTaggedDouble(bcoConstDouble(bco,n));
1101 Case(i_PACK_DOUBLE):
1104 SSS; o = (StgClosure*)grabHpNonUpd(Dzh_sizeW); LLL;
1105 SET_HDR(o,&Dzh_con_info,??);
1106 ASSIGN_DBL(&payloadWord(o,0),xPopTaggedDouble());
1108 fprintf(stderr,"\tBuilt ");
1109 printObj(stgCast(StgClosure*,o));
1111 xPushPtr(stgCast(StgPtr,o));
1114 Case(i_UNPACK_DOUBLE):
1116 StgClosure* con = stgCast(StgClosure*,xStackPtr(0));
1117 /* ASSERT(isDoubleLike(con)); */
1118 xPushTaggedDouble(PK_DBL(&payloadWord(con,0)));
1123 StgStablePtr s = xTaggedStackStable(BCO_INSTR_8);
1124 xPushTaggedStable(s);
1127 Case(i_PACK_STABLE):
1130 SSS; o = (StgClosure*)grabHpNonUpd(Stablezh_sizeW); LLL;
1131 SET_HDR(o,&StablePtr_con_info,??);
1132 payloadWord(o,0) = xPopTaggedStable();
1134 fprintf(stderr,"\tBuilt ");
1136 printObj(stgCast(StgClosure*,o));
1139 xPushPtr(stgCast(StgPtr,o));
1142 Case(i_UNPACK_STABLE):
1144 StgClosure* con = (StgClosure*)xStackPtr(0);
1145 /* ASSERT(isStableLike(con)); */
1146 xPushTaggedStable(payloadWord(con,0));
1154 SSS; p = enterBCO_primop1 ( i ); LLL;
1155 if (p) { obj = p; goto enterLoop; };
1160 /* Remember to save */
1161 int i, trc, pc_saved;
1164 trc = 12345678; /* Assume != any StgThreadReturnCode */
1169 p = enterBCO_primop2 ( i, &trc, &bco_tmp, cap );
1172 bciPtr = &(bcoInstr(bco,pc_saved));
1174 if (trc == 12345678) {
1175 /* we want to enter p */
1176 obj = p; goto enterLoop;
1178 /* p is the the StgThreadReturnCode for this thread */
1179 RETURN((StgThreadReturnCode)p);
1185 /* combined insns, created by peephole opt */
1188 int x = BCO_INSTR_8;
1189 int y = BCO_INSTR_8;
1190 ASSERT(xSp+x+y <= stgCast(StgPtr,xSu));
1191 /* a_1, .. a_x, b_1, .. b_y, s => a_1, .. a_x, s */
1198 xSetStackWord(x+y,xStackWord(x));
1208 p = xStackPtr(BCO_INSTR_8);
1210 p = xStackPtr(BCO_INSTR_8);
1217 xPushPtr(bcoConstPtr(bco,BCO_INSTR_8));
1218 xPushPtr(stgCast(StgPtr,&ret_bco_info));
1219 p = xStackPtr(BCO_INSTR_8);
1225 StgPtr retaddr = bcoConstPtr(bco,BCO_INSTR_8);
1226 StgPtr ptr = xStackPtr(BCO_INSTR_8);
1228 /* A shortcut. We're going to push the address of a
1229 return continuation, and then enter a variable, so
1230 that when the var is evaluated, we return to the
1231 continuation. The shortcut is: if the var is a
1232 constructor, don't bother to enter it. Instead,
1233 push the variable on the stack (since this is what
1234 the continuation expects) and jump directly to the
1237 if (get_itbl((StgClosure*)ptr)->type == CONSTR) {
1239 obj = (StgClosure*)retaddr;
1241 fprintf(stderr, "object to enter is a constructor -- "
1242 "jumping directly to return continuation\n" );
1247 /* This is the normal, non-short-cut route */
1249 xPushPtr(stgCast(StgPtr,&ret_bco_info));
1250 obj = (StgClosure*)ptr;
1255 Case(i_VAR_DOUBLE_big):
1256 Case(i_CONST_FLOAT_big):
1257 Case(i_VAR_FLOAT_big):
1258 Case(i_CONST_CHAR_big):
1259 Case(i_VAR_CHAR_big):
1260 Case(i_CONST_ADDR_big):
1261 Case(i_VAR_ADDR_big):
1262 Case(i_CONST_INTEGER_big):
1263 Case(i_CONST_INT_big):
1264 Case(i_VAR_INT_big):
1265 Case(i_VAR_WORD_big):
1266 Case(i_RETADDR_big):
1270 disInstr ( bco, PC );
1271 barf("\nUnrecognised instruction");
1275 barf("enterBCO: ran off end of loop");
1279 # undef LoopTopLabel
1285 /* ---------------------------------------------------- */
1286 /* End of the bytecode evaluator */
1287 /* ---------------------------------------------------- */
1291 StgBlockingQueue* bh;
1292 StgCAF* caf = (StgCAF*)obj;
1293 if (xSp - sizeofW(StgUpdateFrame) < xSpLim) {
1294 xPushCPtr(obj); /* code to restart with */
1295 RETURN(StackOverflow);
1297 /* ToDo: look for xSp==xSu && stackInt(0) == UPD_FRAME
1298 and insert an indirection immediately */
1299 SSS; bh = (StgBlockingQueue*)grabHpUpd(BLACKHOLE_sizeW()); LLL;
1300 SET_INFO(bh,&CAF_BLACKHOLE_info);
1301 bh->blocking_queue = EndTSOQueue;
1303 fprintf(stderr,"Created CAF_BLACKHOLE %p for CAF %p in evaluator\n",bh,caf));
1304 SET_INFO(caf,&CAF_ENTERED_info);
1305 caf->value = (StgClosure*)bh;
1306 if (caf->mut_link == NULL) {
1307 SSS; recordOldToNewPtrs((StgMutClosure*)caf); LLL;
1309 xPushUpdateFrame(bh,0);
1310 xSp -= sizeofW(StgUpdateFrame);
1311 caf->link = enteredCAFs;
1318 StgCAF* caf = (StgCAF*)obj;
1319 obj = caf->value; /* it's just a fancy indirection */
1325 case SE_CAF_BLACKHOLE:
1327 /*was StgBlackHole* */
1328 StgBlockingQueue* bh = (StgBlockingQueue*)obj;
1329 /* Put ourselves on the blocking queue for this black hole and block */
1330 cap->rCurrentTSO->link = bh->blocking_queue;
1331 bh->blocking_queue = cap->rCurrentTSO;
1332 xPushCPtr(obj); /* code to restart with */
1333 barf("enter: CAF_BLACKHOLE unexpected!");
1334 RETURN(ThreadBlocked);
1338 StgAP_UPD* ap = stgCast(StgAP_UPD*,obj);
1340 if (xSp - (i + sizeofW(StgUpdateFrame)) < xSpLim) {
1341 xPushCPtr(obj); /* code to restart with */
1342 RETURN(StackOverflow);
1344 /* ToDo: look for xSp==xSu && stackInt(0) == UPD_FRAME
1345 and insert an indirection immediately */
1346 xPushUpdateFrame(ap,0);
1347 xSp -= sizeofW(StgUpdateFrame);
1349 xPushWord(payloadWord(ap,i));
1352 #ifdef EAGER_BLACKHOLING
1353 #warn LAZY_BLACKHOLING is default for StgHugs
1354 #error Dont know if EAGER_BLACKHOLING works in StgHugs
1356 /* superfluous - but makes debugging easier */
1357 StgBlackHole* bh = stgCast(StgBlackHole*,ap);
1358 SET_INFO(bh,&BLACKHOLE_info);
1359 bh->blocking_queue = EndTSOQueue;
1361 fprintf(stderr,"Eagerly blackholed AP_UPD %p in evaluator\n",bh));
1364 #endif /* EAGER_BLACKHOLING */
1369 StgPAP* pap = stgCast(StgPAP*,obj);
1370 int i = pap->n_args; /* ToDo: stack check */
1371 /* ToDo: if PAP is in whnf, we can update any update frames
1375 xPushWord(payloadWord(pap,i));
1382 obj = stgCast(StgInd*,obj)->indirectee;
1387 obj = stgCast(StgIndOldGen*,obj)->indirectee;
1396 case CONSTR_INTLIKE:
1397 case CONSTR_CHARLIKE:
1399 case CONSTR_NOCAF_STATIC:
1402 switch (get_itbl(stgCast(StgClosure*,xSp))->type) {
1404 SSS; PopCatchFrame(); LLL;
1407 xPopUpdateFrame(obj);
1410 SSS; PopSeqFrame(); LLL;
1414 ASSERT(xSp==(P_)xSu);
1417 fprintf(stderr, "hit a STOP_FRAME\n");
1419 fprintf(stderr,"xSp = %p\txSu = %p\n", xSp, xSu);
1420 printStack(xSp,cap->rCurrentTSO->stack
1421 + cap->rCurrentTSO->stack_size,xSu);
1424 SSS; PopStopFrame(obj); LLL;
1425 RETURN(ThreadFinished);
1435 /* was: goto enterLoop;
1436 But we know that obj must be a bco now, so jump directly.
1439 case RET_SMALL: /* return to GHC */
1443 // barf("todo: RET_[VEC_]{BIG,SMALL}");
1445 belch("entered CONSTR with invalid continuation on stack");
1448 printObj(stgCast(StgClosure*,xSp));
1451 barf("bailing out");
1458 //fprintf(stderr, "enterCountI = %d\n", enterCountI);
1459 //fprintf(stderr, "entering unknown closure -- yielding to sched\n");
1462 cap->rCurrentTSO->whatNext = ThreadEnterGHC;
1463 xPushCPtr(obj); /* code to restart with */
1464 RETURN(ThreadYielding);
1467 barf("Ran off the end of enter - yoiks");
1484 #undef xSetStackWord
1487 #undef xPushTaggedInt
1488 #undef xPopTaggedInt
1489 #undef xTaggedStackInt
1490 #undef xPushTaggedWord
1491 #undef xPopTaggedWord
1492 #undef xTaggedStackWord
1493 #undef xPushTaggedAddr
1494 #undef xTaggedStackAddr
1495 #undef xPopTaggedAddr
1496 #undef xPushTaggedStable
1497 #undef xTaggedStackStable
1498 #undef xPopTaggedStable
1499 #undef xPushTaggedChar
1500 #undef xTaggedStackChar
1501 #undef xPopTaggedChar
1502 #undef xPushTaggedFloat
1503 #undef xTaggedStackFloat
1504 #undef xPopTaggedFloat
1505 #undef xPushTaggedDouble
1506 #undef xTaggedStackDouble
1507 #undef xPopTaggedDouble
1508 #undef xPopUpdateFrame
1509 #undef xPushUpdateFrame
1512 /* --------------------------------------------------------------------------
1513 * Supporting routines for primops
1514 * ------------------------------------------------------------------------*/
1516 static inline void PushTag ( StackTag t )
1518 inline void PushPtr ( StgPtr x )
1519 { *(--stgCast(StgPtr*,gSp)) = x; }
1520 static inline void PushCPtr ( StgClosure* x )
1521 { *(--stgCast(StgClosure**,gSp)) = x; }
1522 static inline void PushInt ( StgInt x )
1523 { *(--stgCast(StgInt*,gSp)) = x; }
1524 static inline void PushWord ( StgWord x )
1525 { *(--stgCast(StgWord*,gSp)) = x; }
1528 static inline void checkTag ( StackTag t1, StackTag t2 )
1529 { ASSERT(t1 == t2);}
1530 static inline void PopTag ( StackTag t )
1531 { checkTag(t,*(gSp++)); }
1532 inline StgPtr PopPtr ( void )
1533 { return *stgCast(StgPtr*,gSp)++; }
1534 static inline StgClosure* PopCPtr ( void )
1535 { return *stgCast(StgClosure**,gSp)++; }
1536 static inline StgInt PopInt ( void )
1537 { return *stgCast(StgInt*,gSp)++; }
1538 static inline StgWord PopWord ( void )
1539 { return *stgCast(StgWord*,gSp)++; }
1541 static inline StgPtr stackPtr ( StgStackOffset i )
1542 { return *stgCast(StgPtr*, gSp+i); }
1543 static inline StgInt stackInt ( StgStackOffset i )
1544 { return *stgCast(StgInt*, gSp+i); }
1545 static inline StgWord stackWord ( StgStackOffset i )
1546 { return *stgCast(StgWord*,gSp+i); }
1548 static inline void setStackWord ( StgStackOffset i, StgWord w )
1551 static inline void PushTaggedRealWorld( void )
1552 { PushTag(REALWORLD_TAG); }
1553 inline void PushTaggedInt ( StgInt x )
1554 { gSp -= sizeofW(StgInt); *gSp = x; PushTag(INT_TAG); }
1555 inline void PushTaggedWord ( StgWord x )
1556 { gSp -= sizeofW(StgWord); *gSp = x; PushTag(WORD_TAG); }
1557 inline void PushTaggedAddr ( StgAddr x )
1558 { gSp -= sizeofW(StgAddr); *gSp = (W_)x; PushTag(ADDR_TAG); }
1559 inline void PushTaggedChar ( StgChar x )
1560 { gSp -= sizeofW(StgChar); *gSp = stgCast(StgWord,x); PushTag(CHAR_TAG); }
1561 inline void PushTaggedFloat ( StgFloat x )
1562 { gSp -= sizeofW(StgFloat); ASSIGN_FLT(gSp,x); PushTag(FLOAT_TAG); }
1563 inline void PushTaggedDouble ( StgDouble x )
1564 { gSp -= sizeofW(StgDouble); ASSIGN_DBL(gSp,x); PushTag(DOUBLE_TAG); }
1565 inline void PushTaggedStablePtr ( StgStablePtr x )
1566 { gSp -= sizeofW(StgStablePtr); *gSp = x; PushTag(STABLE_TAG); }
1567 static inline void PushTaggedBool ( int x )
1568 { PushTaggedInt(x); }
1572 static inline void PopTaggedRealWorld ( void )
1573 { PopTag(REALWORLD_TAG); }
1574 inline StgInt PopTaggedInt ( void )
1575 { StgInt r; PopTag(INT_TAG); r = *stgCast(StgInt*, gSp);
1576 gSp += sizeofW(StgInt); return r;}
1577 inline StgWord PopTaggedWord ( void )
1578 { StgWord r; PopTag(WORD_TAG); r = *stgCast(StgWord*, gSp);
1579 gSp += sizeofW(StgWord); return r;}
1580 inline StgAddr PopTaggedAddr ( void )
1581 { StgAddr r; PopTag(ADDR_TAG); r = *stgCast(StgAddr*, gSp);
1582 gSp += sizeofW(StgAddr); return r;}
1583 inline StgChar PopTaggedChar ( void )
1584 { StgChar r; PopTag(CHAR_TAG); r = stgCast(StgChar, *gSp);
1585 gSp += sizeofW(StgChar); return r;}
1586 inline StgFloat PopTaggedFloat ( void )
1587 { StgFloat r; PopTag(FLOAT_TAG); r = PK_FLT(gSp);
1588 gSp += sizeofW(StgFloat); return r;}
1589 inline StgDouble PopTaggedDouble ( void )
1590 { StgDouble r; PopTag(DOUBLE_TAG); r = PK_DBL(gSp);
1591 gSp += sizeofW(StgDouble); return r;}
1592 inline StgStablePtr PopTaggedStablePtr ( void )
1593 { StgInt r; PopTag(STABLE_TAG); r = *stgCast(StgStablePtr*, gSp);
1594 gSp += sizeofW(StgStablePtr); return r;}
1598 static inline StgInt taggedStackInt ( StgStackOffset i )
1599 { checkTag(INT_TAG,gSp[i]); return *stgCast(StgInt*, gSp+1+i); }
1600 static inline StgWord taggedStackWord ( StgStackOffset i )
1601 { checkTag(WORD_TAG,gSp[i]); return *stgCast(StgWord*, gSp+1+i); }
1602 static inline StgAddr taggedStackAddr ( StgStackOffset i )
1603 { checkTag(ADDR_TAG,gSp[i]); return *stgCast(StgAddr*, gSp+1+i); }
1604 static inline StgChar taggedStackChar ( StgStackOffset i )
1605 { checkTag(CHAR_TAG,gSp[i]); return stgCast(StgChar, *(gSp+1+i)) ; }
1606 static inline StgFloat taggedStackFloat ( StgStackOffset i )
1607 { checkTag(FLOAT_TAG,gSp[i]); return PK_FLT(gSp+1+i); }
1608 static inline StgDouble taggedStackDouble ( StgStackOffset i )
1609 { checkTag(DOUBLE_TAG,gSp[i]); return PK_DBL(gSp+1+i); }
1610 static inline StgStablePtr taggedStackStable ( StgStackOffset i )
1611 { checkTag(STABLE_TAG,gSp[i]); return *stgCast(StgStablePtr*, gSp+1+i); }
1614 /* --------------------------------------------------------------------------
1617 * Should we allocate from a nursery or use the
1618 * doYouWantToGC/allocate interface? We'd already implemented a
1619 * nursery-style scheme when the doYouWantToGC/allocate interface
1621 * One reason to prefer the doYouWantToGC/allocate interface is to
1622 * support operations which allocate an unknown amount in the heap
1623 * (array ops, gmp ops, etc)
1624 * ------------------------------------------------------------------------*/
1626 static inline StgPtr grabHpUpd( nat size )
1628 ASSERT( size >= MIN_UPD_SIZE + sizeofW(StgHeader) );
1629 #ifdef CRUDE_PROFILING
1630 cp_bill_words ( size );
1632 return allocate(size);
1635 static inline StgPtr grabHpNonUpd( nat size )
1637 ASSERT( size >= MIN_NONUPD_SIZE + sizeofW(StgHeader) );
1638 #ifdef CRUDE_PROFILING
1639 cp_bill_words ( size );
1641 return allocate(size);
1644 /* --------------------------------------------------------------------------
1645 * Manipulate "update frame" list:
1646 * o Update frames (based on stg_do_update and friends in Updates.hc)
1647 * o Error handling/catching (based on catchzh_fast and friends in Prims.hc)
1648 * o Seq frames (based on seq_frame_entry in Prims.hc)
1650 * ------------------------------------------------------------------------*/
1652 static inline void PopUpdateFrame ( StgClosure* obj )
1654 /* NB: doesn't assume that gSp == gSu */
1656 fprintf(stderr, "Updating ");
1657 printPtr(stgCast(StgPtr,gSu->updatee));
1658 fprintf(stderr, " with ");
1660 fprintf(stderr,"gSp = %p\tgSu = %p\n\n", gSp, gSu);
1662 #ifdef EAGER_BLACKHOLING
1663 #warn LAZY_BLACKHOLING is default for StgHugs
1664 #error Dont know if EAGER_BLACKHOLING works in StgHugs
1665 ASSERT(get_itbl(gSu->updatee)->type == BLACKHOLE
1666 || get_itbl(gSu->updatee)->type == SE_BLACKHOLE
1667 || get_itbl(gSu->updatee)->type == CAF_BLACKHOLE
1668 || get_itbl(gSu->updatee)->type == SE_CAF_BLACKHOLE
1670 #endif /* EAGER_BLACKHOLING */
1671 UPD_IND(gSu->updatee,obj);
1672 gSp = stgCast(StgStackPtr,gSu) + sizeofW(StgUpdateFrame);
1676 static inline void PopStopFrame ( StgClosure* obj )
1678 /* Move gSu just off the end of the stack, we're about to gSpam the
1679 * STOP_FRAME with the return value.
1681 gSu = stgCast(StgUpdateFrame*,gSp+1);
1682 *stgCast(StgClosure**,gSp) = obj;
1685 static inline void PushCatchFrame ( StgClosure* handler )
1688 /* ToDo: stack check! */
1689 gSp -= sizeofW(StgCatchFrame);
1690 fp = stgCast(StgCatchFrame*,gSp);
1691 SET_HDR(fp,(StgInfoTable*)&catch_frame_info,CCCS);
1692 fp->handler = handler;
1694 gSu = stgCast(StgUpdateFrame*,fp);
1697 static inline void PopCatchFrame ( void )
1699 /* NB: doesn't assume that gSp == gSu */
1700 /* fprintf(stderr,"Popping catch frame\n"); */
1701 gSp = stgCast(StgStackPtr,gSu) + sizeofW(StgCatchFrame);
1702 gSu = stgCast(StgCatchFrame*,gSu)->link;
1705 static inline void PushSeqFrame ( void )
1708 /* ToDo: stack check! */
1709 gSp -= sizeofW(StgSeqFrame);
1710 fp = stgCast(StgSeqFrame*,gSp);
1711 SET_HDR(fp,(StgInfoTable*)&seq_frame_info,CCCS);
1713 gSu = stgCast(StgUpdateFrame*,fp);
1716 static inline void PopSeqFrame ( void )
1718 /* NB: doesn't assume that gSp == gSu */
1719 gSp = stgCast(StgStackPtr,gSu) + sizeofW(StgSeqFrame);
1720 gSu = stgCast(StgSeqFrame*,gSu)->link;
1723 static inline StgClosure* raiseAnError ( StgClosure* errObj )
1725 StgClosure *raise_closure;
1727 /* This closure represents the expression 'raise# E' where E
1728 * is the exception raised. It is used to overwrite all the
1729 * thunks which are currently under evaluation.
1731 raise_closure = (StgClosure *)allocate(sizeofW(StgClosure)+1);
1732 raise_closure->header.info = &raise_info;
1733 raise_closure->payload[0] = 0xdeadbeef; /*R1.cl;*/
1736 switch (get_itbl(gSu)->type) {
1738 UPD_IND(gSu->updatee,raise_closure);
1739 gSp = stgCast(StgStackPtr,gSu) + sizeofW(StgUpdateFrame);
1745 case CATCH_FRAME: /* found it! */
1747 StgCatchFrame* fp = stgCast(StgCatchFrame*,gSu);
1748 StgClosure *handler = fp->handler;
1750 gSp += sizeofW(StgCatchFrame); /* Pop */
1755 barf("raiseError: uncaught exception: STOP_FRAME");
1757 barf("raiseError: weird activation record");
1763 static StgClosure* makeErrorCall ( const char* msg )
1765 /* Note! the msg string should be allocated in a
1766 place which will not get freed -- preferably
1767 read-only data of the program. That's because
1768 the thunk we build here may linger indefinitely.
1769 (thinks: probably not so, but anyway ...)
1772 = asmClosureOfObject(getHugs_AsmObject_for("error"));
1774 = asmClosureOfObject(getHugs_AsmObject_for("primUnpackString"));
1776 = rts_apply ( unpack, rts_mkAddr ( (void*)msg ) );
1778 = rts_apply ( error, thunk );
1780 (StgClosure*) thunk;
1783 #define raiseIndex(where) makeErrorCall("Array index out of range in " where)
1784 #define raiseDiv0(where) makeErrorCall("Division by zero in " where)
1786 /* --------------------------------------------------------------------------
1788 * ------------------------------------------------------------------------*/
1790 #define OP_CC_B(e) \
1792 unsigned char x = PopTaggedChar(); \
1793 unsigned char y = PopTaggedChar(); \
1794 PushTaggedBool(e); \
1799 unsigned char x = PopTaggedChar(); \
1808 #define OP_IW_I(e) \
1810 StgInt x = PopTaggedInt(); \
1811 StgWord y = PopTaggedWord(); \
1815 #define OP_II_I(e) \
1817 StgInt x = PopTaggedInt(); \
1818 StgInt y = PopTaggedInt(); \
1822 #define OP_II_B(e) \
1824 StgInt x = PopTaggedInt(); \
1825 StgInt y = PopTaggedInt(); \
1826 PushTaggedBool(e); \
1831 PushTaggedAddr(e); \
1836 StgInt x = PopTaggedInt(); \
1837 PushTaggedAddr(e); \
1842 StgInt x = PopTaggedInt(); \
1848 PushTaggedChar(e); \
1853 StgInt x = PopTaggedInt(); \
1854 PushTaggedChar(e); \
1859 PushTaggedWord(e); \
1864 StgInt x = PopTaggedInt(); \
1865 PushTaggedWord(e); \
1870 StgInt x = PopTaggedInt(); \
1871 PushTaggedStablePtr(e); \
1876 PushTaggedFloat(e); \
1881 StgInt x = PopTaggedInt(); \
1882 PushTaggedFloat(e); \
1887 PushTaggedDouble(e); \
1892 StgInt x = PopTaggedInt(); \
1893 PushTaggedDouble(e); \
1896 #define OP_WW_B(e) \
1898 StgWord x = PopTaggedWord(); \
1899 StgWord y = PopTaggedWord(); \
1900 PushTaggedBool(e); \
1903 #define OP_WW_W(e) \
1905 StgWord x = PopTaggedWord(); \
1906 StgWord y = PopTaggedWord(); \
1907 PushTaggedWord(e); \
1912 StgWord x = PopTaggedWord(); \
1918 StgStablePtr x = PopTaggedStablePtr(); \
1924 StgWord x = PopTaggedWord(); \
1925 PushTaggedWord(e); \
1928 #define OP_AA_B(e) \
1930 StgAddr x = PopTaggedAddr(); \
1931 StgAddr y = PopTaggedAddr(); \
1932 PushTaggedBool(e); \
1936 StgAddr x = PopTaggedAddr(); \
1939 #define OP_AI_C(s) \
1941 StgAddr x = PopTaggedAddr(); \
1942 int y = PopTaggedInt(); \
1945 PushTaggedChar(r); \
1947 #define OP_AI_I(s) \
1949 StgAddr x = PopTaggedAddr(); \
1950 int y = PopTaggedInt(); \
1955 #define OP_AI_A(s) \
1957 StgAddr x = PopTaggedAddr(); \
1958 int y = PopTaggedInt(); \
1961 PushTaggedAddr(s); \
1963 #define OP_AI_F(s) \
1965 StgAddr x = PopTaggedAddr(); \
1966 int y = PopTaggedInt(); \
1969 PushTaggedFloat(r); \
1971 #define OP_AI_D(s) \
1973 StgAddr x = PopTaggedAddr(); \
1974 int y = PopTaggedInt(); \
1977 PushTaggedDouble(r); \
1979 #define OP_AI_s(s) \
1981 StgAddr x = PopTaggedAddr(); \
1982 int y = PopTaggedInt(); \
1985 PushTaggedStablePtr(r); \
1987 #define OP_AIC_(s) \
1989 StgAddr x = PopTaggedAddr(); \
1990 int y = PopTaggedInt(); \
1991 StgChar z = PopTaggedChar(); \
1994 #define OP_AII_(s) \
1996 StgAddr x = PopTaggedAddr(); \
1997 int y = PopTaggedInt(); \
1998 StgInt z = PopTaggedInt(); \
2001 #define OP_AIA_(s) \
2003 StgAddr x = PopTaggedAddr(); \
2004 int y = PopTaggedInt(); \
2005 StgAddr z = PopTaggedAddr(); \
2008 #define OP_AIF_(s) \
2010 StgAddr x = PopTaggedAddr(); \
2011 int y = PopTaggedInt(); \
2012 StgFloat z = PopTaggedFloat(); \
2015 #define OP_AID_(s) \
2017 StgAddr x = PopTaggedAddr(); \
2018 int y = PopTaggedInt(); \
2019 StgDouble z = PopTaggedDouble(); \
2022 #define OP_AIs_(s) \
2024 StgAddr x = PopTaggedAddr(); \
2025 int y = PopTaggedInt(); \
2026 StgStablePtr z = PopTaggedStablePtr(); \
2031 #define OP_FF_B(e) \
2033 StgFloat x = PopTaggedFloat(); \
2034 StgFloat y = PopTaggedFloat(); \
2035 PushTaggedBool(e); \
2038 #define OP_FF_F(e) \
2040 StgFloat x = PopTaggedFloat(); \
2041 StgFloat y = PopTaggedFloat(); \
2042 PushTaggedFloat(e); \
2047 StgFloat x = PopTaggedFloat(); \
2048 PushTaggedFloat(e); \
2053 StgFloat x = PopTaggedFloat(); \
2054 PushTaggedBool(e); \
2059 StgFloat x = PopTaggedFloat(); \
2065 StgFloat x = PopTaggedFloat(); \
2066 PushTaggedDouble(e); \
2069 #define OP_DD_B(e) \
2071 StgDouble x = PopTaggedDouble(); \
2072 StgDouble y = PopTaggedDouble(); \
2073 PushTaggedBool(e); \
2076 #define OP_DD_D(e) \
2078 StgDouble x = PopTaggedDouble(); \
2079 StgDouble y = PopTaggedDouble(); \
2080 PushTaggedDouble(e); \
2085 StgDouble x = PopTaggedDouble(); \
2086 PushTaggedBool(e); \
2091 StgDouble x = PopTaggedDouble(); \
2092 PushTaggedDouble(e); \
2097 StgDouble x = PopTaggedDouble(); \
2103 StgDouble x = PopTaggedDouble(); \
2104 PushTaggedFloat(e); \
2108 #ifdef STANDALONE_INTEGER
2109 StgPtr CreateByteArrayToHoldInteger ( int nbytes )
2111 StgInt words = (nbytes+sizeof(W_)-1)/sizeof(W_);
2112 StgWord size = sizeofW(StgArrWords) + words;
2113 StgArrWords* arr = (StgArrWords*)allocate(size);
2114 SET_HDR(arr,&ARR_WORDS_info,CCCS);
2116 ASSERT(nbytes <= arr->words * sizeof(W_));
2119 for (i = 0; i < words; ++i) {
2120 arr->payload[i] = 0xdeadbeef;
2122 { B* b = (B*) &(arr->payload[0]);
2123 b->used = b->sign = 0;
2129 B* IntegerInsideByteArray ( StgPtr arr0 )
2132 StgArrWords* arr = (StgArrWords*)arr0;
2133 ASSERT(GET_INFO(arr) == &ARR_WORDS_info);
2134 b = (B*) &(arr->payload[0]);
2138 void SloppifyIntegerEnd ( StgPtr arr0 )
2140 StgArrWords* arr = (StgArrWords*)arr0;
2141 B* b = (B*) & (arr->payload[0]);
2142 I_ nwunused = arr->words - sizeofW(B) - (b->used+sizeof(W_)-1)/sizeof(W_);
2143 if (nwunused >= ((I_)sizeofW(StgArrWords))) {
2145 b->size -= nwunused * sizeof(W_);
2146 if (b->size < b->used) b->size = b->used;
2149 arr->words -= nwunused;
2150 slop = (StgArrWords*)&(arr->payload[arr->words]);
2151 SET_HDR(slop,&ARR_WORDS_info,CCCS);
2152 slop->words = nwunused - sizeofW(StgArrWords);
2153 ASSERT( &(slop->payload[slop->words]) ==
2154 &(arr->payload[arr->words + nwunused]) );
2158 #define OP_Z_Z(op) \
2160 B* x = IntegerInsideByteArray(PopPtr()); \
2161 int n = mycat2(size_,op)(x); \
2162 StgPtr p = CreateByteArrayToHoldInteger(n); \
2163 mycat2(do_,op)(x,n,IntegerInsideByteArray(p)); \
2164 SloppifyIntegerEnd(p); \
2167 #define OP_ZZ_Z(op) \
2169 B* x = IntegerInsideByteArray(PopPtr()); \
2170 B* y = IntegerInsideByteArray(PopPtr()); \
2171 int n = mycat2(size_,op)(x,y); \
2172 StgPtr p = CreateByteArrayToHoldInteger(n); \
2173 mycat2(do_,op)(x,y,n,IntegerInsideByteArray(p)); \
2174 SloppifyIntegerEnd(p); \
2182 #define HEADER_mI(ty,where) \
2183 StgArrWords* x = stgCast(StgArrWords*,PopPtr()); \
2184 nat i = PopTaggedInt(); \
2185 if (i * sizeof(ty) + (sizeof(ty)) > sizeof(StgWord) * x->words) { \
2186 return (raiseIndex(where)); \
2188 #define OP_mI_ty(ty,where,s) \
2190 HEADER_mI(mycat2(Stg,ty),where) \
2191 { mycat2(Stg,ty) r; \
2193 mycat2(PushTagged,ty)(r); \
2196 #define OP_mIty_(ty,where,s) \
2198 HEADER_mI(mycat2(Stg,ty),where) \
2200 mycat2(Stg,ty) z = mycat2(PopTagged,ty)(); \
2206 void myStackCheck ( Capability* cap )
2208 /* fprintf(stderr, "myStackCheck\n"); */
2209 if (!(gSpLim <= gSp && gSp <= stgCast(StgPtr,gSu))) {
2210 fprintf(stderr, "myStackCheck: invalid initial gSp/gSu \n" );
2214 if (!(gSu >= cap->rCurrentTSO->stack
2215 && gSu <= cap->rCurrentTSO->stack
2216 + cap->rCurrentTSO->stack_size)) {
2217 fprintf ( stderr, "myStackCheck: gSu out of stack\n" );
2220 switch (get_itbl(stgCast(StgClosure*,gSu))->type) {
2222 gSu = (StgPtr) ((StgCatchFrame*)(gSu))->link;
2225 gSu = (StgPtr) ((StgUpdateFrame*)(gSu))->link;
2228 gSu = (StgPtr) ((StgSeqFrame*)(gSu))->link;
2233 fprintf(stderr, "myStackCheck: invalid activation record\n"); assert(0);
2240 /* --------------------------------------------------------------------------
2241 * Primop stuff for bytecode interpreter
2242 * ------------------------------------------------------------------------*/
2244 /* Returns & of the next thing to enter (if throwing an exception),
2245 or NULL in the normal case.
2247 static void* enterBCO_primop1 ( int primop1code )
2249 switch (primop1code) {
2250 case i_pushseqframe:
2252 StgClosure* c = PopCPtr();
2257 case i_pushcatchframe:
2259 StgClosure* e = PopCPtr();
2260 StgClosure* h = PopCPtr();
2266 case i_gtChar: OP_CC_B(x>y); break;
2267 case i_geChar: OP_CC_B(x>=y); break;
2268 case i_eqChar: OP_CC_B(x==y); break;
2269 case i_neChar: OP_CC_B(x!=y); break;
2270 case i_ltChar: OP_CC_B(x<y); break;
2271 case i_leChar: OP_CC_B(x<=y); break;
2272 case i_charToInt: OP_C_I(x); break;
2273 case i_intToChar: OP_I_C(x); break;
2275 case i_gtInt: OP_II_B(x>y); break;
2276 case i_geInt: OP_II_B(x>=y); break;
2277 case i_eqInt: OP_II_B(x==y); break;
2278 case i_neInt: OP_II_B(x!=y); break;
2279 case i_ltInt: OP_II_B(x<y); break;
2280 case i_leInt: OP_II_B(x<=y); break;
2281 case i_minInt: OP__I(INT_MIN); break;
2282 case i_maxInt: OP__I(INT_MAX); break;
2283 case i_plusInt: OP_II_I(x+y); break;
2284 case i_minusInt: OP_II_I(x-y); break;
2285 case i_timesInt: OP_II_I(x*y); break;
2288 int x = PopTaggedInt();
2289 int y = PopTaggedInt();
2291 return (raiseDiv0("quotInt"));
2293 /* ToDo: protect against minInt / -1 errors
2294 * (repeat for all other division primops) */
2300 int x = PopTaggedInt();
2301 int y = PopTaggedInt();
2303 return (raiseDiv0("remInt"));
2310 StgInt x = PopTaggedInt();
2311 StgInt y = PopTaggedInt();
2313 return (raiseDiv0("quotRemInt"));
2315 PushTaggedInt(x%y); /* last result */
2316 PushTaggedInt(x/y); /* first result */
2319 case i_negateInt: OP_I_I(-x); break;
2321 case i_andInt: OP_II_I(x&y); break;
2322 case i_orInt: OP_II_I(x|y); break;
2323 case i_xorInt: OP_II_I(x^y); break;
2324 case i_notInt: OP_I_I(~x); break;
2325 case i_shiftLInt: OP_II_I(x<<y); break;
2326 case i_shiftRAInt: OP_II_I(x>>y); break; /* ToDo */
2327 case i_shiftRLInt: OP_II_I(x>>y); break; /* ToDo */
2329 case i_gtWord: OP_WW_B(x>y); break;
2330 case i_geWord: OP_WW_B(x>=y); break;
2331 case i_eqWord: OP_WW_B(x==y); break;
2332 case i_neWord: OP_WW_B(x!=y); break;
2333 case i_ltWord: OP_WW_B(x<y); break;
2334 case i_leWord: OP_WW_B(x<=y); break;
2335 case i_minWord: OP__W(0); break;
2336 case i_maxWord: OP__W(UINT_MAX); break;
2337 case i_plusWord: OP_WW_W(x+y); break;
2338 case i_minusWord: OP_WW_W(x-y); break;
2339 case i_timesWord: OP_WW_W(x*y); break;
2342 StgWord x = PopTaggedWord();
2343 StgWord y = PopTaggedWord();
2345 return (raiseDiv0("quotWord"));
2347 PushTaggedWord(x/y);
2352 StgWord x = PopTaggedWord();
2353 StgWord y = PopTaggedWord();
2355 return (raiseDiv0("remWord"));
2357 PushTaggedWord(x%y);
2362 StgWord x = PopTaggedWord();
2363 StgWord y = PopTaggedWord();
2365 return (raiseDiv0("quotRemWord"));
2367 PushTaggedWord(x%y); /* last result */
2368 PushTaggedWord(x/y); /* first result */
2371 case i_negateWord: OP_W_W(-x); break;
2372 case i_andWord: OP_WW_W(x&y); break;
2373 case i_orWord: OP_WW_W(x|y); break;
2374 case i_xorWord: OP_WW_W(x^y); break;
2375 case i_notWord: OP_W_W(~x); break;
2376 case i_shiftLWord: OP_WW_W(x<<y); break;
2377 case i_shiftRAWord: OP_WW_W(x>>y); break; /* ToDo */
2378 case i_shiftRLWord: OP_WW_W(x>>y); break; /* ToDo */
2379 case i_intToWord: OP_I_W(x); break;
2380 case i_wordToInt: OP_W_I(x); break;
2382 case i_gtAddr: OP_AA_B(x>y); break;
2383 case i_geAddr: OP_AA_B(x>=y); break;
2384 case i_eqAddr: OP_AA_B(x==y); break;
2385 case i_neAddr: OP_AA_B(x!=y); break;
2386 case i_ltAddr: OP_AA_B(x<y); break;
2387 case i_leAddr: OP_AA_B(x<=y); break;
2388 case i_intToAddr: OP_I_A((StgAddr)x); break; /* ToDo */
2389 case i_addrToInt: OP_A_I((StgInt)x); break; /* ToDo */
2391 case i_intToStable: OP_I_s(x); break;
2392 case i_stableToInt: OP_s_I(x); break;
2394 case i_indexCharOffAddr: OP_AI_C(indexCharOffAddrzh(r,x,y)); break;
2395 case i_readCharOffAddr: OP_AI_C(indexCharOffAddrzh(r,x,y)); break;
2396 case i_writeCharOffAddr: OP_AIC_(writeCharOffAddrzh(x,y,z)); break;
2398 case i_indexIntOffAddr: OP_AI_I(indexIntOffAddrzh(r,x,y)); break;
2399 case i_readIntOffAddr: OP_AI_I(indexIntOffAddrzh(r,x,y)); break;
2400 case i_writeIntOffAddr: OP_AII_(writeIntOffAddrzh(x,y,z)); break;
2402 case i_indexAddrOffAddr: OP_AI_A(indexAddrOffAddrzh(r,x,y)); break;
2403 case i_readAddrOffAddr: OP_AI_A(indexAddrOffAddrzh(r,x,y)); break;
2404 case i_writeAddrOffAddr: OP_AIA_(writeAddrOffAddrzh(x,y,z)); break;
2406 case i_indexFloatOffAddr: OP_AI_F(indexFloatOffAddrzh(r,x,y)); break;
2407 case i_readFloatOffAddr: OP_AI_F(indexFloatOffAddrzh(r,x,y)); break;
2408 case i_writeFloatOffAddr: OP_AIF_(writeFloatOffAddrzh(x,y,z)); break;
2410 case i_indexDoubleOffAddr: OP_AI_D(indexDoubleOffAddrzh(r,x,y)); break;
2411 case i_readDoubleOffAddr: OP_AI_D(indexDoubleOffAddrzh(r,x,y)); break;
2412 case i_writeDoubleOffAddr: OP_AID_(writeDoubleOffAddrzh(x,y,z)); break;
2414 case i_indexStableOffAddr: OP_AI_s(indexStablePtrOffAddrzh(r,x,y)); break;
2415 case i_readStableOffAddr: OP_AI_s(indexStablePtrOffAddrzh(r,x,y)); break;
2416 case i_writeStableOffAddr: OP_AIs_(writeStablePtrOffAddrzh(x,y,z)); break;
2418 #ifdef STANDALONE_INTEGER
2419 case i_compareInteger:
2421 B* x = IntegerInsideByteArray(PopPtr());
2422 B* y = IntegerInsideByteArray(PopPtr());
2423 StgInt r = do_cmp(x,y);
2424 PushTaggedInt(r<0 ? -1 : (r>0 ? 1 : 0));
2427 case i_negateInteger: OP_Z_Z(neg); break;
2428 case i_plusInteger: OP_ZZ_Z(add); break;
2429 case i_minusInteger: OP_ZZ_Z(sub); break;
2430 case i_timesInteger: OP_ZZ_Z(mul); break;
2431 case i_quotRemInteger:
2433 B* x = IntegerInsideByteArray(PopPtr());
2434 B* y = IntegerInsideByteArray(PopPtr());
2435 int n = size_qrm(x,y);
2436 StgPtr q = CreateByteArrayToHoldInteger(n);
2437 StgPtr r = CreateByteArrayToHoldInteger(n);
2438 if (do_getsign(y)==0)
2439 return (raiseDiv0("quotRemInteger"));
2440 do_qrm(x,y,n,IntegerInsideByteArray(q),
2441 IntegerInsideByteArray(r));
2442 SloppifyIntegerEnd(q);
2443 SloppifyIntegerEnd(r);
2448 case i_intToInteger:
2450 int n = size_fromInt();
2451 StgPtr p = CreateByteArrayToHoldInteger(n);
2452 do_fromInt( PopTaggedInt(), n, IntegerInsideByteArray(p));
2456 case i_wordToInteger:
2458 int n = size_fromWord();
2459 StgPtr p = CreateByteArrayToHoldInteger(n);
2460 do_fromWord( PopTaggedWord(), n, IntegerInsideByteArray(p));
2464 case i_integerToInt: PushTaggedInt(do_toInt(
2465 IntegerInsideByteArray(PopPtr())
2469 case i_integerToWord: PushTaggedWord(do_toWord(
2470 IntegerInsideByteArray(PopPtr())
2474 case i_integerToFloat: PushTaggedFloat(do_toFloat(
2475 IntegerInsideByteArray(PopPtr())
2479 case i_integerToDouble: PushTaggedDouble(do_toDouble(
2480 IntegerInsideByteArray(PopPtr())
2484 #error Non-standalone integer not yet implemented
2485 #endif /* STANDALONE_INTEGER */
2487 case i_gtFloat: OP_FF_B(x>y); break;
2488 case i_geFloat: OP_FF_B(x>=y); break;
2489 case i_eqFloat: OP_FF_B(x==y); break;
2490 case i_neFloat: OP_FF_B(x!=y); break;
2491 case i_ltFloat: OP_FF_B(x<y); break;
2492 case i_leFloat: OP_FF_B(x<=y); break;
2493 case i_minFloat: OP__F(FLT_MIN); break;
2494 case i_maxFloat: OP__F(FLT_MAX); break;
2495 case i_radixFloat: OP__I(FLT_RADIX); break;
2496 case i_digitsFloat: OP__I(FLT_MANT_DIG); break;
2497 case i_minExpFloat: OP__I(FLT_MIN_EXP); break;
2498 case i_maxExpFloat: OP__I(FLT_MAX_EXP); break;
2499 case i_plusFloat: OP_FF_F(x+y); break;
2500 case i_minusFloat: OP_FF_F(x-y); break;
2501 case i_timesFloat: OP_FF_F(x*y); break;
2504 StgFloat x = PopTaggedFloat();
2505 StgFloat y = PopTaggedFloat();
2506 PushTaggedFloat(x/y);
2509 case i_negateFloat: OP_F_F(-x); break;
2510 case i_floatToInt: OP_F_I(x); break;
2511 case i_intToFloat: OP_I_F(x); break;
2512 case i_expFloat: OP_F_F(exp(x)); break;
2513 case i_logFloat: OP_F_F(log(x)); break;
2514 case i_sqrtFloat: OP_F_F(sqrt(x)); break;
2515 case i_sinFloat: OP_F_F(sin(x)); break;
2516 case i_cosFloat: OP_F_F(cos(x)); break;
2517 case i_tanFloat: OP_F_F(tan(x)); break;
2518 case i_asinFloat: OP_F_F(asin(x)); break;
2519 case i_acosFloat: OP_F_F(acos(x)); break;
2520 case i_atanFloat: OP_F_F(atan(x)); break;
2521 case i_sinhFloat: OP_F_F(sinh(x)); break;
2522 case i_coshFloat: OP_F_F(cosh(x)); break;
2523 case i_tanhFloat: OP_F_F(tanh(x)); break;
2524 case i_powerFloat: OP_FF_F(pow(x,y)); break;
2526 #ifdef STANDALONE_INTEGER
2527 case i_encodeFloatZ:
2529 StgPtr sig = PopPtr();
2530 StgInt exp = PopTaggedInt();
2532 B__encodeFloat(IntegerInsideByteArray(sig), exp)
2536 case i_decodeFloatZ:
2538 StgFloat f = PopTaggedFloat();
2539 StgPtr sig = CreateByteArrayToHoldInteger(size_fltmantissa());
2541 B__decodeFloat(IntegerInsideByteArray(sig), &exp, f);
2547 #error encode/decodeFloatZ not yet implemented for GHC ints
2549 case i_isNaNFloat: OP_F_B(isFloatNaN(x)); break;
2550 case i_isInfiniteFloat: OP_F_B(isFloatInfinite(x)); break;
2551 case i_isNegativeZeroFloat: OP_F_B(isFloatNegativeZero(x)); break;
2552 case i_isDenormalizedFloat: OP_F_B(isFloatDenormalized(x)); break;
2553 case i_gtDouble: OP_DD_B(x>y); break;
2554 case i_geDouble: OP_DD_B(x>=y); break;
2555 case i_eqDouble: OP_DD_B(x==y); break;
2556 case i_neDouble: OP_DD_B(x!=y); break;
2557 case i_ltDouble: OP_DD_B(x<y); break;
2558 case i_leDouble: OP_DD_B(x<=y) break;
2559 case i_minDouble: OP__D(DBL_MIN); break;
2560 case i_maxDouble: OP__D(DBL_MAX); break;
2561 case i_radixDouble: OP__I(FLT_RADIX); break;
2562 case i_digitsDouble: OP__I(DBL_MANT_DIG); break;
2563 case i_minExpDouble: OP__I(DBL_MIN_EXP); break;
2564 case i_maxExpDouble: OP__I(DBL_MAX_EXP); break;
2565 case i_plusDouble: OP_DD_D(x+y); break;
2566 case i_minusDouble: OP_DD_D(x-y); break;
2567 case i_timesDouble: OP_DD_D(x*y); break;
2568 case i_divideDouble:
2570 StgDouble x = PopTaggedDouble();
2571 StgDouble y = PopTaggedDouble();
2572 PushTaggedDouble(x/y);
2575 case i_negateDouble: OP_D_D(-x); break;
2576 case i_doubleToInt: OP_D_I(x); break;
2577 case i_intToDouble: OP_I_D(x); break;
2578 case i_doubleToFloat: OP_D_F(x); break;
2579 case i_floatToDouble: OP_F_F(x); break;
2580 case i_expDouble: OP_D_D(exp(x)); break;
2581 case i_logDouble: OP_D_D(log(x)); break;
2582 case i_sqrtDouble: OP_D_D(sqrt(x)); break;
2583 case i_sinDouble: OP_D_D(sin(x)); break;
2584 case i_cosDouble: OP_D_D(cos(x)); break;
2585 case i_tanDouble: OP_D_D(tan(x)); break;
2586 case i_asinDouble: OP_D_D(asin(x)); break;
2587 case i_acosDouble: OP_D_D(acos(x)); break;
2588 case i_atanDouble: OP_D_D(atan(x)); break;
2589 case i_sinhDouble: OP_D_D(sinh(x)); break;
2590 case i_coshDouble: OP_D_D(cosh(x)); break;
2591 case i_tanhDouble: OP_D_D(tanh(x)); break;
2592 case i_powerDouble: OP_DD_D(pow(x,y)); break;
2594 #ifdef STANDALONE_INTEGER
2595 case i_encodeDoubleZ:
2597 StgPtr sig = PopPtr();
2598 StgInt exp = PopTaggedInt();
2600 B__encodeDouble(IntegerInsideByteArray(sig), exp)
2604 case i_decodeDoubleZ:
2606 StgDouble d = PopTaggedDouble();
2607 StgPtr sig = CreateByteArrayToHoldInteger(size_dblmantissa());
2609 B__decodeDouble(IntegerInsideByteArray(sig), &exp, d);
2615 #error encode/decodeDoubleZ not yet implemented for GHC ints
2617 case i_isNaNDouble: OP_D_B(isDoubleNaN(x)); break;
2618 case i_isInfiniteDouble: OP_D_B(isDoubleInfinite(x)); break;
2619 case i_isNegativeZeroDouble: OP_D_B(isDoubleNegativeZero(x)); break;
2620 case i_isDenormalizedDouble: OP_D_B(isDoubleDenormalized(x)); break;
2621 case i_isIEEEDouble:
2623 PushTaggedBool(rtsTrue);
2627 barf("Unrecognised primop1");
2634 /* For normal cases, return NULL and leave *return2 unchanged.
2635 To return the address of the next thing to enter,
2636 return the address of it and leave *return2 unchanged.
2637 To return a StgThreadReturnCode to the scheduler,
2638 set *return2 to it and return a non-NULL value.
2640 static void* enterBCO_primop2 ( int primop2code,
2641 int* /*StgThreadReturnCode* */ return2,
2645 switch (primop2code) {
2646 case i_raise: /* raise#{err} */
2648 StgClosure* err = PopCPtr();
2649 return (raiseAnError(err));
2654 StgClosure* init = PopCPtr();
2656 = stgCast(StgMutVar*,allocate(sizeofW(StgMutVar)));
2657 SET_HDR(mv,&MUT_VAR_info,CCCS);
2659 PushPtr(stgCast(StgPtr,mv));
2664 StgMutVar* mv = stgCast(StgMutVar*,PopPtr());
2670 StgMutVar* mv = stgCast(StgMutVar*,PopPtr());
2671 StgClosure* value = PopCPtr();
2677 nat n = PopTaggedInt(); /* or Word?? */
2678 StgClosure* init = PopCPtr();
2679 StgWord size = sizeofW(StgMutArrPtrs) + n;
2682 = stgCast(StgMutArrPtrs*,allocate(size));
2683 SET_HDR(arr,&MUT_ARR_PTRS_info,CCCS);
2685 for (i = 0; i < n; ++i) {
2686 arr->payload[i] = init;
2688 PushPtr(stgCast(StgPtr,arr));
2694 StgMutArrPtrs* arr = stgCast(StgMutArrPtrs*,PopPtr());
2695 nat i = PopTaggedInt(); /* or Word?? */
2696 StgWord n = arr->ptrs;
2698 return (raiseIndex("{index,read}Array"));
2700 PushCPtr(arr->payload[i]);
2705 StgMutArrPtrs* arr = stgCast(StgMutArrPtrs*,PopPtr());
2706 nat i = PopTaggedInt(); /* or Word? */
2707 StgClosure* v = PopCPtr();
2708 StgWord n = arr->ptrs;
2710 return (raiseIndex("{index,read}Array"));
2712 arr->payload[i] = v;
2716 case i_sizeMutableArray:
2718 StgMutArrPtrs* arr = stgCast(StgMutArrPtrs*,PopPtr());
2719 PushTaggedInt(arr->ptrs);
2722 case i_unsafeFreezeArray:
2724 StgMutArrPtrs* arr = stgCast(StgMutArrPtrs*,PopPtr());
2725 SET_INFO(arr,&MUT_ARR_PTRS_FROZEN_info);
2726 PushPtr(stgCast(StgPtr,arr));
2729 case i_unsafeFreezeByteArray:
2731 /* Delightfully simple :-) */
2735 case i_sameMutableArray:
2736 case i_sameMutableByteArray:
2738 StgPtr x = PopPtr();
2739 StgPtr y = PopPtr();
2740 PushTaggedBool(x==y);
2744 case i_newByteArray:
2746 nat n = PopTaggedInt(); /* or Word?? */
2747 StgInt words = (n+sizeof(W_)-1)/sizeof(W_);
2748 StgWord size = sizeofW(StgArrWords) + words;
2749 StgArrWords* arr = stgCast(StgArrWords*,allocate(size));
2750 SET_HDR(arr,&ARR_WORDS_info,CCCS);
2754 for (i = 0; i < n; ++i) {
2755 arr->payload[i] = 0xdeadbeef;
2758 PushPtr(stgCast(StgPtr,arr));
2762 /* Most of these generate alignment warnings on gSparcs and similar architectures.
2763 * These are harmless and are caused by the cast to C* in BYTE_ARR_CTS.
2765 case i_indexCharArray:
2766 OP_mI_ty(Char,"indexCharArray", indexCharArrayzh(r,x,i)); break;
2767 case i_readCharArray:
2768 OP_mI_ty(Char,"readCharArray", readCharArrayzh(r,x,i)); break;
2769 case i_writeCharArray:
2770 OP_mIty_(Char,"writeCharArray", writeCharArrayzh(x,i,z)); break;
2772 case i_indexIntArray:
2773 OP_mI_ty(Int,"indexIntArray", indexIntArrayzh(r,x,i)); break;
2774 case i_readIntArray:
2775 OP_mI_ty(Int,"readIntArray", readIntArrayzh(r,x,i)); break;
2776 case i_writeIntArray:
2777 OP_mIty_(Int,"writeIntArray", writeIntArrayzh(x,i,z)); break;
2779 case i_indexAddrArray:
2780 OP_mI_ty(Addr,"indexAddrArray", indexAddrArrayzh(r,x,i)); break;
2781 case i_readAddrArray:
2782 OP_mI_ty(Addr,"readAddrArray", readAddrArrayzh(r,x,i)); break;
2783 case i_writeAddrArray:
2784 OP_mIty_(Addr,"writeAddrArray", writeAddrArrayzh(x,i,z)); break;
2786 case i_indexFloatArray:
2787 OP_mI_ty(Float,"indexFloatArray", indexFloatArrayzh(r,x,i)); break;
2788 case i_readFloatArray:
2789 OP_mI_ty(Float,"readFloatArray", readFloatArrayzh(r,x,i)); break;
2790 case i_writeFloatArray:
2791 OP_mIty_(Float,"writeFloatArray", writeFloatArrayzh(x,i,z)); break;
2793 case i_indexDoubleArray:
2794 OP_mI_ty(Double,"indexDoubleArray", indexDoubleArrayzh(r,x,i)); break;
2795 case i_readDoubleArray:
2796 OP_mI_ty(Double,"readDoubleArray", readDoubleArrayzh(r,x,i)); break;
2797 case i_writeDoubleArray:
2798 OP_mIty_(Double,"writeDoubleArray", writeDoubleArrayzh(x,i,z)); break;
2801 #ifdef PROVIDE_STABLE
2802 case i_indexStableArray:
2803 OP_mI_ty(StablePtr,"indexStableArray", indexStablePtrArrayzh(r,x,i)); break;
2804 case i_readStableArray:
2805 OP_mI_ty(StablePtr,"readStableArray", readStablePtrArrayzh(r,x,i)); break;
2806 case i_writeStableArray:
2807 OP_mIty_(StablePtr,"writeStableArray", writeStablePtrArrayzh(x,i,z)); break;
2813 #ifdef PROVIDE_COERCE
2814 case i_unsafeCoerce:
2816 /* Another nullop */
2820 #ifdef PROVIDE_PTREQUALITY
2821 case i_reallyUnsafePtrEquality:
2822 { /* identical to i_sameRef */
2823 StgPtr x = PopPtr();
2824 StgPtr y = PopPtr();
2825 PushTaggedBool(x==y);
2829 #ifdef PROVIDE_FOREIGN
2830 /* ForeignObj# operations */
2831 case i_makeForeignObj:
2833 StgForeignObj *result
2834 = stgCast(StgForeignObj*,allocate(sizeofW(StgForeignObj)));
2835 SET_HDR(result,&FOREIGN_info,CCCS);
2836 result -> data = PopTaggedAddr();
2837 PushPtr(stgCast(StgPtr,result));
2840 #endif /* PROVIDE_FOREIGN */
2845 = stgCast(StgWeak*,allocate(sizeofW(StgWeak)));
2846 SET_HDR(w, &WEAK_info, CCCS);
2848 w->value = PopCPtr();
2849 w->finaliser = PopCPtr();
2850 w->link = weak_ptr_list;
2852 IF_DEBUG(weak, fprintf(stderr,"New weak pointer at %p\n",w));
2853 PushPtr(stgCast(StgPtr,w));
2858 StgWeak *w = stgCast(StgWeak*,PopPtr());
2859 if (w->header.info == &WEAK_info) {
2860 PushCPtr(w->value); /* last result */
2861 PushTaggedInt(1); /* first result */
2863 PushPtr(stgCast(StgPtr,w));
2864 /* ToDo: error thunk would be better */
2869 #endif /* PROVIDE_WEAK */
2871 case i_makeStablePtr:
2873 StgPtr p = PopPtr();
2874 StgStablePtr sp = getStablePtr ( p );
2875 PushTaggedStablePtr(sp);
2878 case i_deRefStablePtr:
2881 StgStablePtr sp = PopTaggedStablePtr();
2882 p = deRefStablePtr(sp);
2886 case i_freeStablePtr:
2888 StgStablePtr sp = PopTaggedStablePtr();
2893 case i_createAdjThunkARCH:
2895 StgStablePtr stableptr = PopTaggedStablePtr();
2896 StgAddr typestr = PopTaggedAddr();
2897 StgChar callconv = PopTaggedChar();
2898 StgAddr adj_thunk = createAdjThunk(stableptr,typestr,callconv);
2899 PushTaggedAddr(adj_thunk);
2905 StgInt n = prog_argc;
2911 StgInt n = PopTaggedInt();
2912 StgAddr a = (StgAddr)prog_argv[n];
2917 #ifdef PROVIDE_CONCURRENT
2920 StgClosure* c = PopCPtr();
2921 StgTSO* t = createGenThread(RtsFlags.GcFlags.initialStkSize,c);
2922 PushPtr(stgCast(StgPtr,t));
2924 /* switch at the earliest opportunity */
2926 /* but don't automatically switch to GHC - or you'll waste your
2927 * time slice switching back.
2929 * Actually, there's more to it than that: the default
2930 * (ThreadEnterGHC) causes the thread to crash - don't
2931 * understand why. - ADR
2933 t->whatNext = ThreadEnterHugs;
2938 StgTSO* tso = stgCast(StgTSO*,PopPtr());
2940 if (tso == cap->rCurrentTSO) { /* suicide */
2941 *return2 = ThreadFinished;
2942 return (void*)(1+(NULL));
2947 { /* identical to i_sameRef */
2948 StgPtr x = PopPtr();
2949 StgPtr y = PopPtr();
2950 PushTaggedBool(x==y);
2955 StgMVar *mvar = stgCast(StgMVar*,allocate(sizeofW(StgMVar)));
2956 SET_INFO(mvar,&EMPTY_MVAR_info);
2957 mvar->head = mvar->tail = EndTSOQueue;
2958 /* ToDo: this is a little strange */
2959 mvar->value = stgCast(StgClosure*,&END_TSO_QUEUE_closure);
2960 PushPtr(stgCast(StgPtr,mvar));
2965 ToDo: another way out of the problem might be to add an explicit
2966 continuation to primTakeMVar: takeMVar v = primTakeMVar v takeMVar.
2967 The problem with this plan is that now I dont know how much to chop
2972 StgMVar *mvar = stgCast(StgMVar*,PopPtr());
2973 /* If the MVar is empty, put ourselves
2974 * on its blocking queue, and wait
2975 * until we're woken up.
2977 if (GET_INFO(mvar) != &FULL_MVAR_info) {
2978 if (mvar->head == EndTSOQueue) {
2979 mvar->head = cap->rCurrentTSO;
2981 mvar->tail->link = cap->rCurrentTSO;
2983 cap->rCurrentTSO->link = EndTSOQueue;
2984 mvar->tail = cap->rCurrentTSO;
2986 /* Hack, hack, hack.
2987 * When we block, we push a restart closure
2988 * on the stack - but which closure?
2989 * We happen to know that the BCO we're
2990 * executing looks like this:
2999 * 14: ALLOC_CONSTR 0x8213a80
3009 * so we rearrange the stack to look the
3010 * way it did when we entered this BCO
3012 * What a disgusting hack!
3018 *return2 = ThreadBlocked;
3019 return (void*)(1+(NULL));
3022 PushCPtr(mvar->value);
3023 SET_INFO(mvar,&EMPTY_MVAR_info);
3024 /* ToDo: this is a little strange */
3025 mvar->value = (StgClosure*)&END_TSO_QUEUE_closure;
3032 StgMVar* mvar = stgCast(StgMVar*,PopPtr());
3033 StgClosure* value = PopCPtr();
3034 if (GET_INFO(mvar) == &FULL_MVAR_info) {
3035 return (raisePrim("putMVar {full MVar}"));
3037 /* wake up the first thread on the
3038 * queue, it will continue with the
3039 * takeMVar operation and mark the
3042 StgTSO* tso = mvar->head;
3043 SET_INFO(mvar,&FULL_MVAR_info);
3044 mvar->value = value;
3045 if (tso != EndTSOQueue) {
3046 PUSH_ON_RUN_QUEUE(tso);
3047 mvar->head = tso->link;
3048 tso->link = EndTSOQueue;
3049 if (mvar->head == EndTSOQueue) {
3050 mvar->tail = EndTSOQueue;
3054 /* yield for better communication performance */
3061 /* As PrimOps.h says: Hmm, I'll think about these later. */
3064 #endif /* PROVIDE_CONCURRENT */
3065 case i_ccall_ccall_Id:
3066 case i_ccall_ccall_IO:
3067 case i_ccall_stdcall_Id:
3068 case i_ccall_stdcall_IO:
3071 CFunDescriptor* descriptor = PopTaggedAddr();
3072 void (*funPtr)(void) = PopTaggedAddr();
3073 char cc = (primop2code == i_ccall_stdcall_Id ||
3074 primop2code == i_ccall_stdcall_IO)
3076 r = ccall(descriptor,funPtr,bco,cc,cap);
3079 return makeErrorCall(
3080 "unhandled type or too many args/results in ccall");
3082 barf("ccall not configured correctly for this platform");
3083 barf("unknown return code from ccall");
3086 barf("Unrecognised primop2");
3092 /* -----------------------------------------------------------------------------
3093 * ccall support code:
3094 * marshall moves args from C stack to Haskell stack
3095 * unmarshall moves args from Haskell stack to C stack
3096 * argSize calculates how much gSpace you need on the C stack
3097 * ---------------------------------------------------------------------------*/
3099 /* Pop arguments off the C stack and Push them onto the Hugs stack.
3100 * Used when preparing for C calling Haskell or in regSponse to
3101 * Haskell calling C.
3103 nat marshall(char arg_ty, void* arg)
3107 PushTaggedInt(*((int*)arg));
3108 return ARG_SIZE(INT_TAG);
3109 #ifdef TODO_STANDALONE_INTEGER
3111 PushTaggedInteger(*((mpz_ptr*)arg));
3112 return ARG_SIZE(INTEGER_TAG);
3115 PushTaggedWord(*((unsigned int*)arg));
3116 return ARG_SIZE(WORD_TAG);
3118 PushTaggedChar(*((char*)arg));
3119 return ARG_SIZE(CHAR_TAG);
3121 PushTaggedFloat(*((float*)arg));
3122 return ARG_SIZE(FLOAT_TAG);
3124 PushTaggedDouble(*((double*)arg));
3125 return ARG_SIZE(DOUBLE_TAG);
3127 PushTaggedAddr(*((void**)arg));
3128 return ARG_SIZE(ADDR_TAG);
3130 PushTaggedStablePtr(*((StgStablePtr*)arg));
3131 return ARG_SIZE(STABLE_TAG);
3132 #ifdef PROVIDE_FOREIGN
3134 /* Not allowed in this direction - you have to
3135 * call makeForeignPtr explicitly
3137 barf("marshall: ForeignPtr#\n");
3142 /* Not allowed in this direction */
3143 barf("marshall: [Mutable]ByteArray#\n");
3146 barf("marshall: unrecognised arg type %d\n",arg_ty);
3151 /* Pop arguments off the Hugs stack and Push them onto the C stack.
3152 * Used when preparing for Haskell calling C or in regSponse to
3153 * C calling Haskell.
3155 nat unmarshall(char res_ty, void* res)
3159 *((int*)res) = PopTaggedInt();
3160 return ARG_SIZE(INT_TAG);
3161 #ifdef TODO_STANDALONE_INTEGER
3163 *((mpz_ptr*)res) = PopTaggedInteger();
3164 return ARG_SIZE(INTEGER_TAG);
3167 *((unsigned int*)res) = PopTaggedWord();
3168 return ARG_SIZE(WORD_TAG);
3170 *((int*)res) = PopTaggedChar();
3171 return ARG_SIZE(CHAR_TAG);
3173 *((float*)res) = PopTaggedFloat();
3174 return ARG_SIZE(FLOAT_TAG);
3176 *((double*)res) = PopTaggedDouble();
3177 return ARG_SIZE(DOUBLE_TAG);
3179 *((void**)res) = PopTaggedAddr();
3180 return ARG_SIZE(ADDR_TAG);
3182 *((StgStablePtr*)res) = PopTaggedStablePtr();
3183 return ARG_SIZE(STABLE_TAG);
3184 #ifdef PROVIDE_FOREIGN
3187 StgForeignObj *result = stgCast(StgForeignObj*,PopPtr());
3188 *((void**)res) = result->data;
3189 return sizeofW(StgPtr);
3195 StgMutArrPtrs* arr = stgCast(StgMutArrPtrs*,PopPtr());
3196 *((void**)res) = stgCast(void*,&(arr->payload));
3197 return sizeofW(StgPtr);
3200 barf("unmarshall: unrecognised result type %d\n",res_ty);
3204 nat argSize( const char* ks )
3207 for( ; *ks != '\0'; ++ks) {
3210 sz += sizeof(StgWord) * ARG_SIZE(INT_TAG);
3212 #ifdef TODO_STANDALONE_INTEGER
3214 sz += sizeof(StgWord) * ARG_SIZE(INTEGER_TAG);
3218 sz += sizeof(StgWord) * ARG_SIZE(WORD_TAG);
3221 sz += sizeof(StgWord) * ARG_SIZE(CHAR_TAG);
3224 sz += sizeof(StgWord) * ARG_SIZE(FLOAT_TAG);
3227 sz += sizeof(StgWord) * ARG_SIZE(DOUBLE_TAG);
3230 sz += sizeof(StgWord) * ARG_SIZE(ADDR_TAG);
3233 sz += sizeof(StgWord) * ARG_SIZE(STABLE_TAG);
3235 #ifdef PROVIDE_FOREIGN
3240 sz += sizeof(StgPtr);
3243 barf("argSize: unrecognised result type %d\n",*ks);
3251 /* -----------------------------------------------------------------------------
3252 * encode/decode Float/Double code for standalone Hugs
3253 * Code based on the HBC code (lib/fltcode.c) and more recently GHC
3254 * (ghc/rts/StgPrimFloat.c)
3255 * ---------------------------------------------------------------------------*/
3257 #ifdef STANDALONE_INTEGER
3259 #if IEEE_FLOATING_POINT
3260 #define MY_DMINEXP ((DBL_MIN_EXP) - (DBL_MANT_DIG) - 1)
3261 /* DMINEXP is defined in values.h on Linux (for example) */
3262 #define DHIGHBIT 0x00100000
3263 #define DMSBIT 0x80000000
3265 #define MY_FMINEXP ((FLT_MIN_EXP) - (FLT_MANT_DIG) - 1)
3266 #define FHIGHBIT 0x00800000
3267 #define FMSBIT 0x80000000
3269 #error The following code doesnt work in a non-IEEE FP environment
3272 #ifdef WORDS_BIGENDIAN
3281 StgDouble B__encodeDouble (B* s, I_ e) /* result = s * 2^e */
3286 /* Convert a B to a double; knows a lot about internal rep! */
3287 for(r = 0.0, i = s->used-1; i >= 0; i--)
3288 r = (r * B_BASE_FLT) + s->stuff[i];
3290 /* Now raise to the exponent */
3291 if ( r != 0.0 ) /* Lennart suggests this avoids a bug in MIPS's ldexp */
3294 /* handle the sign */
3295 if (s->sign < 0) r = -r;
3302 #if ! FLOATS_AS_DOUBLES
3303 StgFloat B__encodeFloat (B* s, I_ e) /* result = s * 2^e */
3308 /* Convert a B to a float; knows a lot about internal rep! */
3309 for(r = 0.0, i = s->used-1; i >= 0; i--)
3310 r = (r * B_BASE_FLT) + s->stuff[i];
3312 /* Now raise to the exponent */
3313 if ( r != 0.0 ) /* Lennart suggests this avoids a bug in MIPS's ldexp */
3316 /* handle the sign */
3317 if (s->sign < 0) r = -r;
3321 #endif /* FLOATS_AS_DOUBLES */
3325 /* This only supports IEEE floating point */
3326 void B__decodeDouble (B* man, I_* exp, StgDouble dbl)
3328 /* Do some bit fiddling on IEEE */
3329 nat low, high; /* assuming 32 bit ints */
3331 union { double d; int i[2]; } u; /* assuming 32 bit ints, 64 bit double */
3333 u.d = dbl; /* grab chunks of the double */
3337 ASSERT(B_BASE == 256);
3339 /* Assume that the supplied B is the right size */
3342 if (low == 0 && (high & ~DMSBIT) == 0) {
3343 man->sign = man->used = 0;
3348 iexp = ((high >> 20) & 0x7ff) + MY_DMINEXP;
3352 if (iexp != MY_DMINEXP) /* don't add hidden bit to denorms */
3356 /* A denorm, normalize the mantissa */
3357 while (! (high & DHIGHBIT)) {
3367 man->stuff[7] = (((W_)high) >> 24) & 0xff;
3368 man->stuff[6] = (((W_)high) >> 16) & 0xff;
3369 man->stuff[5] = (((W_)high) >> 8) & 0xff;
3370 man->stuff[4] = (((W_)high) ) & 0xff;
3372 man->stuff[3] = (((W_)low) >> 24) & 0xff;
3373 man->stuff[2] = (((W_)low) >> 16) & 0xff;
3374 man->stuff[1] = (((W_)low) >> 8) & 0xff;
3375 man->stuff[0] = (((W_)low) ) & 0xff;
3377 if (sign < 0) man->sign = -1;
3379 do_renormalise(man);
3383 #if ! FLOATS_AS_DOUBLES
3384 void B__decodeFloat (B* man, I_* exp, StgFloat flt)
3386 /* Do some bit fiddling on IEEE */
3387 int high, sign; /* assuming 32 bit ints */
3388 union { float f; int i; } u; /* assuming 32 bit float and int */
3390 u.f = flt; /* grab the float */
3393 ASSERT(B_BASE == 256);
3395 /* Assume that the supplied B is the right size */
3398 if ((high & ~FMSBIT) == 0) {
3399 man->sign = man->used = 0;
3404 *exp = ((high >> 23) & 0xff) + MY_FMINEXP;
3408 if (*exp != MY_FMINEXP) /* don't add hidden bit to denorms */
3412 /* A denorm, normalize the mantissa */
3413 while (! (high & FHIGHBIT)) {
3418 man->stuff[3] = (((W_)high) >> 24) & 0xff;
3419 man->stuff[2] = (((W_)high) >> 16) & 0xff;
3420 man->stuff[1] = (((W_)high) >> 8) & 0xff;
3421 man->stuff[0] = (((W_)high) ) & 0xff;
3423 if (sign < 0) man->sign = -1;
3425 do_renormalise(man);
3428 #endif /* FLOATS_AS_DOUBLES */
3430 #endif /* STANDALONE_INTEGER */
3432 #endif /* INTERPRETER */