1 \section[StgMiniInt]{The ``mini-interpreter'' that drives the STG machine}
3 % this file is part of the C-as-assembler document
9 For portable~C, there really is a mini-interpreter that repeatedly
10 grabs the continuation from each code fragment and jumps to it.
12 In portable~C, we also have a ``debugging'' version of the
13 mini-interpreter which does ``hygiene-checking'' of the stacks/heap(?)
14 each time it regains control. This is deeply wonderful when the
15 compiler's generating duff code and things are badly broken!
17 For optimised~C, the mini-interpreter really {\em doesn't} do anything
18 remotely interpretive. It just jumps off into a Haskell Threaded
19 World, dropping a label for \tr{_miniInterpretEnd} so we'll have a
20 place to eventually come back to.
22 A complication in optimised~C: Because we completely nuke C-stack
23 activity (pushing/popping frames, moving register-windows) within the
24 Haskell-threaded world, we need to ensure there is enough C-stack
25 space actually present to satisfy the code that GCC generated.
27 IMPORTANT POINT: the mini-interpreter is supposed to be {\em generic}.
28 It is not only for the Haskell Threaded World---the storage manager
29 may use it as well. So: whatever threaded world is in operation has
30 to handle its own register saving/restoring, and such grimy details.
31 For an example, see the @startStgWorld@, @stopStgWorld@ pair of
34 %************************************************************************
36 \subsection[StgMiniInt-optimised]{Mini-interpreter for ``optimised~C''}
38 %************************************************************************
40 Unusually, for mini-interpreters, the ``optimised~C'' case involves
44 #if defined(__STG_TAILJUMPS__) && defined(__GNUC__)
46 #if i386_TARGET_ARCH || i486_TARGET_ARCH
47 /* All together now: "Hack me gently, hack me dead ..." */
48 P_ SP_stack[8]; /* two/three? is all that is really needed, I think (WDP) */
53 miniInterpret(start_cont)
57 * MINI_INTERPRETER_SETUP _must_ save _all_ callee-saves registers, because
58 * the caller expects them to be saved if they are used, but the threaded
59 * code never saaves anything (all function prologues have been removed).
62 MINI_INTERPRETER_SETUP
65 * starts Haskell world by _calling_ "start_cont"
67 * Make this a JMP_ and dead code elimination will make you unhappy.
69 * You will be even more unhappy with a registerized HP build, because
70 * the continuation passed in here is actually the address of a function
71 * ADT, and not the address where the function really begins.
76 * and drops a label for "miniInterpretEnd" right here, along
77 * with any cleanup that has to be done before we return.
79 * _Always_ RESUME_(miniInterpretEnd). Never JMP_(miniInterpretEnd).
88 %************************************************************************
90 \subsection[StgMiniInt-portable]{Mini-interpreter for ``portable~C''}
92 %************************************************************************
95 #else /* ! (__STG_TAILJUMPS__ && __GNUC__) */
98 /* by which we mean the Standard C Library stuff */
101 %************************************************************************
103 \subsubsection[StgMiniInt-portable-normal]{Normal mini-interpreter for ``portable~C''}
105 %************************************************************************
107 The static @jmp_environment@ variable allows @miniInterpret@ to
108 communicate with @miniInterpretEnd@.
110 Because @miniInterpret@ may be used recursively, we carefully
111 save and restore the whole of @jmp_environment@.
114 static jmp_buf jmp_environment;
116 extern void bcopy PROTO((char *, char *, int)); /*ToDo: properly?*/
119 miniInterpret(start_cont)
120 StgFunPtr start_cont;
122 StgFunPtr continuation = (StgFunPtr) start_cont;
124 bcopy((char *) jmp_environment, (char *) save_buf, sizeof(jmp_buf));
125 /* Save jmp_environment for previous call to miniInterpret */
127 if (setjmp(jmp_environment) == 0) {
130 /* unrolled for a little speed */
131 continuation = (StgFunPtr) (continuation)();
132 continuation = (StgFunPtr) (continuation)();
133 continuation = (StgFunPtr) (continuation)();
134 continuation = (StgFunPtr) (continuation)();
135 continuation = (StgFunPtr) (continuation)();
140 /* Restore jmp_environment for previous call */
141 bcopy((char *) save_buf, (char *) jmp_environment, sizeof(jmp_buf));
143 /* ToDo: restore real registers ... (see longjmp) */
146 Note that on returning (after miniInterpretEnd is called)
147 the values variables declared as real machine registers
152 void miniInterpretEnd(STG_NO_ARGS)
154 /* ToDo: save real register in something somewhere */
155 longjmp(jmp_environment, 1);
159 %************************************************************************
161 \subsubsection[StgMiniInt-portable-debugging]{Debugging mini-interpreter for ``portable~C''}
163 %************************************************************************
165 See comments about @jmp_environment@ in section above.
167 The debugging mini-interpreter, which is invoked if suitable RTS flags
168 are given, offers two extra ``features:''
171 \item[Circular buffer of last @NUM_SAVED_CONTINUATIONS@ continuations:]
172 These are in @savedCont@, with @savedContCtr@ pointing to where the
173 last one was slotted in.
175 Reference is frequently made to this buffer when \tr{gdb}-ing broken C
178 \item[Hygiene-checking:]
180 This version of the mini-interpreter can be given a hygiene-checking
181 function which will be invoked each time 'round the loop. Again,
182 given suitable RTS flags, we pass along a routine that walks over the
183 stack checking for Bad Stuff. An example might be: pointers from the
184 A stack into the wrong semi-space of the heap (indicating a
185 garbage-collection bug)...
189 extern I_ doSanityChks; /* ToDo: move tidily */
191 #define NUM_SAVED_CONTINUATIONS 32 /* For debug */
194 StgFunPtr savedCont[NUM_SAVED_CONTINUATIONS];
196 void miniInterpret_debug(start_cont, hygiene)
197 StgFunPtr start_cont;
200 StgFunPtr continuation = (StgFunPtr) start_cont;
201 StgFunPtr next_continuation;
203 bcopy((char *) jmp_environment, (char *) save_buf, sizeof(jmp_buf));
204 /* Save jmp_environment for previous call to miniInterpret */
206 if (setjmp(jmp_environment) == 0) {
210 savedCont[0] = start_cont;
213 next_continuation = (StgFunPtr) (continuation)();
216 savedContCtr = (savedContCtr + 1) % NUM_SAVED_CONTINUATIONS;
217 savedCont[savedContCtr] = next_continuation;
219 continuation = next_continuation;
221 /* hygiene chk can't be at start of loop, because it's the
222 first continuation-thingy that loads up the registers.
224 if (doSanityChks && hygiene) {
229 /* Restore jmp_environment for previous call */
230 bcopy((char *) save_buf, (char *) jmp_environment, sizeof(jmp_buf));
232 /* ToDo: restore real registers ... (see longjmp) */
235 Note that on returning (after miniInterpretEnd is called)
236 the values variables declared as real machine registers
241 /* debugging version uses same "miniInterpretEnd" as the regular one */
243 #endif /* ! __STG_TAILJUMPS__ */