File:  [gforth] / gforth / engine / engine.c
Revision 1.10: download - view: text, annotated - select for diffs
Fri Jan 8 16:58:31 1999 UTC (25 years, 3 months ago) by anton
Branches: MAIN
CVS tags: HEAD
there is now a debugging version of the engine that maintains ip and
rp in global variables (to allow backtrace on signals). The debugging
engine is called gforth and the original engine is called gforth-fast.

    1: /* Gforth virtual machine (aka inner interpreter)
    2: 
    3:   Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
    4: 
    5:   This file is part of Gforth.
    6: 
    7:   Gforth is free software; you can redistribute it and/or
    8:   modify it under the terms of the GNU General Public License
    9:   as published by the Free Software Foundation; either version 2
   10:   of the License, or (at your option) any later version.
   11: 
   12:   This program is distributed in the hope that it will be useful,
   13:   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:   GNU General Public License for more details.
   16: 
   17:   You should have received a copy of the GNU General Public License
   18:   along with this program; if not, write to the Free Software
   19:   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   20: */
   21: 
   22: #include "config.h"
   23: #include <ctype.h>
   24: #include <stdio.h>
   25: #include <string.h>
   26: #include <math.h>
   27: #include <assert.h>
   28: #include <stdlib.h>
   29: #include <errno.h>
   30: #include "forth.h"
   31: #include "io.h"
   32: #include "threaded.h"
   33: #ifndef STANDALONE
   34: #include <sys/types.h>
   35: #include <sys/stat.h>
   36: #include <fcntl.h>
   37: #include <time.h>
   38: #include <sys/time.h>
   39: #include <unistd.h>
   40: #include <pwd.h>
   41: #else
   42: #include "systypes.h"
   43: #endif
   44: 
   45: #if defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) /* what else? */
   46: #include <dlfcn.h>
   47: #endif
   48: #if defined(_WIN32)
   49: #include <windows.h>
   50: #endif
   51: #ifdef hpux
   52: #include <dl.h>
   53: #endif
   54: 
   55: #ifndef SEEK_SET
   56: /* should be defined in stdio.h, but some systems don't have it */
   57: #define SEEK_SET 0
   58: #endif
   59: 
   60: #define IOR(flag)	((flag)? -512-errno : 0)
   61: 
   62: struct F83Name {
   63:   struct F83Name *next;  /* the link field for old hands */
   64:   char		countetc;
   65:   char		name[0];
   66: };
   67: 
   68: /* are macros for setting necessary? */
   69: #define F83NAME_COUNT(np)	((np)->countetc & 0x1f)
   70: #define F83NAME_SMUDGE(np)	(((np)->countetc & 0x40) != 0)
   71: #define F83NAME_IMMEDIATE(np)	(((np)->countetc & 0x20) != 0)
   72: 
   73: Cell *SP;
   74: Float *FP;
   75: Address UP=NULL;
   76: 
   77: #if 0
   78: /* not used currently */
   79: int emitcounter;
   80: #endif
   81: #define NULLC '\0'
   82: 
   83: #ifdef HAS_FILE
   84: char *cstr(Char *from, UCell size, int clear)
   85: /* return a C-string corresponding to the Forth string ( FROM SIZE ).
   86:    the C-string lives until the next call of cstr with CLEAR being true */
   87: {
   88:   static struct cstr_buffer {
   89:     char *buffer;
   90:     size_t size;
   91:   } *buffers=NULL;
   92:   static int nbuffers=0;
   93:   static int used=0;
   94:   struct cstr_buffer *b;
   95: 
   96:   if (buffers==NULL)
   97:     buffers=malloc(0);
   98:   if (clear)
   99:     used=0;
  100:   if (used>=nbuffers) {
  101:     buffers=realloc(buffers,sizeof(struct cstr_buffer)*(used+1));
  102:     buffers[used]=(struct cstr_buffer){malloc(0),0};
  103:     nbuffers=used+1;
  104:   }
  105:   b=&buffers[used];
  106:   if (size+1 > b->size) {
  107:     b->buffer = realloc(b->buffer,size+1);
  108:     b->size = size+1;
  109:   }
  110:   memcpy(b->buffer,from,size);
  111:   b->buffer[size]='\0';
  112:   used++;
  113:   return b->buffer;
  114: }
  115: 
  116: char *tilde_cstr(Char *from, UCell size, int clear)
  117: /* like cstr(), but perform tilde expansion on the string */
  118: {
  119:   char *s1,*s2;
  120:   int s1_len, s2_len;
  121:   struct passwd *getpwnam (), *user_entry;
  122: 
  123:   if (size<1 || from[0]!='~')
  124:     return cstr(from, size, clear);
  125:   if (size<2 || from[1]=='/') {
  126:     s1 = (char *)getenv ("HOME");
  127:     if(s1 == NULL)
  128:       s1 = "";
  129:     s2 = from+1;
  130:     s2_len = size-1;
  131:   } else {
  132:     UCell i;
  133:     for (i=1; i<size && from[i]!='/'; i++)
  134:       ;
  135:     {
  136:       char user[i];
  137:       memcpy(user,from+1,i-1);
  138:       user[i-1]='\0';
  139:       user_entry=getpwnam(user);
  140:     }
  141:     if (user_entry==NULL)
  142:       return cstr(from, size, clear);
  143:     s1 = user_entry->pw_dir;
  144:     s2 = from+i;
  145:     s2_len = size-i;
  146:   }
  147:   s1_len = strlen(s1);
  148:   if (s1_len>1 && s1[s1_len-1]=='/')
  149:     s1_len--;
  150:   {
  151:     char path[s1_len+s2_len];
  152:     memcpy(path,s1,s1_len);
  153:     memcpy(path+s1_len,s2,s2_len);
  154:     return cstr(path,s1_len+s2_len,clear);
  155:   }
  156: }
  157: #endif
  158: 
  159: #define NEWLINE	'\n'
  160: 
  161: #ifndef HAVE_RINT
  162: #define rint(x)	floor((x)+0.5)
  163: #endif
  164: 
  165: #ifdef HAS_FILE
  166: static char* fileattr[6]={"r","rb","r+","r+b","w","wb"};
  167: 
  168: #ifndef O_BINARY
  169: #define O_BINARY 0
  170: #endif
  171: #ifndef O_TEXT
  172: #define O_TEXT 0
  173: #endif
  174: 
  175: static int ufileattr[6]= {
  176:   O_RDONLY|O_TEXT, O_RDONLY|O_BINARY,
  177:   O_RDWR  |O_TEXT, O_RDWR  |O_BINARY,
  178:   O_WRONLY|O_TEXT, O_WRONLY|O_BINARY };
  179: #endif
  180: 
  181: /* if machine.h has not defined explicit registers, define them as implicit */
  182: #ifndef IPREG
  183: #define IPREG
  184: #endif
  185: #ifndef SPREG
  186: #define SPREG
  187: #endif
  188: #ifndef RPREG
  189: #define RPREG
  190: #endif
  191: #ifndef FPREG
  192: #define FPREG
  193: #endif
  194: #ifndef LPREG
  195: #define LPREG
  196: #endif
  197: #ifndef CFAREG
  198: #define CFAREG
  199: #endif
  200: #ifndef UPREG
  201: #define UPREG
  202: #endif
  203: #ifndef TOSREG
  204: #define TOSREG
  205: #endif
  206: #ifndef FTOSREG
  207: #define FTOSREG
  208: #endif
  209: 
  210: #ifndef CPU_DEP1
  211: # define CPU_DEP1 0
  212: #endif
  213: 
  214: /* declare and compute cfa for certain threading variants */
  215: /* warning: this is nonsyntactical; it will not work in place of a statement */
  216: #ifdef CFA_NEXT
  217: #define DOCFA
  218: #else
  219: #define DOCFA	Xt cfa; GETCFA(cfa)
  220: #endif
  221: 
  222: #ifdef GFORTH_DEBUGGING
  223: /* define some VM registers as global variables, so they survive exceptions;
  224:    global register variables are not up to the task (according to the 
  225:    GNU C manual) */
  226: Xt *ip;
  227: Cell *rp;
  228: #endif
  229: 
  230: Label *engine(Xt *ip0, Cell *sp0, Cell *rp0, Float *fp0, Address lp0)
  231: /* executes code at ip, if ip!=NULL
  232:    returns array of machine code labels (for use in a loader), if ip==NULL
  233: */
  234: {
  235: #ifndef GFORTH_DEBUGGING
  236:   register Xt *ip IPREG;
  237:   register Cell *rp RPREG;
  238: #endif
  239:   register Cell *sp SPREG = sp0;
  240:   register Float *fp FPREG = fp0;
  241:   register Address lp LPREG = lp0;
  242: #ifdef CFA_NEXT
  243:   register Xt cfa CFAREG;
  244: #endif
  245:   register Address up UPREG = UP;
  246:   IF_TOS(register Cell TOS TOSREG;)
  247:   IF_FTOS(register Float FTOS FTOSREG;)
  248: #if defined(DOUBLY_INDIRECT)
  249:   static Label *symbols;
  250:   static void *routines[]= {
  251: #else /* !defined(DOUBLY_INDIRECT) */
  252:   static Label symbols[]= {
  253: #endif /* !defined(DOUBLY_INDIRECT) */
  254:     (Label)&&docol,
  255:     (Label)&&docon,
  256:     (Label)&&dovar,
  257:     (Label)&&douser,
  258:     (Label)&&dodefer,
  259:     (Label)&&dofield,
  260:     (Label)&&dodoes,
  261:     /* the following entry is normally unused;
  262:        it's there because its index indicates a does-handler */
  263:     CPU_DEP1,
  264: #include "prim_lab.i"
  265:     (Label)0
  266:   };
  267: #ifdef CPU_DEP2
  268:   CPU_DEP2
  269: #endif
  270: 
  271:   ip = ip0;
  272:   rp = rp0;
  273: #ifdef DEBUG
  274:   fprintf(stderr,"ip=%x, sp=%x, rp=%x, fp=%x, lp=%x, up=%x\n",
  275:           (unsigned)ip,(unsigned)sp,(unsigned)rp,
  276: 	  (unsigned)fp,(unsigned)lp,(unsigned)up);
  277: #endif
  278: 
  279:   if (ip == NULL) {
  280: #if defined(DOUBLY_INDIRECT)
  281: #define MAX_SYMBOLS (sizeof(routines)/sizeof(routines[0]))
  282: #define CODE_OFFSET (22*sizeof(Cell))
  283:     int i;
  284:     Cell code_offset = offset_image? CODE_OFFSET : 0;
  285: 
  286:     symbols = (Label *)(malloc(MAX_SYMBOLS*sizeof(Cell)+CODE_OFFSET)+code_offset);
  287:     for (i=0; i<DOESJUMP+1; i++)
  288:       symbols[i] = (Label)routines[i];
  289:     for (; routines[i]!=0; i++) {
  290:       if (i>=MAX_SYMBOLS) {
  291: 	fprintf(stderr,"gforth-ditc: more than %d primitives\n",MAX_SYMBOLS);
  292: 	exit(1);
  293:     }
  294:     symbols[i] = &routines[i];
  295:   }
  296: #endif /* defined(DOUBLY_INDIRECT) */
  297:   return symbols;
  298: }
  299: 
  300:   IF_TOS(TOS = sp[0]);
  301:   IF_FTOS(FTOS = fp[0]);
  302: /*  prep_terminal(); */
  303:   NEXT_P0;
  304:   NEXT;
  305: 
  306: #ifdef CPU_DEP3
  307:   CPU_DEP3
  308: #endif
  309:   
  310:  docol:
  311:   {
  312:     DOCFA;
  313: #ifdef DEBUG
  314:     fprintf(stderr,"%08lx: col: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
  315: #endif
  316: #ifdef CISC_NEXT
  317:     /* this is the simple version */
  318:     *--rp = (Cell)ip;
  319:     ip = (Xt *)PFA1(cfa);
  320:     NEXT_P0;
  321:     NEXT;
  322: #else
  323:     /* this one is important, so we help the compiler optimizing
  324:        The following version may be better (for scheduling), but probably has
  325:        problems with code fields employing calls and delay slots
  326:        */
  327:     {
  328:       DEF_CA
  329:       Xt *current_ip = (Xt *)PFA1(cfa);
  330:       cfa = *current_ip;
  331:       NEXT1_P1;
  332:       *--rp = (Cell)ip;
  333:       ip = current_ip+1;
  334:       NEXT1_P2;
  335:     }
  336: #endif
  337:   }
  338: 
  339:  docon:
  340:   {
  341:     DOCFA;
  342: #ifdef DEBUG
  343:     fprintf(stderr,"%08lx: con: %08lx\n",(Cell)ip,*(Cell*)PFA1(cfa));
  344: #endif
  345: #ifdef USE_TOS
  346:     *sp-- = TOS;
  347:     TOS = *(Cell *)PFA1(cfa);
  348: #else
  349:     *--sp = *(Cell *)PFA1(cfa);
  350: #endif
  351:   }
  352:   NEXT_P0;
  353:   NEXT;
  354:   
  355:  dovar:
  356:   {
  357:     DOCFA;
  358: #ifdef DEBUG
  359:     fprintf(stderr,"%08lx: var: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
  360: #endif
  361: #ifdef USE_TOS
  362:     *sp-- = TOS;
  363:     TOS = (Cell)PFA1(cfa);
  364: #else
  365:     *--sp = (Cell)PFA1(cfa);
  366: #endif
  367:   }
  368:   NEXT_P0;
  369:   NEXT;
  370:   
  371:  douser:
  372:   {
  373:     DOCFA;
  374: #ifdef DEBUG
  375:     fprintf(stderr,"%08lx: user: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
  376: #endif
  377: #ifdef USE_TOS
  378:     *sp-- = TOS;
  379:     TOS = (Cell)(up+*(Cell*)PFA1(cfa));
  380: #else
  381:     *--sp = (Cell)(up+*(Cell*)PFA1(cfa));
  382: #endif
  383:   }
  384:   NEXT_P0;
  385:   NEXT;
  386:   
  387:  dodefer:
  388:   {
  389:     DOCFA;
  390: #ifdef DEBUG
  391:     fprintf(stderr,"%08lx: defer: %08lx\n",(Cell)ip,*(Cell*)PFA1(cfa));
  392: #endif
  393:     EXEC(*(Xt *)PFA1(cfa));
  394:   }
  395: 
  396:  dofield:
  397:   {
  398:     DOCFA;
  399: #ifdef DEBUG
  400:     fprintf(stderr,"%08lx: field: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
  401: #endif
  402:     TOS += *(Cell*)PFA1(cfa); 
  403:   }
  404:   NEXT_P0;
  405:   NEXT;
  406: 
  407:  dodoes:
  408:   /* this assumes the following structure:
  409:      defining-word:
  410:      
  411:      ...
  412:      DOES>
  413:      (possible padding)
  414:      possibly handler: jmp dodoes
  415:      (possible branch delay slot(s))
  416:      Forth code after DOES>
  417:      
  418:      defined word:
  419:      
  420:      cfa: address of or jump to handler OR
  421:           address of or jump to dodoes, address of DOES-code
  422:      pfa:
  423:      
  424:      */
  425:   {
  426:     DOCFA;
  427: 
  428:     /*    fprintf(stderr, "Got CFA %08lx at doescode %08lx/%08lx: does: %08lx\n",cfa,(Cell)ip,(Cell)PFA(cfa),(Cell)DOES_CODE1(cfa));*/
  429: #ifdef DEBUG
  430:     fprintf(stderr,"%08lx/%08lx: does: %08lx\n",(Cell)ip,(Cell)PFA(cfa),(Cell)DOES_CODE1(cfa));
  431:     fflush(stderr);
  432: #endif
  433:     *--rp = (Cell)ip;
  434:     /* PFA1 might collide with DOES_CODE1 here, so we use PFA */
  435:     ip = DOES_CODE1(cfa);
  436: #ifdef USE_TOS
  437:     *sp-- = TOS;
  438:     TOS = (Cell)PFA(cfa);
  439: #else
  440:     *--sp = (Cell)PFA(cfa);
  441: #endif
  442:     /*    fprintf(stderr,"TOS = %08lx, IP=%08lx\n", TOS, IP);*/
  443:   }
  444:   NEXT_P0;
  445:   NEXT;
  446: 
  447: #include "prim.i"
  448: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>