X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fruntime%2Fc-as-asm%2FStgMiniInt.lc;fp=ghc%2Fruntime%2Fc-as-asm%2FStgMiniInt.lc;h=2739ad7e83940adb2557a145f0da333031b3a059;hb=e7d21ee4f8ac907665a7e170c71d59e13a01da09;hp=0000000000000000000000000000000000000000;hpb=e48474bff05e6cfb506660420f025f694c870d38;p=ghc-hetmet.git diff --git a/ghc/runtime/c-as-asm/StgMiniInt.lc b/ghc/runtime/c-as-asm/StgMiniInt.lc new file mode 100644 index 0000000..2739ad7 --- /dev/null +++ b/ghc/runtime/c-as-asm/StgMiniInt.lc @@ -0,0 +1,244 @@ +\section[StgMiniInt]{The ``mini-interpreter'' that drives the STG machine} + +% this file is part of the C-as-assembler document + +\begin{code} +#include "rtsdefs.h" +\end{code} + +For portable~C, there really is a mini-interpreter that repeatedly +grabs the continuation from each code fragment and jumps to it. + +In portable~C, we also have a ``debugging'' version of the +mini-interpreter which does ``hygiene-checking'' of the stacks/heap(?) +each time it regains control. This is deeply wonderful when the +compiler's generating duff code and things are badly broken! + +For optimised~C, the mini-interpreter really {\em doesn't} do anything +remotely interpretive. It just jumps off into a Haskell Threaded +World, dropping a label for \tr{_miniInterpretEnd} so we'll have a +place to eventually come back to. + +A complication in optimised~C: Because we completely nuke C-stack +activity (pushing/popping frames, moving register-windows) within the +Haskell-threaded world, we need to ensure there is enough C-stack +space actually present to satisfy the code that GCC generated. + +IMPORTANT POINT: the mini-interpreter is supposed to be {\em generic}. +It is not only for the Haskell Threaded World---the storage manager +may use it as well. So: whatever threaded world is in operation has +to handle its own register saving/restoring, and such grimy details. +For an example, see the @startStgWorld@, @stopStgWorld@ pair of +routines. + +%************************************************************************ +%* * +\subsection[StgMiniInt-optimised]{Mini-interpreter for ``optimised~C''} +%* * +%************************************************************************ + +Unusually, for mini-interpreters, the ``optimised~C'' case involves +less code. + +\begin{code} +#if defined(__STG_TAILJUMPS__) && defined(__GNUC__) + +#if i386_TARGET_ARCH || i486_TARGET_ARCH +/* All together now: "Hack me gently, hack me dead ..." */ +P_ SP_stack[8]; /* two/three? is all that is really needed, I think (WDP) */ +I_ SP_stack_ptr = -1; +#endif + +void +miniInterpret(start_cont) + StgFunPtr start_cont; +{ + /* + * MINI_INTERPRETER_SETUP _must_ save _all_ callee-saves registers, because + * the caller expects them to be saved if they are used, but the threaded + * code never saaves anything (all function prologues have been removed). + */ + + MINI_INTERPRETER_SETUP + + /* + * starts Haskell world by _calling_ "start_cont" + * + * Make this a JMP_ and dead code elimination will make you unhappy. + * + * You will be even more unhappy with a registerized HP build, because + * the continuation passed in here is actually the address of a function + * ADT, and not the address where the function really begins. + */ + (start_cont)(); + + /* + * and drops a label for "miniInterpretEnd" right here, along + * with any cleanup that has to be done before we return. + * + * _Always_ RESUME_(miniInterpretEnd). Never JMP_(miniInterpretEnd). + */ + + MINI_INTERPRETER_END + + return; +} +\end{code} + +%************************************************************************ +%* * +\subsection[StgMiniInt-portable]{Mini-interpreter for ``portable~C''} +%* * +%************************************************************************ + +\begin{code} +#else /* ! (__STG_TAILJUMPS__ && __GNUC__) */ + +#include +/* by which we mean the Standard C Library stuff */ +\end{code} + +%************************************************************************ +%* * +\subsubsection[StgMiniInt-portable-normal]{Normal mini-interpreter for ``portable~C''} +%* * +%************************************************************************ + +The static @jmp_environment@ variable allows @miniInterpret@ to +communicate with @miniInterpretEnd@. + +Because @miniInterpret@ may be used recursively, we carefully +save and restore the whole of @jmp_environment@. + +\begin{code} +static jmp_buf jmp_environment; + +extern void bcopy PROTO((char *, char *, int)); /*ToDo: properly?*/ + +void +miniInterpret(start_cont) + StgFunPtr start_cont; +{ + StgFunPtr continuation = (StgFunPtr) start_cont; + jmp_buf save_buf; + bcopy((char *) jmp_environment, (char *) save_buf, sizeof(jmp_buf)); + /* Save jmp_environment for previous call to miniInterpret */ + + if (setjmp(jmp_environment) == 0) { + + while ( 1 ) { + /* unrolled for a little speed */ + continuation = (StgFunPtr) (continuation)(); + continuation = (StgFunPtr) (continuation)(); + continuation = (StgFunPtr) (continuation)(); + continuation = (StgFunPtr) (continuation)(); + continuation = (StgFunPtr) (continuation)(); + } + } + + + /* Restore jmp_environment for previous call */ + bcopy((char *) save_buf, (char *) jmp_environment, sizeof(jmp_buf)); + + /* ToDo: restore real registers ... (see longjmp) */ + return; + /* + Note that on returning (after miniInterpretEnd is called) + the values variables declared as real machine registers + will be undefined. + */ +} + +void miniInterpretEnd(STG_NO_ARGS) +{ + /* ToDo: save real register in something somewhere */ + longjmp(jmp_environment, 1); +} +\end{code} + +%************************************************************************ +%* * +\subsubsection[StgMiniInt-portable-debugging]{Debugging mini-interpreter for ``portable~C''} +%* * +%************************************************************************ + +See comments about @jmp_environment@ in section above. + +The debugging mini-interpreter, which is invoked if suitable RTS flags +are given, offers two extra ``features:'' +\begin{description} + +\item[Circular buffer of last @NUM_SAVED_CONTINUATIONS@ continuations:] +These are in @savedCont@, with @savedContCtr@ pointing to where the +last one was slotted in. + +Reference is frequently made to this buffer when \tr{gdb}-ing broken C +out of the compiler! + +\item[Hygiene-checking:] + +This version of the mini-interpreter can be given a hygiene-checking +function which will be invoked each time 'round the loop. Again, +given suitable RTS flags, we pass along a routine that walks over the +stack checking for Bad Stuff. An example might be: pointers from the +A stack into the wrong semi-space of the heap (indicating a +garbage-collection bug)... +\end{description} + +\begin{code} +extern I_ doSanityChks; /* ToDo: move tidily */ + +#define NUM_SAVED_CONTINUATIONS 32 /* For debug */ +I_ totalContCtr; +I_ savedContCtr; +StgFunPtr savedCont[NUM_SAVED_CONTINUATIONS]; + +void miniInterpret_debug(start_cont, hygiene) + StgFunPtr start_cont; + void (*hygiene)(); +{ + StgFunPtr continuation = (StgFunPtr) start_cont; + StgFunPtr next_continuation; + jmp_buf save_buf; + bcopy((char *) jmp_environment, (char *) save_buf, sizeof(jmp_buf)); + /* Save jmp_environment for previous call to miniInterpret */ + + if (setjmp(jmp_environment) == 0) { + + totalContCtr = 0; + savedContCtr = 0; + savedCont[0] = start_cont; + + while ( 1 ) { + next_continuation = (StgFunPtr) (continuation)(); + + totalContCtr += 1; + savedContCtr = (savedContCtr + 1) % NUM_SAVED_CONTINUATIONS; + savedCont[savedContCtr] = next_continuation; + + continuation = next_continuation; + + /* hygiene chk can't be at start of loop, because it's the + first continuation-thingy that loads up the registers. + */ + if (doSanityChks && hygiene) { + (hygiene)(); + } + } + } + /* Restore jmp_environment for previous call */ + bcopy((char *) save_buf, (char *) jmp_environment, sizeof(jmp_buf)); + + /* ToDo: restore real registers ... (see longjmp) */ + return; + /* + Note that on returning (after miniInterpretEnd is called) + the values variables declared as real machine registers + will be undefined. + */ +} + +/* debugging version uses same "miniInterpretEnd" as the regular one */ + +#endif /* ! __STG_TAILJUMPS__ */ +\end{code}