\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__) 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; 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); } #endif /* ! __STG_TAILJUMPS__ */ \end{code}