home *** CD-ROM | disk | FTP | other *** search
- /* The bytecode interpreter */
-
- #include <math.h>
- #include "alloc.h"
- #include "debugger.h"
- #include "fail.h"
- #include "instruct.h"
- #include "memory.h"
- #include "minor_gc.h"
- #include "misc.h"
- #include "mlvalues.h"
- #include "prims.h"
- #include "signals.h"
- #include "stacks.h"
- #include "str.h"
- #include "unalignd.h"
- #ifdef HAS_UI
- #include "ui.h"
- #endif
-
- #ifdef DEBUG
- static long icount = 0;
- static void stop_here () {}
- #endif
-
- /* Registers for the abstract machine:
- pc the code pointer
- sp the stack pointer (grows downward)
- accu the accumulator
- env heap-allocated environment
- trapsp pointer to the current trap frame
- extra_args number of extra arguments provided by the caller
-
- sp is a local copy of the global variable extern_sp. */
-
- extern code_t start_code;
-
- typedef unsigned char opcode_t;
-
- /* Other viewpoints on pc (to read immediate operands) */
-
- #define SHORT (sizeof(short))
- #define LONG (sizeof(int32))
- #define DOUBLE (sizeof(double))
-
- #define s16pc s16(pc)
- #define u16pc u16(pc)
- #define s32pc s32(pc)
- #define u32pc u32(pc)
-
- /* The empty environment */
-
- #define null_env Atom(0)
-
- /* Code for returning from the signal handler */
-
- unsigned char return_from_interrupt[] = { ACC0, RETURN, 1 };
-
- /* GC interface */
-
- #define Setup_for_gc { sp -= 2; sp[0] = accu; sp[1] = env; extern_sp = sp; }
- #define Restore_after_gc { accu = sp[0]; env = sp[1]; sp += 2; }
- #define Setup_for_c_call { *--sp = env; extern_sp = sp; }
- #define Restore_after_c_call { sp = extern_sp; env = *sp++; }
-
- /* GCC 2.0 has labels as first-class values. We take advantage of that
- to provide faster dispatch than the "switch" statement. */
-
- #if defined(__GNUC__) && __GNUC__ >= 2 && !defined(DEBUG)
- #define DIRECT_JUMP
- #endif
-
- /* The interpreter itself */
-
- value interprete(prog)
- code_t prog;
- {
-
- /* Declarations for the registers of the abstract machine.
- The most heavily used registers come first.
- For reasonable performance, "pc" MUST reside in a register.
- Many ``optimizing'' compilers underestimate the importance of "pc",
- and don't put it in a register.
- For GCC users, I've hand-assigned registers for some architectures. */
-
- #if defined(__GNUC__) && defined(sparc)
- register code_t pc asm("%l0");
- register value accu asm("%l1");
- register value * sp asm("%l2");
- #else
- #if defined(__GNUC__) && defined(mc68000)
- register code_t pc asm("a5");
- register value accu;
- register value * sp;
- #else
- #if defined(__GNUC__) && defined(mips)
- register code_t pc asm("$20");
- register value accu asm("$21");
- register value * sp asm("$22");
- #else
- #if defined(__GNUC__) && defined(__alpha__)
- register code_t pc asm("$11");
- register value accu asm("$12");
- register value * sp asm("$13");
- #else
- #if defined(__GNUC__) && defined(hppa)
- register code_t pc asm("%r11");
- register value accu asm("%r12");
- register value * sp asm("%r13");
- #else
- #if defined(__GNUC__) && defined(i386)
- #if defined(MSDOS)
- register code_t pc asm("si");
- register value * sp asm("di");
- #else
- register code_t pc asm("%esi");
- register value * sp asm("%edi");
- #endif
- register value accu;
- #else
- register code_t pc;
- register value accu;
- register value * sp;
- #endif
- #endif
- #endif
- #endif
- #endif
- #endif
-
- value env;
- int extra_args;
- struct longjmp_buffer * initial_external_raise;
- int initial_sp_offset;
- value * initial_c_roots_head;
- struct longjmp_buffer raise_buf;
- value * modify_dest, modify_newval;
- value tmp;
- int last_instr, cur_instr;
-
- #ifdef DIRECT_JUMP
- static void * jumptable[] = {
- # include "jumptbl.h"
- };
- #endif
-
- double dtmp;
-
- /* #define FREQONE */
-
- #ifdef FREQONE
- long freqtable[256];
- #include "opnames.h"
- {
- int i;
- for (i=0; i<256; i++)
- freqtable[i] = 0;
- }
- #define INCRFREQ(instr1,instr2) freqtable[instr2]++;
- #define DUMPTABLE \
- { \
- int i; \
- printf("\n\n"); \
- for (i=0; i<256; i++) \
- if (freqtable[i]) \
- printf("%.8d %s\n", freqtable[i], \
- names_of_instructions[i]); \
- }
- #else
- #ifdef FREQTWO
- long freqtable[256][256];
- #include "opnames.h"
- {
- int i1, i2;
- for (i1=0; i1<256; i1++)
- for (i2=0; i2<256; i2++)
- freqtable[i1][i2] = 0;
- last_instr = 0;
- }
-
- #define INCRFREQ(instr1,instr2) \
- freqtable[instr1][instr2]++; \
- last_instr = cur_instr;
-
- #define DUMPTABLE \
- { \
- int i1, i2; \
- printf("\n\n"); \
- for (i1=0; i1<256; i1++) \
- for (i2=0; i2<256; i2++) \
- if (freqtable[i1][i2]) \
- printf("%.9d %s/%s\n", freqtable[i1][i2], \
- names_of_instructions[i1], \
- names_of_instructions[i2]); \
- }
- #else
- #define INCRFREQ(instr1,instr2) /* nothing */
- #define DUMPTABLE /* nothing */
- #endif
- #endif
-
- sp = extern_sp;
- pc = prog;
- extra_args = 0;
- env = null_env;
- accu = Val_long(0);
- initial_c_roots_head = c_roots_head;
- initial_sp_offset = stack_high - sp;
- initial_external_raise = external_raise;
-
- if (setjmp(raise_buf.buf)) {
- c_roots_head = initial_c_roots_head;
- accu = exn_bucket;
- goto raise_exception;
- }
- external_raise = &raise_buf;
-
- #ifdef DEBUG
- log_ptr = log_buffer;
- #endif
-
- #ifdef DIRECT_JUMP
- # define Instruct(name) lbl_##name
- # define Next cur_instr = *pc++; INCRFREQ(last_instr,cur_instr) \
- goto *jumptable[cur_instr]
- #else
- # define Instruct(name) case name
- # define Next break
- #endif
-
- #ifdef DIRECT_JUMP
- Next; /* Jump to the first instruction */
- #else
- while (1) {
- #ifdef DEBUG
- if (icount-- == 0) stop_here ();
- *log_ptr++ = pc;
- if (log_ptr >= log_buffer + LOG_BUFFER_SIZE) log_ptr = log_buffer;
- if (trace_flag) disasm_instr(pc);
- Assert(sp >= stack_low);
- Assert(sp <= stack_high);
- #endif
- cur_instr = *pc++;
- decode_instruction:
- switch (cur_instr) {
- #endif
-
- /* Basic stack operations */
-
- Instruct(SWAP):
- { value tmp = accu;
- accu = sp[0];
- sp[0] = tmp;
- Next;
- }
-
- Instruct(PUSH):
- Instruct(PUSHACC0): *--sp = accu; Next;
- Instruct(ACC0): accu = sp[0]; Next;
-
- Instruct(PUSHACC1): *--sp = accu; /* Fallthrough */
- Instruct(ACC1): accu = sp[1]; Next;
-
- Instruct(PUSHACC2): *--sp = accu; /* Fallthrough */
- Instruct(ACC2): accu = sp[2]; Next;
-
- Instruct(PUSHACC3): *--sp = accu; /* Fallthrough */
- Instruct(ACC3): accu = sp[3]; Next;
-
- Instruct(PUSHACC4): *--sp = accu; /* Fallthrough */
- Instruct(ACC4): accu = sp[4]; Next;
-
- Instruct(PUSHACC5): *--sp = accu; /* Fallthrough */
- Instruct(ACC5): accu = sp[5]; Next;
-
- Instruct(PUSHACC6): *--sp = accu; /* Fallthrough */
- Instruct(ACC6): accu = sp[6]; Next;
-
- Instruct(PUSHACC7): *--sp = accu; /* Fallthrough */
- Instruct(ACC7): accu = sp[7]; Next;
-
- Instruct(PUSHACC): *--sp = accu; /* Fallthrough */
- Instruct(ACCESS): accu = sp[*pc++]; Next;
-
- Instruct(POP):
- sp += *pc++;
- Next;
- Instruct(ASSIGN):
- sp[*pc++] = accu;
- accu = Val_unit;
- Next;
-
- /* Access in heap-allocated environment */
-
- Instruct(PUSHENV1): *--sp = accu; /* Fallthrough */
- Instruct(ENV1): accu = Field(env, 1); Next;
-
- Instruct(PUSHENV2): *--sp = accu; /* Fallthrough */
- Instruct(ENV2): accu = Field(env, 2); Next;
-
- Instruct(PUSHENV3): *--sp = accu; /* Fallthrough */
- Instruct(ENV3): accu = Field(env, 3); Next;
-
- Instruct(PUSHENV4): *--sp = accu; /* Fallthrough */
- Instruct(ENV4): accu = Field(env, 4); Next;
-
- Instruct(PUSHENV5): *--sp = accu; /* Fallthrough */
- Instruct(ENV5): accu = Field(env, 5); Next;
-
- Instruct(PUSHENV6): *--sp = accu; /* Fallthrough */
- Instruct(ENV6): accu = Field(env, 6); Next;
-
- Instruct(PUSHENV7): *--sp = accu; /* Fallthrough */
- Instruct(ENV7): accu = Field(env, 7); Next;
-
- Instruct(PUSHENVACC): *--sp = accu; /* Fallthrough */
- Instruct(ENVACC): accu = Field(env, *pc++); Next;
-
- Instruct(PUSH_ENV1_APPLY1):
- {
- sp -= 4;
- sp[0] = accu;
- sp[1] = (value)pc;
- sp[2] = env;
- sp[3] = Val_long(extra_args);
- extra_args = 0;
- accu = Field(env, 1);
- goto apply;
- }
-
- Instruct(PUSH_ENV1_APPLY2):
- { value arg2 = sp[0];
- sp -= 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = (value)pc;
- sp[3] = env;
- sp[4] = Val_long(extra_args);
- extra_args = 1;
- accu = Field(env, 1);
- goto apply;
- }
-
- Instruct(PUSH_ENV1_APPLY3):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- sp -= 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = (value)pc;
- sp[4] = env;
- sp[5] = Val_long(extra_args);
- extra_args = 2;
- accu = Field(env, 1);
- goto apply;
- }
-
- Instruct(PUSH_ENV1_APPLY4):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- value arg4 = sp[2];
- sp -= 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = arg4;
- sp[4] = (value)pc;
- sp[5] = env;
- sp[6] = Val_long(extra_args);
- extra_args = 3;
- accu = Field(env, 1);
- goto apply;
- }
-
- Instruct(PUSH_ENV1_APPTERM1):
- { sp = sp + *pc++ - 2;
- sp[0] = accu;
- } /* Fall through */
- env1_appterm:
- accu = Field(env, 1);
- appterm:
- pc = Code_val(accu);
- env = accu;
- goto check_signals;
-
- Instruct(PUSH_ENV1_APPTERM2):
- { value arg2 = sp[0];
- sp = sp + *pc++ - 3;
- sp[0] = accu;
- sp[1] = arg2;
- extra_args += 1;
- goto env1_appterm;
- }
-
- Instruct(PUSH_ENV1_APPTERM3):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- sp = sp + *pc++ - 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- extra_args += 2;
- goto env1_appterm;
- }
-
- Instruct(PUSH_ENV1_APPTERM4):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- value arg4 = sp[2];
- sp = sp + *pc++ - 5;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = arg4;
- extra_args += 3;
- goto env1_appterm;
- }
-
- /* Function application */
-
- Instruct(PUSH_RETADDR): {
- sp -= 3;
- sp[0] = (value) (pc + s16pc);
- sp[1] = env;
- sp[2] = Val_long(extra_args);
- pc += SHORT;
- Next;
- }
- Instruct(APPLY): {
- extra_args = *pc - 1;
- goto apply;
- }
- Instruct(APPLY1): {
- value arg1 = sp[0];
- sp -= 3;
- sp[0] = arg1;
- sp[1] = (value)pc;
- sp[2] = env;
- sp[3] = Val_long(extra_args);
- extra_args = 0;
- goto apply;
- }
- Instruct(APPLY2): {
- value arg1 = sp[0];
- value arg2 = sp[1];
- sp -= 3;
- sp[0] = arg1;
- sp[1] = arg2;
- sp[2] = (value)pc;
- sp[3] = env;
- sp[4] = Val_long(extra_args);
- extra_args = 1;
- goto apply;
- }
- Instruct(APPLY3): {
- value arg1 = sp[0];
- value arg2 = sp[1];
- value arg3 = sp[2];
- sp -= 3;
- sp[0] = arg1;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = (value)pc;
- sp[4] = env;
- sp[5] = Val_long(extra_args);
- extra_args = 2;
- goto apply;
- }
- Instruct(APPLY4): {
- value arg1 = sp[0];
- value arg2 = sp[1];
- value arg3 = sp[2];
- value arg4 = sp[3];
- sp -= 3;
- sp[0] = arg1;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = arg4;
- sp[4] = (value)pc;
- sp[5] = env;
- sp[6] = Val_long(extra_args);
- extra_args = 3;
- goto apply;
- }
-
- Instruct(APPTERM): {
- int nargs = *pc++;
- int slotsize = *pc++;
- value * newsp;
- int i;
- /* Slide the nargs bottom words of the current frame to the top
- of the frame, and discard the remainder of the frame */
- newsp = sp + slotsize - nargs;
- for (i = nargs - 1; i >= 0; i--) newsp[i] = sp[i];
- sp = newsp;
- extra_args += nargs - 1;
- goto appterm;
- }
- Instruct(APPTERM1): {
- value arg1 = sp[0];
- sp = sp + *pc++ - 1;
- sp[0] = arg1;
- goto appterm;
- }
- Instruct(APPTERM2): {
- value arg1 = sp[0];
- value arg2 = sp[1];
- sp = sp + *pc++ - 2;
- sp[0] = arg1;
- sp[1] = arg2;
- extra_args += 1;
- goto appterm;
- }
- Instruct(APPTERM3): {
- value arg1 = sp[0];
- value arg2 = sp[1];
- value arg3 = sp[2];
- sp = sp + *pc++ - 3;
- sp[0] = arg1;
- sp[1] = arg2;
- sp[2] = arg3;
- extra_args += 2;
- goto appterm;
- }
- Instruct(APPTERM4): {
- value arg1 = sp[0];
- value arg2 = sp[1];
- value arg3 = sp[2];
- value arg4 = sp[3];
- sp = sp + *pc++ - 4;
- sp[0] = arg1;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = arg4;
- extra_args += 3;
- goto appterm;
- }
-
- Instruct(RETURN1):
- sp += 1;
- return_code:
- if (extra_args > 0) {
- extra_args--;
- pc = Code_val(accu);
- env = accu;
- } else {
- pc = (code_t)(sp[0]);
- env = sp[1];
- extra_args = Long_val(sp[2]);
- sp += 3;
- if (something_to_do) goto process_signal;
- }
- Next;
-
- Instruct(RETURN2):
- sp += 2;
- goto return_code;
-
- Instruct(RETURN):
- sp += *pc++;
- goto return_code;
-
- Instruct(RESTART): {
- int num_args = Wosize_val(env) - 2;
- int i;
- sp -= num_args;
- for (i = 0; i < num_args; i++) sp[i] = Field(env, i + 2);
- env = Field(env, 1);
- extra_args += num_args;
- Next;
- }
-
- Instruct(GRAB): {
- int required = *pc++;
- if (extra_args >= required) {
- extra_args -= required;
- } else {
- mlsize_t num_args, i;
- num_args = 1 + extra_args; /* arg1 + extra args */
- Alloc_small(accu, num_args + 2, Closure_tag);
- Field(accu, 1) = env;
- for (i = 0; i < num_args; i++) Field(accu, i + 2) = sp[i];
- Code_val(accu) = pc - 3; /* Point to the preceding RESTART instr. */
- sp += num_args;
- pc = (code_t)(sp[0]);
- env = sp[1];
- extra_args = Long_val(sp[2]);
- sp += 3;
- }
- Next;
- }
-
- Instruct(CLOSURE): {
- int nvars = *pc++;
- int i;
- if (nvars > 0) *--sp = accu;
- Alloc_small(accu, 1 + nvars, Closure_tag);
- Code_val(accu) = pc + s16pc;
- for (i = 0; i < nvars; i++) Field(accu, i + 1) = sp[i];
- sp += nvars;
- pc += SHORT;
- Next;
- }
-
- Instruct(CLOSREC): {
- int nvars = *pc++;
- int i;
- if (nvars > 0) *--sp = accu;
- Alloc_small(accu, 2 + nvars, Closure_tag);
- Code_val(accu) = pc + s16pc;
- Field(accu, 1) = Val_int(0);
- for (i = 0; i < nvars; i++) Field(accu, i + 2) = sp[i];
- sp += nvars;
- modify(&Field(accu, 1), accu);
- pc += SHORT;
- Next;
- }
-
- /* For recursive definitions */
-
- Instruct(DUMMY): {
- int size = *pc++ + 1; /* size + 1 to match CLOSURE */
- Alloc_small(accu, size, 0);
- while (size--) Field(accu, size) = Val_long(0);
- Next;
- }
- Instruct(UPDATE): {
- value newval = *sp++;
- mlsize_t size, n;
- size = Wosize_val(newval);
- Assert(size == Wosize_val(accu));
- Tag_val(accu) = Tag_val(newval);
- for (n = 0; n < size; n++) {
- modify(&Field(accu, n), Field(newval, n));
- }
- accu = Val_unit;
- Next;
- }
-
- /* Globals */
-
- Instruct(PUSH_GETGLOBAL):
- *--sp = accu;
- /* Fallthrough */
- Instruct(GETGLOBAL):
- accu = Field(global_data, u16pc);
- pc += SHORT;
- Next;
-
- Instruct(PUSH_GETGLOBAL_APPLY1):
- { sp -= 4;
- sp[0] = accu;
- accu = Field(global_data, u16pc);
- pc += SHORT;
- sp[1] = (value)pc;
- sp[2] = env;
- sp[3] = Val_long(extra_args);
- extra_args = 0;
- }
- apply:
- pc = Code_val(accu);
- env = accu;
- /* Fall through to stack check */
-
- check_stacks:
- if (sp < stack_threshold) {
- extern_sp = sp;
- realloc_stack();
- sp = extern_sp;
- }
- /* Fall through to signals check */
-
- check_signals:
-
- Instruct(CHECK_SIGNALS): /* accu not preserved */
- #ifdef PERIODIC_ACTION_FREQ
- { static int periodic_action_count = 1;
- if (--periodic_action_count == 0) {
- periodic_action_count = PERIODIC_ACTION_FREQ;
- ui_periodic_action();
- }
- }
- #endif
- #ifdef macintosh
- #ifndef __MWERKS__
- { static int spin_count = 1;
- if (--spin_count == 0) { spin_count = 24; SpinCursor ((short) 1); }
- }
- #endif
- #endif
- #if defined(MSDOS) && defined(__GNUC__)
- { static int poll_count = 1;
- if (--poll_count == 0) { poll_count = 500; poll_break(); }
- }
- #endif
- if (something_to_do) goto process_signal;
- Next;
-
- Instruct(PUSH_GETGLOBAL_APPLY2):
- { value arg2 = sp[0];
- sp -= 4;
- sp[0] = accu;
- sp[1] = arg2;
- accu = Field(global_data, u16pc);
- pc += SHORT;
- sp[2] = (value)pc;
- sp[3] = env;
- sp[4] = Val_long(extra_args);
- extra_args = 1;
- goto apply;
- }
-
- Instruct(PUSH_GETGLOBAL_APPLY3):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- sp -= 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- accu = Field(global_data, u16pc);
- pc += SHORT;
- sp[3] = (value)pc;
- sp[4] = env;
- sp[5] = Val_long(extra_args);
- extra_args = 2;
- goto apply;
- }
- Instruct(PUSH_GETGLOBAL_APPLY4):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- value arg4 = sp[2];
- sp -= 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = arg4;
- accu = Field(global_data, u16pc);
- pc += SHORT;
- sp[4] = (value)pc;
- sp[5] = env;
- sp[6] = Val_long(extra_args);
- extra_args = 3;
- goto apply;
- }
-
- Instruct(PUSH_GETGLOBAL_APPTERM1):
- /* opcode, popnbr, globalindex */
- sp = sp + *pc++ - 2;
- sp[0] = accu;
- getglobal_appterm:
- accu = Field(global_data, u16pc);
- pc = Code_val(accu);
- env = accu;
- goto check_signals;
-
- Instruct(PUSH_GETGLOBAL_APPTERM2):
- { value arg2 = sp[0];
- sp = sp + *pc++ - 3;
- sp[0] = accu;
- sp[1] = arg2;
- extra_args += 1;
- goto getglobal_appterm;
- }
-
- Instruct(PUSH_GETGLOBAL_APPTERM3):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- sp = sp + *pc++ - 4;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- extra_args += 2;
- goto getglobal_appterm;
- }
-
- Instruct(PUSH_GETGLOBAL_APPTERM4):
- { value arg2 = sp[0];
- value arg3 = sp[1];
- value arg4 = sp[2];
- sp = sp + *pc++ - 5;
- sp[0] = accu;
- sp[1] = arg2;
- sp[2] = arg3;
- sp[3] = arg4;
- extra_args += 3;
- goto getglobal_appterm;
- }
-
- Instruct(SETGLOBAL):
- modify(&Field(global_data, u16pc), accu);
- accu = Val_unit; /* ? */
- pc += SHORT;
- Next;
-
- /* Allocation of blocks */
-
- Instruct(PUSHATOM0):
- *--sp = accu;
- /* Fallthrough */
- Instruct(ATOM0):
- accu = Atom(0); Next;
-
- Instruct(ATOM1):
- accu = Atom(1); Next;
- Instruct(ATOM2):
- accu = Atom(2); Next;
- Instruct(ATOM3):
- accu = Atom(3); Next;
- Instruct(ATOM4):
- accu = Atom(4); Next;
- Instruct(ATOM5):
- accu = Atom(5); Next;
- Instruct(ATOM6):
- accu = Atom(6); Next;
- Instruct(ATOM7):
- accu = Atom(7); Next;
- Instruct(ATOM8):
- accu = Atom(8); Next;
- Instruct(ATOM9):
- accu = Atom(9); Next;
-
- Instruct(PUSHATOM):
- *--sp = accu;
- /* Fallthrough */
- Instruct(ATOM):
- accu = Atom(*pc++); Next;
-
- Instruct(MAKEBLOCK):
- { header_t hdr;
- mlsize_t size;
- tag_t tag;
- int i;
-
- hdr = u32pc;
- pc += LONG;
- size = Wosize_hd(hdr);
- tag = Tag_hd(hdr);
- if (size < Max_young_wosize) {
- Alloc_small(tmp, size, tag);
- Field(tmp, size-1) = accu;
- for (i = size-2; i >= 0; i--) Field(tmp, i) = *sp++;
- accu = tmp;
- } else {
- Setup_for_gc;
- tmp = alloc_shr (size, tag);
- Restore_after_gc;
- initialize (&Field(tmp, size-1), accu);
- for (i = size-2; i >= 0; i--) initialize (&Field(tmp, i), *sp++);
- accu = tmp;
- }
- Next;
- }
-
- Instruct(MAKEBLOCK1): {
- tag_t tag = *pc++;
- value block;
- Alloc_small(block, 1, tag);
- Field(block, 0) = accu;
- accu = block;
- Next;
- }
- Instruct(MAKEBLOCK2): {
- tag_t tag = *pc++;
- value block;
- Alloc_small(block, 2, tag);
- Field(block, 0) = sp[0];
- Field(block, 1) = accu;
- sp += 1;
- accu = block;
- Next;
- }
- Instruct(MAKEBLOCK3): {
- tag_t tag = *pc++;
- value block;
- Alloc_small(block, 3, tag);
- Field(block, 0) = sp[1];
- Field(block, 1) = sp[0];
- Field(block, 2) = accu;
- sp += 2;
- accu = block;
- Next;
- }
- Instruct(MAKEBLOCK4): {
- tag_t tag = *pc++;
- value block;
- Alloc_small(block, 4, tag);
- Field(block, 0) = sp[2];
- Field(block, 1) = sp[1];
- Field(block, 2) = sp[0];
- Field(block, 3) = accu;
- sp += 3;
- accu = block;
- Next;
- }
-
- /* Access to components of blocks */
-
- Instruct(GETFIELD0):
- accu = Field(accu, 0); Next;
- Instruct(GETFIELD1):
- accu = Field(accu, 1); Next;
- Instruct(GETFIELD2):
- accu = Field(accu, 2); Next;
- Instruct(GETFIELD3):
- accu = Field(accu, 3); Next;
- Instruct(GETFIELD):
- accu = Field(accu, u16pc); pc += SHORT; Next;
-
- Instruct(GETFIELD0_0):
- accu = Field(accu, 0);
- accu = Field(accu, 0);
- Next;
-
- Instruct(GETFIELD0_1):
- accu = Field(accu, 0);
- accu = Field(accu, 1);
- Next;
-
- Instruct(GETFIELD1_0):
- accu = Field(accu, 1);
- accu = Field(accu, 0);
- Next;
-
- Instruct(GETFIELD1_1):
- accu = Field(accu, 1);
- accu = Field(accu, 1);
- Next;
-
- Instruct(SETFIELD0):
- modify_dest = &Field(*sp++, 0);
- modify_newval = accu;
- modify:
- Modify(modify_dest, modify_newval);
- accu = Val_unit; /* Atom(0); */
- Next;
- Instruct(SETFIELD1):
- modify_dest = &Field(*sp++, 1);
- modify_newval = accu;
- goto modify;
- Instruct(SETFIELD2):
- modify_dest = &Field(*sp++, 2);
- modify_newval = accu;
- goto modify;
- Instruct(SETFIELD3):
- modify_dest = &Field(*sp++, 3);
- modify_newval = accu;
- goto modify;
- Instruct(SETFIELD):
- modify_dest = &Field(*sp++, u16pc);
- pc += SHORT;
- modify_newval = accu;
- goto modify;
-
- /* Array operations */
-
- Instruct(VECTLENGTH):
- accu = Val_long(Wosize_val(accu));
- Next;
- Instruct(GETVECTITEM):
- accu = Field(sp[0], Long_val(accu));
- sp += 1;
- Next;
- Instruct(SETVECTITEM):
- modify_dest = &Field(sp[1], Long_val(sp[0]));
- modify_newval = accu;
- sp += 2;
- goto modify;
-
- /* String operations */
-
- Instruct(GETSTRINGCHAR):
- accu = Val_int(Byte_u(sp[0], Long_val(accu)));
- sp += 1;
- Next;
- Instruct(SETSTRINGCHAR):
- Byte_u(sp[1], Long_val(sp[0])) = Int_val(accu);
- accu = Atom(0);
- sp += 2;
- Next;
-
- /* Branches and conditional branches */
-
- #define branch() pc += s16pc
-
- Instruct(BRANCH):
- branch(); Next;
- Instruct(BRANCHIF):
- if (Tag_val(accu) != 0) branch(); else pc += SHORT;
- Next;
- Instruct(BRANCHIFNOT):
- if (Tag_val(accu) == 0) branch(); else pc += SHORT;
- Next;
- Instruct(POPBRANCHIFNOT):
- tmp = accu;
- accu = *sp++;
- if (Tag_val(tmp) == 0) branch(); else pc += SHORT;
- Next;
- Instruct(BRANCHIFNEQTAG):
- if (Tag_val(accu) != *pc++) branch(); else pc += SHORT;
- Next;
- Instruct(SWITCH):
- Assert(Long_val(accu) >= 0 && Long_val(accu) < *pc);
- pc++;
- pc += s16(pc + accu - 1);
- Next;
- Instruct(BOOLNOT):
- accu = Atom(Tag_val(accu) == 0); Next;
-
-
- /* Exceptions */
-
- Instruct(PUSHTRAP):
- sp -= 4;
- Trap_pc(sp) = pc + s16pc;
- Trap_link(sp) = trapsp;
- sp[2] = env;
- sp[3] = Val_long(extra_args);
- trapsp = sp;
- pc += SHORT;
- Next;
-
- Instruct(POPTRAP):
- /* We should check here if a signal is pending, to preserve the
- semantics of the program w.r.t. exceptions. Unfortunately,
- process_signal destroys the accumulator, and there is no
- convenient way to preserve it... */
- trapsp = Trap_link(sp);
- sp += 4;
- Next;
-
- raise_exception: /* An external raise jumps here */
-
- Instruct(RAISE): /* arg */
- sp = trapsp;
- if (sp >= stack_high - initial_sp_offset) {
- exn_bucket = accu;
- external_raise = initial_external_raise;
- longjmp(external_raise->buf, 1);
- }
- pc = Trap_pc(sp);
- trapsp = Trap_link(sp);
- env = sp[2];
- extra_args = Long_val(sp[3]);
- sp += 4;
- Next;
-
- process_signal:
- something_to_do = 0;
- if (force_minor_flag){
- force_minor_flag = 0;
- Setup_for_gc;
- minor_collection ();
- Restore_after_gc;
- }
- /* If a signal arrives between the following two instructions,
- it will be lost. */
- { int signal_number = signal_is_pending;
- signal_is_pending = 0;
- if (signal_number) {
- /* e -- to save accu, why not?:
- sp -= 8;
- sp[0] = Val_int(signal_number);
- sp[1] = (value) return_from_interrupt;
- sp[2] = Atom(0);
- sp[3] = 0;
- sp[4] = accu;
- sp[5] = (value) pc;
- sp[6] = env;
- sp[7] = Val_long(extra_args);
- instead of...
- */
- /* Push a return frame to the current code location */
- sp -= 4;
- sp[0] = Val_int(signal_number);
- sp[1] = (value) pc;
- sp[2] = env;
- sp[3] = Val_long(extra_args);
- /* Branch to the signal handler */
- /* e -- signal_handler should be a closure, but isn't in 1.31.
- env = (value )signal_handler; // env = Field(signal_handlers, signal_number);
- pc = Code_val(env);
- I'm lazy, so for now... */
- env = null_env;
- pc = signal_handler;
- /* */
- extra_args = 0;
- }
- }
- Next;
-
- /* Calling C functions */
-
- Instruct(C_CALL1):
- Setup_for_c_call;
- accu = (cprim[u16pc])(accu);
- Restore_after_c_call;
- pc += SHORT;
- Next;
- Instruct(C_CALL2):
- Setup_for_c_call;
- /* sp[0] temporarily holds the environment pointer */
- accu = (cprim[u16pc])(sp[1], accu);
- Restore_after_c_call;
- pc += SHORT;
- sp += 1;
- Next;
- Instruct(C_CALL3):
- Setup_for_c_call;
- accu = (cprim[u16pc])(sp[2], sp[1], accu);
- Restore_after_c_call;
- pc += SHORT;
- sp += 2;
- Next;
- Instruct(C_CALL4):
- Setup_for_c_call;
- accu = (cprim[u16pc])(sp[3], sp[2], sp[1], accu);
- Restore_after_c_call;
- pc += SHORT;
- sp += 3;
- Next;
- Instruct(C_CALL5):
- Setup_for_c_call;
- accu = (cprim[u16pc])(sp[4], sp[3], sp[2], sp[1], accu);
- Restore_after_c_call;
- pc += SHORT;
- sp += 4;
- Next;
- Instruct(C_CALLN):
- { int n = *pc++;
- value * args;
- int i;
- *--sp = accu;
- Setup_for_c_call;
- args = (value*)malloc(n * sizeof(value));
- for (i = 0; i < n; i++)
- args[i] = sp[n-i];
- accu = (cprim[u16pc])(args, n);
- Restore_after_c_call;
- pc += SHORT;
- free(args);
- sp += n;
- Next; }
-
- /* small values */
-
- Instruct(CONSTBYTE): accu = *pc++; Next;
-
- Instruct(CONSTSHORT): accu = s16pc; pc += SHORT; Next;
-
- /* Integer constants */
-
- Instruct(PUSHCONST0): *--sp = accu; /* Fallthrough */
- Instruct(CONST0): accu = Val_int(0); Next;
-
- Instruct(PUSHCONST1): *--sp = accu; /* Fallthrough */
- Instruct(CONST1): accu = Val_int(1); Next;
-
- Instruct(PUSHCONST2): *--sp = accu; /* Fallthrough */
- Instruct(CONST2): accu = Val_int(2); Next;
-
- Instruct(PUSHCONST3): *--sp = accu; /* Fallthrough */
- Instruct(CONST3): accu = Val_int(3); Next;
-
- Instruct(PUSHCONSTINT): *--sp = accu; /* Fallthrough */
- Instruct(CONSTINT):
- accu = Val_int(s32pc);
- pc += LONG;
- Next;
-
- /* Unsigned integer arithmetic modulo 2^(wordsize-1) */
-
- Instruct(ADDINT): /* Modified for Moscow ML: unsigned */
- accu = (unsigned long) ((unsigned long) *sp++
- + (unsigned long) (accu - 1)); Next;
- Instruct(SUBINT): /* unsigned */
- accu = (unsigned long) ((unsigned long) *sp++
- - (unsigned long) (accu - 1)); Next;
- Instruct(MULINT): /* unsigned */
- accu = (unsigned long) (1 + (unsigned long) (*sp++ >> 1)
- * (unsigned long) (accu - 1)); Next;
- Instruct(DIVINT): /* unsigned */
- tmp = accu - 1;
- if (tmp == 0) {
- accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- accu = Val_long((unsigned long) ((unsigned long) (*sp++ - 1)
- / (unsigned long) tmp));
- Next;
-
- Instruct(MODINT):
- tmp = accu - 1;
- if (tmp == 0) {
- accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- accu = (unsigned long) (1 + (unsigned long) (*sp++ - 1)
- % (unsigned long) tmp);
- Next;
-
- Instruct(ANDINT):
- accu &= *sp++; Next;
- Instruct(ORINT):
- accu |= *sp++; Next;
- Instruct(XORINT):
- accu = 1 + (accu ^ *sp++); Next;
- Instruct(SHIFTLEFTINT):
- accu = 1 + ((*sp++ - 1) << Long_val(accu)); Next;
- Instruct(SHIFTRIGHTINTSIGNED):
- accu = 1 | ((*sp++ - 1) >> Long_val(accu)); Next;
- Instruct(SHIFTRIGHTINTUNSIGNED):
- accu = 1 | ((unsigned long)(*sp++ - 1) >> Long_val(accu)); Next;
-
- #define inttest(name1,name2,tst) \
- Instruct(name1): \
- accu = Atom(*sp++ tst accu); \
- Next; \
- Instruct(name2): \
- if (*sp++ tst accu) { branch(); } else { pc += SHORT; } \
- Next;
-
- inttest(EQ,BRANCHIFEQ,==);
- inttest(NEQ,BRANCHIFNEQ,!=);
- inttest(LTINT,BRANCHIFLT,<);
- inttest(GTINT,BRANCHIFGT,>);
- inttest(LEINT,BRANCHIFLE,<=);
- inttest(GEINT,BRANCHIFGE,>=);
-
- Instruct(TAGOF):
- accu = Val_long(Tag_val(accu));
- Next;
-
- #define unsigntest(name, tst) \
- Instruct(name): \
- accu = Atom((unsigned)(*sp++) tst (unsigned)accu); \
- Next; \
-
- unsigntest(EQUNSIGN,==);
- unsigntest(NEQUNSIGN,!=);
- unsigntest(LTUNSIGN,<);
- unsigntest(GTUNSIGN,>);
- unsigntest(LEUNSIGN,<=);
- unsigntest(GEUNSIGN,>=);
-
- Instruct(BRANCHINTERVAL):
- { value low_bound, high_bound;
- high_bound = accu;
- low_bound = *sp++;
- accu = *sp++;
- if (accu < low_bound) {
- branch();
- Next;
- }
- pc += SHORT;
- if (accu > high_bound) {
- branch();
- Next;
- }
- pc += SHORT;
- accu = accu - low_bound + 1;
- Next;
- }
-
- /* --- Moscow SML changes begin --- */
-
- #define Check_float(dval) \
- if ((dval > maxdouble) || (dval < -maxdouble)) \
- { accu = Atom(float_exn); goto raise_exception; }
-
- Instruct(FLOATOFINT):
- dtmp = (double) Long_val(accu); goto float_done;
-
- Instruct(SMLNEGFLOAT):
- float_exn = SMLEXN_OVF;
- dtmp = -Double_val(accu);
- Check_float(dtmp); goto float_done;
-
- Instruct(SMLADDFLOAT):
- float_exn = SMLEXN_OVF;
- dtmp = Double_val(*sp++) + Double_val(accu);
- Check_float(dtmp); goto float_done;
-
- Instruct(SMLSUBFLOAT):
- float_exn = SMLEXN_OVF;
- dtmp = Double_val(*sp++) - Double_val(accu);
- Check_float(dtmp); goto float_done;
-
- Instruct(SMLMULFLOAT):
- float_exn = SMLEXN_OVF;
- dtmp = Double_val(*sp++) * Double_val(accu);
- Check_float(dtmp); goto float_done;
-
- Instruct(SMLDIVFLOAT):
- float_exn = SMLEXN_OVF;
- dtmp = Double_val(accu);
- if (dtmp == 0) {
- accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- dtmp = Double_val(*sp++) / dtmp;
- Check_float(dtmp); /* Fallthrough */
- float_done:
- Alloc_small(tmp, Double_wosize, Double_tag);
- Store_double_val(tmp, dtmp);
- accu = tmp;
- Next;
-
- /* --- Moscow SML changes end --- */
-
- Instruct(INTOFFLOAT):
- accu = Val_long((long)Double_val(accu)); Next;
-
- #define floattest(name, tst) \
- Instruct(name): \
- accu = Atom(Double_val(*sp++) tst Double_val(accu)); \
- Next;
-
- floattest(EQFLOAT,==);
- floattest(NEQFLOAT,!=);
- floattest(LTFLOAT,<);
- floattest(GTFLOAT,>);
- floattest(LEFLOAT,<=);
- floattest(GEFLOAT,>=);
-
- Instruct(STRINGLENGTH):
- accu = Val_long(string_length(accu));
- Next;
-
- #define stringtest(name, tst) \
- Instruct(name): \
- accu = Atom(compare_strings(*sp++, accu) tst Val_long(0)); \
- Next;
-
- stringtest(EQSTRING,==);
- stringtest(NEQSTRING,!=);
- stringtest(LTSTRING,<);
- stringtest(GTSTRING,>);
- stringtest(LESTRING,<=);
- stringtest(GESTRING, >=);
-
- Instruct(MAKEVECTOR):
- { mlsize_t size = Long_val(sp[0]);
- /* Make sure that the object referred to by sp[0] survives gc: */
- sp[0] = accu;
- if (size == 0)
- accu = Atom(0);
- else if (size < Max_young_wosize){
- Alloc_small (accu, size, 0);
- do {size--; Field (accu, size) = *sp;} while (size != 0);
- }else if (Is_block (*sp) && Is_young (*sp)){
- Setup_for_gc;
- minor_collection ();
- tmp = alloc_shr (size, 0);
- Restore_after_gc;
- accu = tmp;
- do {size--; Field (accu, size) = *sp;} while (size != 0);
- }else{
- Setup_for_gc;
- tmp = alloc_shr (size, 0);
- Restore_after_gc;
- accu = tmp;
- do {size--; initialize(&Field(accu, size), *sp);} while (size != 0);
- }
- sp++;
- Next;
- }
-
- /* --- Additional instructions for Moscow SML --- */
-
- Instruct(SMLNEGINT):
- tmp = - Long_val(accu);
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp ) {
- accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- }
- Next;
- Instruct(SMLSUCCINT):
- tmp = Long_val(accu) + 1;
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp ) {
- accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- }
- Next;
- Instruct(SMLPREDINT):
- tmp = Long_val(accu) - 1;
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp ) {
- accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- }
- Next;
- Instruct(SMLADDINT):
- tmp = Long_val(*sp++) + Long_val(accu);
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp ) goto raise_sum;
- Next;
- raise_sum:
- accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- Instruct(SMLSUBINT):
- tmp = Long_val(*sp++) - Long_val(accu);
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp ) goto raise_diff;
- Next;
- raise_diff:
- accu = Atom(SMLEXN_OVF);
- goto raise_exception;
-
- #define ChunkLen (4 * sizeof(value) - 1)
- #define MaxChunk ((1L << ChunkLen) - 1)
-
- Instruct(SMLMULINT):
- { register long x, y;
- register int isNegative = 0;
- x = Long_val(*sp++);
- y = Long_val(accu);
- if( x < 0 ) { x = -x; isNegative = 1; }
- if( y < 0 ) { y = -y; isNegative = !isNegative; }
- if( y > x ) { tmp = y; y = x; x = tmp; }
- if( y > MaxChunk ) goto raise_prod;
- if( x <= MaxChunk )
- { accu = Val_long(isNegative?(-(x * y)):(x * y)); }
- else /* x > MaxChunk */
- { tmp = (x >> ChunkLen) * y;
- if( tmp > MaxChunk + 1) goto raise_prod;
- tmp = (tmp << ChunkLen) + (x & MaxChunk) * y;
- if( isNegative ) tmp = - tmp;
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp ) goto raise_prod;
- }
- }
- Next;
- raise_prod :
- accu = Atom(SMLEXN_OVF);
- goto raise_exception;
-
- Instruct(SMLDIVINT):
- tmp = Long_val(accu);
- accu = Long_val(*sp++);
- if (tmp == 0)
- { accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- if( tmp < 0 ) { accu = - accu; tmp = -tmp; }
- if( accu >= 0 )
- { tmp = accu / tmp; }
- else
- { accu = - accu;
- if( accu % tmp == 0 )
- tmp = - (accu /tmp);
- else
- tmp = - (accu / tmp) - 1;
- }
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp )
- { accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- }
- Next;
-
- Instruct(SMLMODINT):
- { register long y;
- y = tmp = Long_val(accu);
- accu = Long_val(*sp++);
- if (tmp == 0)
- { accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- if( tmp < 0 ) { accu = -accu; tmp = -tmp; }
- if( accu >= 0 )
- tmp = accu % tmp;
- else
- { accu = (-accu) % tmp;
- tmp = ( accu == 0 )?( 0 ):( tmp - accu );
- }
- if( y < 0 ) tmp = -tmp;
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp )
- { accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- }
- }
- Next;
-
- Instruct(MAKEREFVECTOR):
- { mlsize_t size = Long_val(sp[0]);
- sp[0] = accu;
- if (size == 0)
- accu = Atom(Reference_tag);
- else if (size < Max_young_wosize){
- Alloc_small (accu, size, Reference_tag);
- do {size--; Field (accu, size) = *sp;} while (size != 0);
- }else if (Is_block (*sp) && Is_young (*sp)){
- Setup_for_gc;
- minor_collection ();
- tmp = alloc_shr (size, Reference_tag);
- Restore_after_gc;
- accu = tmp;
- do {size--; Field (accu, size) = *sp;} while (size != 0);
- }else{
- Setup_for_gc;
- tmp = alloc_shr (size, Reference_tag);
- Restore_after_gc;
- accu = tmp;
- do {size--; initialize(&Field(accu, size), *sp);} while (size != 0);
- }
- sp++;
- Next;
- }
-
- Instruct(SMLQUOTINT):
- tmp = accu - 1;
- if (tmp == 0)
- { accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- tmp = (*sp++ - 1) / tmp;
- accu = Val_long(tmp);
- if( Long_val(accu) != tmp )
- { accu = Atom(SMLEXN_OVF);
- goto raise_exception;
- }
- Next;
- Instruct(SMLREMINT):
- tmp = accu - 1;
- if (tmp == 0) {
- accu = Atom(SMLEXN_DIV);
- goto raise_exception;
- }
- accu = 1 + (*sp++ - 1) % tmp;
- Next;
-
- /* --- End of additional instructions for Moscow SML --- */
-
- /* Machine control */
-
- Instruct(STOP):
- extern_sp = sp;
- external_raise = initial_external_raise;
- DUMPTABLE
- return accu;
-
- #ifdef DIRECT_JUMP
- lbl_EVENT:
- #else
- default:
- #endif
-
- fatal_error("bad opcode");
-
- #ifndef DIRECT_JUMP
- }
- }
- #endif
- }
-
- static opcode_t callback1_code[] = { ACC1, APPLY1, POP, 1, STOP };
- static opcode_t callback2_code[] = { ACC2, APPLY2, POP, 1, STOP };
- static opcode_t callback3_code[] = { ACC3, APPLY3, POP, 1, STOP };
-
- value callback(closure, arg)
- value closure, arg;
- {
- value res;
- extern_sp -= 2;
- extern_sp[0] = arg;
- extern_sp[1] = closure;
- /* callback_depth++; */
- res = interprete(callback1_code, sizeof(callback1_code));
- /* callback_depth--; */
- return res;
- }
-
- value callback2(closure, arg1, arg2)
- value closure, arg1, arg2;
- {
- value res;
- extern_sp -= 3;
- extern_sp[0] = arg1;
- extern_sp[1] = arg2;
- extern_sp[2] = closure;
- /* callback_depth++; */
- res = interprete(callback2_code, sizeof(callback2_code));
- /* callback_depth--; */
- return res;
- }
-
- value callback3(closure, arg1, arg2, arg3)
- value closure, arg1, arg2, arg3;
- {
- value res;
- extern_sp -= 4;
- extern_sp[0] = arg1;
- extern_sp[1] = arg2;
- extern_sp[2] = arg3;
- extern_sp[3] = closure;
- /* callback_depth++; */
- res = interprete(callback3_code, sizeof(callback3_code));
- /* callback_depth--; */
- return res;
- }
-
- /* end */
-