X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FStgCRun.c;h=129cd23c520922c1d4ffad736db7d308a0e8b785;hb=fb69fc467fd1c05d29bff65f8bf5ce74a0052982;hp=71cdf06e32e586d61cd5b1b0dc446903cc52c9db;hpb=35dd3bb2d113ed6317d0bdc25b8655b59478fec7;p=ghc-hetmet.git diff --git a/ghc/rts/StgCRun.c b/ghc/rts/StgCRun.c index 71cdf06..129cd23 100644 --- a/ghc/rts/StgCRun.c +++ b/ghc/rts/StgCRun.c @@ -1,10 +1,35 @@ /* ----------------------------------------------------------------------------- - * $Id: StgCRun.c,v 1.8 1999/11/03 15:00:21 simonmar Exp $ + * $Id: StgCRun.c,v 1.22 2000/11/13 14:53:27 simonmar Exp $ * - * (c) The GHC Team, 1998-1999 + * (c) The GHC Team, 1998-2000 * - * STG-to-C glue. Some architectures have this code written in - * straight assembler (see StgRun.S), some in C. + * STG-to-C glue. + * + * To run an STG function from C land, call + * + * rv = StgRun(f,BaseReg); + * + * where "f" is the STG function to call, and BaseReg is the address of the + * RegTable for this run (we might have separate RegTables if we're running + * multiple threads on an SMP machine). + * + * In the end, "f" must JMP to StgReturn (defined below), + * passing the return-value "rv" in R1, + * to return to the caller of StgRun returning "rv" in + * the whatever way C returns a value. + * + * NOTE: StgRun/StgReturn do *NOT* load or store Hp or any + * other registers (other than saving the C callee-saves + * registers). Instead, the called function "f" must do that + * in STG land. + * + * GCC will have assumed that pushing/popping of C-stack frames is + * going on when it generated its code, and used stack space + * accordingly. However, we actually {\em post-process away} all + * such stack-framery (see \tr{ghc/driver/ghc-asm.lprl}). Things will + * be OK however, if we initially make sure there are + * @RESERVED_C_STACK_BYTES@ on the C-stack to begin with, for local + * variables. * * -------------------------------------------------------------------------- */ @@ -38,63 +63,153 @@ static jmp_buf jmp_environment; -#if 0 +#if 1 extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg) { - jmp_buf save_buf; - /* Save jmp_environment for previous call to miniInterpret */ - memcpy((void *) jmp_environment, (void *) save_buf, sizeof(jmp_buf)); - if (setjmp(jmp_environment) == 0) { - while ( 1 ) { - IF_DEBUG(evaluator, - fprintf(stderr,"Jumping to "); - printPtr((P_)f); - fprintf(stderr,"\n"); - ); - f = (StgFunPtr) (f)(); - } - } - /* Restore jmp_environment for previous call */ - memcpy((void*) save_buf, (void*) jmp_environment, sizeof(jmp_buf)); - - return (StgThreadReturnCode)R1.i; + while (f) { + IF_DEBUG(evaluator, + fprintf(stderr,"Jumping to "); + printPtr((P_)f); + fprintf(stderr,"\n"); + ); + f = (StgFunPtr) (f)(); + } + return (StgThreadReturnCode)R1.i; } EXTFUN(StgReturn) { - longjmp(jmp_environment, 1); + return 0; } #else +#define CHECK_STACK 0 +#define STACK_DETAILS 0 + +static int enters = 0; + +static void scanStackSeg ( W_* ptr, int nwords ) +{ + W_ w; +#if CHECK_STACK + int nwords0 = nwords; +#if STACK_DETAILS + while (nwords > 0) { + w = *ptr; + if (IS_ARG_TAG(w)) { + fprintf ( stderr, "%d",w ); nwords--; ptr++; + while (w) { fprintf(stderr, "_"); w--; nwords--; ptr++; } + } + else { + fprintf(stderr, "p"); + nwords--; ptr++; + } + } + if (nwords < 0) fprintf(stderr, "erk: nwords < 0\n"); +#endif + checkStackChunk ( ptr, ptr-nwords0 ); +#endif +} + +extern StgFunPtr stg_enterStackTop; extern StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg) { char* nm; - while ( f ) { + while (1) { -#if 0 - //IF_DEBUG(evaluator, - fprintf(stderr,"Jumping to "); - nm = nameOfObjSym ( f ); - if (nm) - fprintf(stderr, "%s (%p)", nm, f); else - printPtr((P_)f); - fprintf(stderr,"\n"); - // ); -if (0&& MainRegTable.rSp) { +#if CHECK_STACK + { int i; - StgWord* p = MainRegTable.rSp; -fprintf(stderr, "SP = %p\n", p); - p += (8-1); - for (i = 0; i < 8; i++, p--) - fprintf (stderr, "-- %p: %p\n", p, *p ); -} -#endif + StgTSO* tso = basereg->rCurrentTSO; + StgWord* sb = tso->stack + tso->stack_size; + StgWord* sp; + StgWord* su; + int ws; + + if (f == &stg_enterStackTop) { + sp = tso->sp; + su = tso->su; + } else { + sp = basereg->rSp; + su = basereg->rSu; + } + +#if STACK_DETAILS + fprintf(stderr, + "== SB = %p SP = %p(%p) SU = %p SpLim = %p(%p)\n", + sb, sp, tso->sp, su, basereg->rSpLim, tso->stack + RESERVED_STACK_WORDS); +#endif + + if (su >= sb) goto postloop; + if (!sp || !su) goto postloop; + + printStack ( sp, sb, su); + while (1) { + ws = su - sp; + switch (get_itbl((StgClosure*)su)->type) { + case STOP_FRAME: + scanStackSeg(sp,ws); +#if STACK_DETAILS + fprintf(stderr, "S%d ",ws); + fprintf(stderr, "\n"); +#endif + goto postloop; + case UPDATE_FRAME: + scanStackSeg(sp,ws); +#if STACK_DETAILS + fprintf(stderr,"U%d ",ws); +#endif + sp = su + sizeofW(StgUpdateFrame); + su = ((StgUpdateFrame*)su)->link; + break; + case SEQ_FRAME: + scanStackSeg(sp,ws); +#if STACK_DETAILS + fprintf(stderr,"Q%d ",ws); +#endif + sp = su + sizeofW(StgSeqFrame); + su = ((StgSeqFrame*)su)->link; + break; + case CATCH_FRAME: + scanStackSeg(sp,ws); +#if STACK_DETAILS + fprintf(stderr,"C%d ",ws); +#endif + sp = su + sizeofW(StgCatchFrame); + su = ((StgCatchFrame*)su)->link; + break; + default: + fprintf(stderr, "?\nweird record on stack\n"); + assert(0); + goto postloop; + } + } + postloop: + } +#endif +#if STACK_DETAILS + fprintf(stderr,"\n"); +#endif +#if 1 + fprintf(stderr,"-- enter %p ", f); + nm = nameFromOPtr ( f ); + if (nm) fprintf(stderr, "%s", nm); else + printPtr((P_)f); + fprintf ( stderr, "\n"); +#endif +#if STACK_DETAILS + fprintf(stderr,"\n"); +#endif + zzz: + if (enters % 1000 == 0) fprintf(stderr, "%d enters\n",enters); + enters++; f = (StgFunPtr) (f)(); + if (!f) break; } - + fprintf (stderr, "miniInterpreter: bye!\n\n" ); return (StgThreadReturnCode)R1.i; } @@ -115,7 +230,91 @@ EXTFUN(StgReturn) #endif /* ----------------------------------------------------------------------------- - sparc architecture + x86 architecture + -------------------------------------------------------------------------- */ + +#ifdef i386_TARGET_ARCH + +StgThreadReturnCode +StgRun(StgFunPtr f, StgRegTable *basereg) { + + unsigned char space[ RESERVED_C_STACK_BYTES + 4*sizeof(void *) ]; + StgThreadReturnCode r; + + __asm__ volatile ( + /* + * save callee-saves registers on behalf of the STG code. + */ + "movl %%esp, %%eax\n\t" + "addl %4, %%eax\n\t" + "movl %%ebx,0(%%eax)\n\t" + "movl %%esi,4(%%eax)\n\t" + "movl %%edi,8(%%eax)\n\t" + "movl %%ebp,12(%%eax)\n\t" + /* + * Set BaseReg + */ + "movl %3,%%ebx\n\t" + /* + * grab the function argument from the stack, and jump to it. + */ + "movl %2,%%eax\n\t" + "jmp *%%eax\n\t" + + ".global " STG_RETURN "\n" + STG_RETURN ":\n\t" + + "movl %%esi, %%eax\n\t" /* Return value in R1 */ + + /* + * restore callee-saves registers. (Don't stomp on %%eax!) + */ + "movl %%esp, %%edx\n\t" + "addl %4, %%edx\n\t" + "movl 0(%%edx),%%ebx\n\t" /* restore the registers saved above */ + "movl 4(%%edx),%%esi\n\t" + "movl 8(%%edx),%%edi\n\t" + "movl 12(%%edx),%%ebp\n\t" + + : "=&a" (r), "=m" (space) + : "m" (f), "m" (basereg), "i" (RESERVED_C_STACK_BYTES) + : "edx" /* stomps on %edx */ + ); + + return r; +} + +#endif + +/* ----------------------------------------------------------------------------- + Sparc architecture + + -- + OLD COMMENT from GHC-3.02: + + We want tailjumps to be calls, because `call xxx' is the only Sparc + branch that allows an arbitrary label as a target. (Gcc's ``goto + *target'' construct ends up loading the label into a register and + then jumping, at the cost of two extra instructions for the 32-bit + load.) + + When entering the threaded world, we stash our return address in a + known location so that \tr{%i7} is available as an extra + callee-saves register. Of course, we have to restore this when + coming out of the threaded world. + + I hate this god-forsaken architecture. Since the top of the + reserved stack space is used for globals and the bottom is reserved + for outgoing arguments, we have to stick our return address + somewhere in the middle. Currently, I'm allowing 100 extra + outgoing arguments beyond the first 6. --JSM + + Updated info (GHC 4.06): we don't appear to use %i7 any more, so + I'm not sure whether we still need to save it. Incedentally, what + does the last paragraph above mean when it says "the top of the + stack is used for globals"? What globals? --SDM + + Updated info (GHC 4.08.2): not saving %i7 any more (see below). -------------------------------------------------------------------------- */ #ifdef sparc_TARGET_ARCH @@ -123,14 +322,32 @@ EXTFUN(StgReturn) StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg) { - StgChar space[RESERVED_C_STACK_BYTES+sizeof(void *)]; - register void *i7 __asm__("%i7"); - ((void **)(space))[100] = i7; + StgChar space[RESERVED_C_STACK_BYTES]; f(); - __asm__ volatile (".align 4\n" + __asm__ volatile ( + ".align 4\n" ".global " STG_RETURN "\n" - STG_RETURN ":\n" - "\tld %1,%0" : "=r" (i7) : "m" (((void **)(space))[100])); + STG_RETURN ":" + : : : "l0","l1","l2","l3","l4","l5","l6","l7"); + /* we tell the C compiler that l0-l7 are clobbered on return to + * StgReturn, otherwise it tries to use these to save eg. the + * address of space[100] across the call. The correct thing + * to do would be to save all the callee-saves regs, but we + * can't be bothered to do that. + * + * The code that gcc generates for this little fragment is now + * terrible. We could do much better by coding it directly in + * assembler. + */ +#if 0 + /* updated 4.08.2: we don't save %i7 in the middle of the reserved + * space any more, since gcc tries to save its address across the + * call to f(), this gets clobbered in STG land and we end up + * dereferencing a bogus pointer in StgReturn. + */ + __asm__ volatile ("ld %1,%0" + : "=r" (i7) : "m" (((void **)(space))[100])); +#endif return (StgThreadReturnCode)R1.i; } @@ -145,6 +362,8 @@ StgRun(StgFunPtr f, StgRegTable *basereg) { StgThreadReturnCode StgRun(StgFunPtr f, StgRegTable *basereg) { + StgThreadReturnCode ret; + __asm__ volatile ("stq $9,-8($30)\n\t" "stq $10,-16($30)\n\t" "stq $11,-24($30)\n\t" @@ -169,6 +388,7 @@ StgRun(StgFunPtr f, StgRegTable *basereg) __asm__ volatile (".align 3\n" ".globl " STG_RETURN "\n" STG_RETURN ":\n\t" + "lda %0,($14)\n\t" /* save R1 */ "lda $30,%0($30)\n\t" "ldq $9,-8($30)\n\t" "ldq $10,-16($30)\n\t" @@ -184,11 +404,12 @@ StgRun(StgFunPtr f, StgRegTable *basereg) "ldt $f6,-96($30)\n\t" "ldt $f7,-104($30)\n\t" "ldt $f8,-112($30)\n\t" - "ldt $f9,-120($30)" : : - "K" (RESERVED_C_STACK_BYTES+ + "ldt $f9,-120($30)" + : "=r" (ret) + : "K" (RESERVED_C_STACK_BYTES+ 8*sizeof(double)+8*sizeof(long))); - return (StgThreadReturnCode)R1.i; + return ret; } #endif /* alpha_TARGET_ARCH */