[project @ 2001-01-09 17:36:21 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.9 $
9  * $Date: 2001/01/09 17:36:21 $
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
82              //      checkSanity(1);
83              //             iSp--; StackWord(0) = obj;
84              //             checkStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
85              //             iSp++;
86
87              printStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
88              fprintf(stderr, "\n\n");
89             );
90
91     switch ( get_itbl(obj)->type ) {
92        case INVALID_OBJECT:
93                barf("Invalid object %p",(StgPtr)obj);
94
95 #if 0
96        case AP_UPD:
97         { nat Words;
98           nat i;
99           StgAP_UPD *ap = (StgAP_UPD*)obj;
100           Words = ap->n_args;
101
102           /* WARNING: do a stack overflow check here !
103              This code (copied from stg_AP_UPD_entry) is not correct without it. */
104
105           iSp -= sizeofW(StgUpdateFrame);
106
107           {
108               StgUpdateFrame *__frame;
109               __frame = (StgUpdateFrame *)iSp;
110               SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);
111               __frame->link = iSu;
112               __frame->updatee = (StgClosure *)(ap);
113               iSu = __frame;
114           }
115
116           iSp -= Words;
117
118           /* Reload the stack */
119           for (i=0; i<Words; i++) StackWord(i) = (W_)ap->payload[i];
120
121           iSp--; StackWord(0) = (W_)ap->fun;
122           goto nextEnter;
123         }
124 #endif
125
126        case BCO:
127
128        /* ---------------------------------------------------- */
129        /* Start of the bytecode interpreter                    */
130        /* ---------------------------------------------------- */
131        {
132           register int       bciPtr     = 1; /* instruction pointer */
133           register StgBCO*   bco        = (StgBCO*)obj;
134           register UShort*   instrs     = (UShort*)(&bco->instrs->payload[0]);
135           register StgWord*  literals   = (StgWord*)(&bco->literals->payload[0]);
136           register StgPtr*   ptrs       = (StgPtr*)(&bco->ptrs->payload[0]);
137           register StgInfoTable** itbls = (StgInfoTable**)
138                                              (&bco->itbls->payload[0]);
139
140           if (doYouWantToGC()) {
141              iSp--; StackWord(0) = (W_)bco;
142              RETURN(HeapOverflow);
143           }
144
145           nextInsn:
146
147           ASSERT(bciPtr <= instrs[0]);
148           IF_DEBUG(evaluator,
149                    //fprintf(stderr, "\n-- BEGIN stack\n");
150                    //printStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
151                    //fprintf(stderr, "-- END stack\n\n");
152                    fprintf(stderr,"iSp = %p   iSu = %p   pc = %d      ", iSp, iSu, bciPtr);
153                   disInstr(bco,bciPtr);
154                   if (0) { int i;
155                            fprintf(stderr,"\n");
156                            for (i = 8; i >= 0; i--) 
157                               fprintf(stderr, "%d  %p\n", i, (StgPtr)(*(iSp+i)));
158                            fprintf(stderr,"\n");
159                          }
160                  );
161
162           //             checkStack(iSp,cap->rCurrentTSO->stack+cap->rCurrentTSO->stack_size,iSu);
163
164           switch (BCO_NEXT) {
165
166               case bci_ARGCHECK: {
167                  int i;
168                  StgPAP* pap;
169                  int arg_words_reqd = BCO_NEXT;
170                  int arg_words_avail = ((W_*)iSu) - ((W_*)iSp);
171                  if (arg_words_avail >= arg_words_reqd) goto nextInsn;
172                  /* Handle arg check failure.  Copy the spare args
173                     into a PAP frame. */
174                  /* fprintf(stderr, "arg check fail %d %d\n", arg_words_reqd, arg_words_avail ); */
175                  pap = (StgPAP*)allocate(PAP_sizeW(arg_words_avail));
176                  SET_HDR(pap,&stg_PAP_info,CCS_SYSTEM/*ToDo*/);
177                  pap->n_args = arg_words_avail;
178                  pap->fun = obj;
179                  for (i = 0; i < arg_words_avail; i++)
180                     pap->payload[i] = (StgClosure*)StackWord(i);
181                  /* Push on the stack and defer to the scheduler. */
182                  iSp = (StgPtr)iSu;
183                  iSp --;
184                  StackWord(0) = (W_)pap;
185                  RETURN(ThreadEnterGHC);
186               }
187               case bci_PUSH_L: {
188                  int o1 = BCO_NEXT;
189                  ASSERT((W_*)iSp+o1 < (W_*)iSu);
190                  StackWord(-1) = StackWord(o1);
191                  iSp--;
192                  goto nextInsn;
193               }
194               case bci_PUSH_LL: {
195                  int o1 = BCO_NEXT;
196                  int o2 = BCO_NEXT;
197                  StackWord(-1) = StackWord(o1);
198                  StackWord(-2) = StackWord(o2);
199                  iSp -= 2;
200                  goto nextInsn;
201               }
202               case bci_PUSH_LLL: {
203                  int o1 = BCO_NEXT;
204                  int o2 = BCO_NEXT;
205                  int o3 = BCO_NEXT;
206                  StackWord(-1) = StackWord(o1);
207                  StackWord(-2) = StackWord(o2);
208                  StackWord(-3) = StackWord(o3);
209                  iSp -= 3;
210                  goto nextInsn;
211               }
212               case bci_PUSH_G: {
213                  int o1 = BCO_NEXT;
214                  StackWord(-1) = BCO_PTR(o1);
215                  iSp -= 1;
216                  goto nextInsn;
217               }
218               case bci_PUSH_AS: {
219                  int o_bco  = BCO_NEXT;
220                  int o_itbl = BCO_NEXT;
221                  StackWord(-2) = BCO_LIT(o_itbl);
222                  StackWord(-1) = BCO_PTR(o_bco);
223                  iSp -= 2;
224                  goto nextInsn;
225               }
226               case bci_PUSH_UBX: {
227                  int o_lits = BCO_NEXT;
228                  int n_words = BCO_NEXT;
229                  for (; n_words > 0; n_words--) {
230                     iSp --;
231                     StackWord(0) = BCO_LIT(o_lits);
232                     o_lits++;
233                  }
234                  goto nextInsn;
235               }
236               case bci_PUSH_TAG: {
237                  W_ tag = (W_)(BCO_NEXT);
238                  StackWord(-1) = tag;
239                  iSp --;
240                  goto nextInsn;
241               }
242               case bci_SLIDE: {
243                  int n  = BCO_NEXT;
244                  int by = BCO_NEXT;
245                  ASSERT((W_*)iSp+n+by <= (W_*)iSu);
246                  /* a_1, .. a_n, b_1, .. b_by, s => a_1, .. a_n, s */
247                  while(--n >= 0) {
248                     StackWord(n+by) = StackWord(n);
249                  }
250                  iSp += by;
251                  goto nextInsn;
252               }
253               case bci_ALLOC: {
254                  int n_payload = BCO_NEXT - 1;
255                  StgAP_UPD* ap = (StgAP_UPD*)allocate(AP_sizeW(n_payload));
256                  StackWord(-1) = (W_)ap;
257                  ap->n_args = n_payload;
258                  SET_HDR(ap, &stg_AP_UPD_info, ??)
259                  iSp --;
260                  goto nextInsn;
261               }
262               case bci_MKAP: {
263                  int i;
264                  int stkoff = BCO_NEXT;
265                  int n_payload = BCO_NEXT - 1;
266                  StgAP_UPD* ap = (StgAP_UPD*)StackWord(stkoff);
267                  ASSERT((int)ap->n_args == n_payload);
268                  ap->fun = (StgClosure*)StackWord(0);
269                  for (i = 0; i < n_payload; i++)
270                     ap->payload[i] = (StgClosure*)StackWord(i+1);
271                  iSp += n_payload+1;
272                  goto nextInsn;
273               }
274               case bci_UNPACK: {
275                  /* Unpack N ptr words from t.o.s constructor */
276                  /* The common case ! */
277                  int i;
278                  int n_words = BCO_NEXT;
279                  StgClosure* con = (StgClosure*)StackWord(0);
280                  iSp -= n_words;
281                  for (i = 0; i < n_words; i++)
282                     StackWord(i) = (W_)con->payload[i];
283                  goto nextInsn;
284               }
285               case bci_UPK_TAG: {
286                  /* Unpack N (non-ptr) words from offset M in the
287                     constructor K words down the stack, and then push
288                     N as a tag, on top of it.  Slow but general; we
289                     hope it will be the rare case. */
290                  int i;                
291                  int n_words = BCO_NEXT;
292                  int con_off = BCO_NEXT;
293                  int stk_off = BCO_NEXT;
294                  StgClosure* con = (StgClosure*)StackWord(stk_off);
295                  iSp -= n_words;
296                  for (i = 0; i < n_words; i++) 
297                     StackWord(i) = (W_)con->payload[con_off + i];
298                  iSp --;
299                  StackWord(0) = n_words;
300                  goto nextInsn;
301               }
302               case bci_PACK: {
303                  int i;
304                  int o_itbl         = BCO_NEXT;
305                  int n_words        = BCO_NEXT;
306                  StgInfoTable* itbl = BCO_ITBL(o_itbl);
307                  /* A bit of a kludge since n_words = n_p + n_np */
308                  int request        = CONSTR_sizeW( n_words, 0 );
309                  StgClosure* con = (StgClosure*)allocate(request);
310                  SET_HDR(con, itbl, CCS_SYSTEM/*ToDo*/);
311                  for (i = 0; i < n_words; i++)
312                     con->payload[i] = (StgClosure*)StackWord(i);
313                  iSp += n_words;
314                  iSp --;
315                  StackWord(0) = (W_)con;
316                  goto nextInsn;
317               }
318               case bci_TESTLT_P: {
319                  int discr  = BCO_NEXT;
320                  int failto = BCO_NEXT;
321                  StgClosure* con = (StgClosure*)StackWord(0);
322                  if (constrTag(con) >= discr)
323                     bciPtr = failto;
324                  goto nextInsn;
325               }
326               case bci_TESTEQ_P: {
327                  int discr  = BCO_NEXT;
328                  int failto = BCO_NEXT;
329                  StgClosure* con = (StgClosure*)StackWord(0);
330                  if (constrTag(con) != discr)
331                     bciPtr = failto;
332                  goto nextInsn;
333               }
334               case bci_TESTEQ_I: {
335                  /* The top thing on the stack should be a tagged int. */
336                  int discr   = BCO_NEXT;
337                  int failto  = BCO_NEXT;
338                  I_ stackInt = (I_)StackWord(1);
339                  ASSERT(1 == StackWord(0));
340                  fprintf(stderr, "TESTEQ_I: discr = %d, stack = %d\n",(I_)BCO_LIT(discr), stackInt); 
341                  if (stackInt != (I_)BCO_LIT(discr))
342                     bciPtr = failto;
343                  goto nextInsn;
344               }
345
346               /* Control-flow ish things */
347               case bci_ENTER: {
348                  goto nextEnter;
349               }
350               case bci_RETURN: {
351                  /* Figure out whether returning to interpreted or
352                     compiled code. */
353                  int           o_itoc_itbl = BCO_NEXT;
354                  int           tag         = StackWord(0);
355                  StgInfoTable* ret_itbl    = (StgInfoTable*)StackWord(tag +1);
356                  ASSERT(tag <= 2); /* say ... */
357                  if (ret_itbl == (StgInfoTable*)&stg_ctoi_ret_R1_info
358                      /* || ret_itbl == stg_ctoi_ret_F1_info
359                         || ret_itbl == stg_ctoi_ret_D1_info */) {
360                      /* Returning to interpreted code.  Interpret the BCO 
361                         immediately underneath the itbl. */
362                      StgBCO* ret_bco = (StgBCO*)StackWord(tag +1+1);
363                      iSp --;
364                      StackWord(0) = (W_)ret_bco;
365                      goto nextEnter;
366                  } else {
367                      /* Returning (unboxed value) to compiled code.
368                         Replace tag with a suitable itbl and ask the
369                         scheduler to run it.  The itbl code will copy
370                         the TOS value into R1/F1/D1 and do a standard
371                         compiled-code return. */
372                      StgInfoTable* magic_itbl = BCO_ITBL(o_itoc_itbl);
373                      StackWord(0) = (W_)magic_itbl;
374                      RETURN(ThreadRunGHC);
375                  }
376               }
377         
378               case bci_CASEFAIL:
379                  barf("interpretBCO: hit a CASEFAIL");
380
381               /* As yet unimplemented */
382               case bci_TESTLT_I:
383               case bci_TESTLT_F:
384               case bci_TESTEQ_F:
385               case bci_TESTLT_D:
386               case bci_TESTEQ_D:
387
388               /* Errors */
389               default: 
390                  barf("interpretBCO: unknown or unimplemented opcode");
391
392           } /* switch on opcode */
393
394           barf("interpretBCO: fell off end of insn loop");
395
396        }
397        /* ---------------------------------------------------- */
398        /* End of the bytecode interpreter                      */
399        /* ---------------------------------------------------- */
400
401        default: {
402           /* Can't handle this object; yield to sched. */
403           IF_DEBUG(evaluator,
404                    fprintf(stderr, "entering unknown closure -- yielding to sched\n"); 
405                    printObj(obj);
406                   )
407           cap->rCurrentTSO->what_next = ThreadEnterGHC;
408           iSp--; StackWord(0) = (W_)obj;
409           RETURN(ThreadYielding);
410        }
411     } /* switch on object kind */
412
413     barf("fallen off end of object-type switch in interpretBCO()");
414 }
415
416 #endif /* GHCI */