[project @ 1998-11-26 09:17:22 by sof]
[ghc-hetmet.git] / ghc / runtime / c-as-asm / StgMiniInt.lc
1 \section[StgMiniInt]{The ``mini-interpreter'' that drives the STG machine}
2
3 % this file is part of the C-as-assembler document
4
5 \begin{code}
6 #include "rtsdefs.h"
7 \end{code}
8
9 For portable~C, there really is a mini-interpreter that repeatedly
10 grabs the continuation from each code fragment and jumps to it.
11
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!
16
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.
21
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.
26
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
32 routines.
33
34 %************************************************************************
35 %*                                                                      *
36 \subsection[StgMiniInt-optimised]{Mini-interpreter for ``optimised~C''}
37 %*                                                                      *
38 %************************************************************************
39
40 Unusually, for mini-interpreters, the ``optimised~C'' case involves
41 less code.
42
43 \begin{code}
44 #if defined(__STG_TAILJUMPS__) && defined(__GNUC__)
45
46 void
47 miniInterpret(start_cont)
48     StgFunPtr start_cont;
49 {
50     /* 
51      * MINI_INTERPRETER_SETUP _must_ save _all_ callee-saves registers, because
52      * the caller expects them to be saved if they are used, but the threaded
53      * code never saaves anything (all function prologues have been removed).
54      */
55
56     MINI_INTERPRETER_SETUP
57
58     /* 
59      * starts Haskell world by _calling_ "start_cont"
60      * 
61      * Make this a JMP_ and dead code elimination will make you unhappy.
62      *
63      * You will be even more unhappy with a registerized HP build, because
64      * the continuation passed in here is actually the address of a function
65      * ADT, and not the address where the function really begins.
66      */
67     (start_cont)();
68
69     /* 
70      * and drops a label for "miniInterpretEnd" right here, along
71      * with any cleanup that has to be done before we return.
72      *
73      * _Always_ RESUME_(miniInterpretEnd).  Never JMP_(miniInterpretEnd).
74      */
75
76     MINI_INTERPRETER_END
77
78     return;
79 }
80 \end{code}
81
82 %************************************************************************
83 %*                                                                      *
84 \subsection[StgMiniInt-portable]{Mini-interpreter for ``portable~C''}
85 %*                                                                      *
86 %************************************************************************
87
88 \begin{code}
89 #else /* ! (__STG_TAILJUMPS__ && __GNUC__) */
90
91 #include <setjmp.h>
92 /* by which we mean the Standard C Library stuff */
93 \end{code}
94
95 %************************************************************************
96 %*                                                                      *
97 \subsubsection[StgMiniInt-portable-normal]{Normal mini-interpreter for ``portable~C''}
98 %*                                                                      *
99 %************************************************************************
100
101 The static @jmp_environment@ variable allows @miniInterpret@ to
102 communicate with @miniInterpretEnd@.
103
104 Because @miniInterpret@ may be used recursively, we carefully
105 save and restore the whole of @jmp_environment@.
106
107 \begin{code}
108 static jmp_buf jmp_environment;
109
110 void bcopy PROTO((char *, char *, int)); /*ToDo: properly?*/
111
112 void
113 miniInterpret(start_cont)
114     StgFunPtr start_cont;
115 {
116     StgFunPtr continuation = (StgFunPtr) start_cont;
117     jmp_buf save_buf;
118     bcopy((char *) jmp_environment, (char *) save_buf, sizeof(jmp_buf));        
119         /* Save jmp_environment for previous call to miniInterpret */
120     
121     if (setjmp(jmp_environment) == 0) {
122
123         while ( 1 ) {
124             /* unrolled for a little speed */
125             continuation = (StgFunPtr) (continuation)();
126             continuation = (StgFunPtr) (continuation)();
127             continuation = (StgFunPtr) (continuation)();
128             continuation = (StgFunPtr) (continuation)();
129             continuation = (StgFunPtr) (continuation)();
130         }
131     }
132
133
134     /* Restore jmp_environment for previous call */
135     bcopy((char *) save_buf, (char *) jmp_environment, sizeof(jmp_buf));
136
137     /* ToDo: restore real registers ... (see longjmp) */
138     return;
139     /*
140        Note that on returning (after miniInterpretEnd is called)
141        the values variables declared as real machine registers
142        will be undefined.
143     */
144 }
145
146 void miniInterpretEnd(STG_NO_ARGS)
147 {
148     /* ToDo: save real register in something somewhere */
149     longjmp(jmp_environment, 1);
150 }
151
152 #endif /* ! __STG_TAILJUMPS__ */
153 \end{code}