[project @ 2001-01-05 15:24:28 by sewardj]
[ghc-hetmet.git] / ghc / rts / Interpreter.c
1
2 /* -----------------------------------------------------------------------------
3  * Bytecode evaluator
4  *
5  * Copyright (c) 1994-2000.
6  *
7  * $RCSfile: Interpreter.c,v $
8  * $Revision: 1.8 $
9  * $Date: 2001/01/05 15:24:28 $
10  * ---------------------------------------------------------------------------*/
11
12 #ifdef GHCI
13
14 #include "Rts.h"
15 #include "RtsAPI.h"
16 #include "RtsUtils.h"
17 #include "Closures.h"
18 #include "TSO.h"
19 #include "Schedule.h"
20 #include "RtsFlags.h"
21 #include "Storage.h"
22 #include "Updates.h"
23
24 #include "Bytecodes.h"
25 #include "Printer.h"
26 #include "Disassembler.h"
27 #include "Interpreter.h"
28
29
30 /* --------------------------------------------------------------------------
31  * The new bytecode interpreter
32  * ------------------------------------------------------------------------*/
33
34 /* Sp points to the lowest live word on the stack. */
35
36 #define StackWord(n)  iSp[n]
37 #define BCO_NEXT      instrs[bciPtr++]
38 #define BCO_PTR(n)    (W_)ptrs[n]
39 #define BCO_LIT(n)    (W_)literals[n]
40 #define BCO_ITBL(n)   itbls[n]
41
42 #define LOAD_STACK_POINTERS \
43     iSp = cap->rCurrentTSO->sp; iSu = cap->rCurrentTSO->su;
44
45 #define SAVE_STACK_POINTERS \
46     cap->rCurrentTSO->sp = iSp; cap->rCurrentTSO->su = iSu;
47
48 #define RETURN(retcode) \
49    SAVE_STACK_POINTERS; return retcode;
50
51
52 StgThreadReturnCode interpretBCO ( Capability* cap )
53 {
54    /* On entry, the closure to interpret is on the top of the
55       stack. */
56  
57    /* Use of register here is primarily to make it clear to compilers
58       that these entities are non-aliasable.
59    */
60     register W_*              iSp;    /* local state -- stack pointer */
61     register StgUpdateFrame*  iSu;    /* local state -- frame pointer */
62     register StgPtr           iSpLim; /* local state -- stack lim pointer */
63     register StgClosure*      obj;
64
65     LOAD_STACK_POINTERS;
66
67     iSpLim = cap->rCurrentTSO->stack + RESERVED_STACK_WORDS;
68
69     /* Main object-entering loop.  Object to be entered is on top of
70        stack. */
71     nextEnter:
72
73     obj = (StgClosure*)StackWord(0); iSp++;
74
75     IF_DEBUG(evaluator,
76              fprintf(stderr, 
77              "\n---------------------------------------------------------------\n");
78              fprintf(stderr,"Entering: "); printObj(obj);
79              fprintf(stderr,"iSp = %p\tiSu = %p\n", iSp, iSu);
80              fprintf(stderr, "\n" );
81              printStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
82              fprintf(stderr, "\n\n");
83             );
84
85     switch ( get_itbl(obj)->type ) {
86        case INVALID_OBJECT:
87                barf("Invalid object %p",(StgPtr)obj);
88
89 #if 0
90        case AP_UPD:
91         { nat Words;
92           nat i;
93           StgAP_UPD *ap = (StgAP_UPD*)obj;
94           Words = ap->n_args;
95
96           iSp -= sizeofW(StgUpdateFrame);
97
98           {
99               StgUpdateFrame *__frame;
100               __frame = (StgUpdateFrame *)iSp;
101               SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);
102               __frame->link = iSu;
103               __frame->updatee = (StgClosure *)(ap);
104               iSu = __frame;
105           }
106
107           /* WARNING: do a stack overflow check here ! */
108           iSp -= Words;
109
110           /* Reload the stack */
111           for (i=0; i<Words; i++) StackWord(i) = (W_)ap->payload[i];
112
113           iSp--; StackWord(0) = (W_)ap->fun;
114           goto nextEnter;
115         }
116 #endif
117
118        case BCO:
119
120        /* ---------------------------------------------------- */
121        /* Start of the bytecode interpreter                    */
122        /* ---------------------------------------------------- */
123        {
124           register int       bciPtr     = 1; /* instruction pointer */
125           register StgBCO*   bco        = (StgBCO*)obj;
126           register UShort*   instrs     = (UShort*)(&bco->instrs->payload[0]);
127           register StgWord*  literals   = (StgWord*)(&bco->literals->payload[0]);
128           register StgPtr*   ptrs       = (StgPtr*)(&bco->ptrs->payload[0]);
129           register StgInfoTable** itbls = (StgInfoTable**)
130                                              (&bco->itbls->payload[0]);
131
132           if (doYouWantToGC()) {
133              iSp--; StackWord(0) = (W_)bco;
134              RETURN(HeapOverflow);
135           }
136
137           nextInsn:
138
139           ASSERT(bciPtr <= instrs[0]);
140           IF_DEBUG(evaluator,
141                    //fprintf(stderr, "\n-- BEGIN stack\n");
142                    //printStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
143                    //fprintf(stderr, "-- END stack\n\n");
144                    fprintf(stderr,"iSp = %p   iSu = %p   pc = %d      ", iSp, iSu, bciPtr);
145                   disInstr(bco,bciPtr);
146                   if (0) { int i;
147                            fprintf(stderr,"\n");
148                            for (i = 8; i >= 0; i--) 
149                               fprintf(stderr, "%d  %p\n", i, (StgPtr)(*(iSp+i)));
150                            fprintf(stderr,"\n");
151                          }
152                  );
153
154           switch (BCO_NEXT) {
155
156               case bci_ARGCHECK: {
157                  int i;
158                  StgPAP* pap;
159                  int arg_words_reqd = BCO_NEXT;
160                  int arg_words_avail = ((W_*)iSu) - ((W_*)iSp);
161                  if (arg_words_avail >= arg_words_reqd) goto nextInsn;
162                  /* Handle arg check failure.  Copy the spare args
163                     into a PAP frame. */
164                  /* fprintf(stderr, "arg check fail %d %d\n", arg_words_reqd, arg_words_avail ); */
165                  pap = (StgPAP*)allocate(PAP_sizeW(arg_words_avail));
166                  SET_HDR(pap,&stg_PAP_info,CCS_SYSTEM/*ToDo*/);
167                  pap->n_args = arg_words_avail;
168                  pap->fun = obj;
169                  for (i = 0; i < arg_words_avail; i++)
170                     pap->payload[i] = (StgClosure*)StackWord(i);
171                  /* Push on the stack and defer to the scheduler. */
172                  iSp = (StgPtr)iSu;
173                  iSp --;
174                  StackWord(0) = (W_)pap;
175                  RETURN(ThreadEnterGHC);
176               }
177               case bci_PUSH_L: {
178                  int o1 = BCO_NEXT;
179                  ASSERT((W_*)iSp+o1 < (W_*)iSu);
180                  StackWord(-1) = StackWord(o1);
181                  iSp--;
182                  goto nextInsn;
183               }
184               case bci_PUSH_LL: {
185                  int o1 = BCO_NEXT;
186                  int o2 = BCO_NEXT;
187                  StackWord(-1) = StackWord(o1);
188                  StackWord(-2) = StackWord(o2);
189                  iSp -= 2;
190                  goto nextInsn;
191               }
192               case bci_PUSH_LLL: {
193                  int o1 = BCO_NEXT;
194                  int o2 = BCO_NEXT;
195                  int o3 = BCO_NEXT;
196                  StackWord(-1) = StackWord(o1);
197                  StackWord(-2) = StackWord(o2);
198                  StackWord(-3) = StackWord(o3);
199                  iSp -= 3;
200                  goto nextInsn;
201               }
202               case bci_PUSH_G: {
203                  int o1 = BCO_NEXT;
204                  StackWord(-1) = BCO_PTR(o1);
205                  iSp -= 1;
206                  goto nextInsn;
207               }
208               case bci_PUSH_AS: {
209                  int o_bco  = BCO_NEXT;
210                  int o_itbl = BCO_NEXT;
211                  StackWord(-2) = BCO_LIT(o_itbl);
212                  StackWord(-1) = BCO_PTR(o_bco);
213                  iSp -= 2;
214                  goto nextInsn;
215               }
216               case bci_PUSH_UBX: {
217                  int o_lits = BCO_NEXT;
218                  int n_words = BCO_NEXT;
219                  for (; n_words > 0; n_words--) {
220                     iSp --;
221                     StackWord(0) = BCO_LIT(o_lits);
222                     o_lits++;
223                  }
224                  goto nextInsn;
225               }
226               case bci_PUSH_TAG: {
227                  W_ tag = (W_)(BCO_NEXT);
228                  StackWord(-1) = tag;
229                  iSp --;
230                  goto nextInsn;
231               }
232               case bci_SLIDE: {
233                  int n  = BCO_NEXT;
234                  int by = BCO_NEXT;
235                  ASSERT((W_*)iSp+n+by <= (W_*)iSu);
236                  /* a_1, .. a_n, b_1, .. b_by, s => a_1, .. a_n, s */
237                  while(--n >= 0) {
238                     StackWord(n+by) = StackWord(n);
239                  }
240                  iSp += by;
241                  goto nextInsn;
242               }
243               case bci_ALLOC: {
244                  int n_payload = BCO_NEXT - 1;
245                  StgAP_UPD* ap = (StgAP_UPD*)allocate(AP_sizeW(n_payload));
246                  StackWord(-1) = (W_)ap;
247                  ap->n_args = n_payload;
248                  SET_HDR(ap, &stg_AP_UPD_info, ??)
249                  iSp --;
250                  goto nextInsn;
251               }
252               case bci_MKAP: {
253                  int i;
254                  int stkoff = BCO_NEXT;
255                  int n_payload = BCO_NEXT - 1;
256                  StgAP_UPD* ap = (StgAP_UPD*)StackWord(stkoff);
257                  ASSERT((int)ap->n_args == n_payload);
258                  ap->fun = (StgClosure*)StackWord(0);
259                  for (i = 0; i < n_payload; i++)
260                     ap->payload[i] = (StgClosure*)StackWord(i+1);
261                  iSp += n_payload+1;
262                  goto nextInsn;
263               }
264               case bci_UNPACK: {
265                  /* Unpack N ptr words from t.o.s constructor */
266                  /* The common case ! */
267                  int i;
268                  int n_words = BCO_NEXT;
269                  StgClosure* con = (StgClosure*)StackWord(0);
270                  iSp -= n_words;
271                  for (i = 0; i < n_words; i++)
272                     StackWord(i) = (W_)con->payload[i];
273                  goto nextInsn;
274               }
275               case bci_UPK_TAG: {
276                  /* Unpack N (non-ptr) words from offset M in the
277                     constructor K words down the stack, and then push
278                     N as a tag, on top of it.  Slow but general; we
279                     hope it will be the rare case. */
280                  int i;                
281                  int n_words = BCO_NEXT;
282                  int con_off = BCO_NEXT;
283                  int stk_off = BCO_NEXT;
284                  StgClosure* con = (StgClosure*)StackWord(stk_off);
285                  iSp -= n_words;
286                  for (i = 0; i < n_words; i++) 
287                     StackWord(i) = (W_)con->payload[con_off + i];
288                  iSp --;
289                  StackWord(0) = n_words;
290                  goto nextInsn;
291               }
292               case bci_PACK: {
293                  int i;
294                  int o_itbl         = BCO_NEXT;
295                  int n_words        = BCO_NEXT;
296                  StgInfoTable* itbl = BCO_ITBL(o_itbl);
297                  /* A bit of a kludge since n_words = n_p + n_np */
298                  int request        = CONSTR_sizeW( n_words, 0 );
299                  StgClosure* con = (StgClosure*)allocate(request);
300                  SET_HDR(con, itbl, CCS_SYSTEM/*ToDo*/);
301                  for (i = 0; i < n_words; i++)
302                     con->payload[i] = (StgClosure*)StackWord(i);
303                  iSp += n_words;
304                  iSp --;
305                  StackWord(0) = (W_)con;
306                  goto nextInsn;
307               }
308               case bci_TESTLT_P: {
309                  int discr  = BCO_NEXT;
310                  int failto = BCO_NEXT;
311                  StgClosure* con = (StgClosure*)StackWord(0);
312                  if (constrTag(con) >= discr)
313                     bciPtr = failto;
314                  goto nextInsn;
315               }
316               case bci_TESTEQ_P: {
317                  int discr  = BCO_NEXT;
318                  int failto = BCO_NEXT;
319                  StgClosure* con = (StgClosure*)StackWord(0);
320                  if (constrTag(con) != discr)
321                     bciPtr = failto;
322                  goto nextInsn;
323               }
324
325               /* Control-flow ish things */
326               case bci_ENTER: {
327                  goto nextEnter;
328               }
329               case bci_RETURN: {
330                  /* Figure out whether returning to interpreted or
331                     compiled code. */
332                  int           o_itoc_itbl = BCO_NEXT;
333                  int           tag         = StackWord(0);
334                  StgInfoTable* ret_itbl    = (StgInfoTable*)StackWord(tag+1 +1);
335                  ASSERT(tag <= 2); /* say ... */
336                  if (ret_itbl == (StgInfoTable*)&stg_ctoi_ret_R1_info
337                      /* || ret_itbl == stg_ctoi_ret_F1_info
338                         || ret_itbl == stg_ctoi_ret_D1_info */) {
339                      /* Returning to interpreted code.  Interpret the BCO 
340                         immediately underneath the itbl. */
341                      StgBCO* ret_bco = (StgBCO*)StackWord(tag+1 +1+1);
342                      iSp --;
343                      StackWord(0) = (W_)ret_bco;
344                      goto nextEnter;
345                  } else {
346                      /* Returning (unboxed value) to compiled code.
347                         Replace tag with a suitable itbl and ask the
348                         scheduler to run it.  The itbl code will copy
349                         the TOS value into R1/F1/D1 and do a standard
350                         compiled-code return. */
351                      StgInfoTable* magic_itbl = BCO_ITBL(o_itoc_itbl);
352                      StackWord(0) = (W_)magic_itbl;
353                      RETURN(ThreadRunGHC);
354                  }
355               }
356         
357               case bci_CASEFAIL:
358                  barf("interpretBCO: hit a CASEFAIL");
359
360               /* As yet unimplemented */
361               case bci_TESTLT_I:
362               case bci_TESTEQ_I:
363               case bci_TESTLT_F:
364               case bci_TESTEQ_F:
365               case bci_TESTLT_D:
366               case bci_TESTEQ_D:
367
368               /* Errors */
369               default: 
370                  barf("interpretBCO: unknown or unimplemented opcode");
371
372           } /* switch on opcode */
373
374           barf("interpretBCO: fell off end of insn loop");
375
376        }
377        /* ---------------------------------------------------- */
378        /* End of the bytecode interpreter                      */
379        /* ---------------------------------------------------- */
380
381        default: {
382           /* Can't handle this object; yield to sched. */
383           IF_DEBUG(evaluator,
384                    fprintf(stderr, "entering unknown closure -- yielding to sched\n"); 
385                    printObj(obj);
386                   )
387           cap->rCurrentTSO->what_next = ThreadEnterGHC;
388           iSp--; StackWord(0) = (W_)obj;
389           RETURN(ThreadYielding);
390        }
391     } /* switch on object kind */
392
393     barf("fallen off end of object-type switch in interpretBCO()");
394 }
395
396 #endif /* GHCI */