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