// // basic // Basic bytecode set // F.J. Alberti // case kNop: // Idle for an iteration break; case kDrop: // Pop stack top #if defined(SCOL_DEBUG) checkUnderflow(m) #endif m->pp++; break; case kDup: { // Duplicate stack top int val = m->top[m->pp]; m->top[--m->pp] = val; checkOverflow(m, 0) break; } case kPushnil: // Push constant nil m->top[--m->pp] = NIL; checkOverflow(m, 0) break; case kGoto: // Unconditional branch pc = *(uint32*)&fetch(pc); break; case kIftrue: // Branch if stack top is not 0 #if defined(SCOL_DEBUG) checkUnderflow(m) #endif if (m->top[m->pp++] != 0) pc = *(uint32*)&fetch(pc); else pc += ALIGNMENT(4); break; case kIffalse: // Branch if stack top is 0 #if defined(SCOL_DEBUG) checkUnderflow(m) #endif if (m->top[m->pp++] == 0) pc = *(uint32*)&fetch(pc); else pc += ALIGNMENT(4); break; case kExeccall: { // to be deprecated // Call a function ('exec' calling convention) if (m->top[m->pp] == NIL || m->top[m->pp+1] == NIL) { m->top[++m->pp] = NIL; break; } int nargs = m->tape[m->top[m->pp]>>1]>>1; if (nargs > 0) { checkOverflow(m, nargs-1) int i; int32 pp = m->pp+1; // Push nargs-1 arguments initialised to nil for (i = 1; i < nargs; i++) m->top[--m->pp] = NIL; int32 fun = m->top[pp]; // function int32 args = m->top[pp-1]>>1; // arguments tuple for (i = 0; i < nargs; i++) m->top[pp-i] = m->tape[args+SizeHeader+i]; m->top[m->pp] = fun; } else m->pp++; // fall through } case kCall: { // Call a function (either native or SCOL) tailcall = false; call: // If function pointer is undefined, return an error int fun = m->top[m->pp]; if (fun == NIL) throw Exception(MERREP); /* // Print package and function name int t = m->tape[(fun>>1)+SizeHeader+OFFPVAR]>>1; MMechostr(MSKRUNTIME, "> call '%s#%s'\n", (char*)&m->tape[(m->tape[(m->tape[t+SizeHeader+OFFVPKG]>>1)+SizeHeader+OFFPKNAME]>>1)+SizeHeader], (char*)&m->tape[(m->tape[t+SizeHeader+OFFVNAME]>>1)+SizeHeader]); */ int s = (fun>>1)+SizeHeader; int nargs = m->tape[s+OFFPARG]>>1; // function arity int nlocs = m->tape[s+OFFPLOC]>>1; // # of local variables (excluding args) int optarg = m->tape[s+OFFPOPT]; // pointer to first optional arg, if any #if defined(INCLUDE_DEBUGGER) if (debug.sock) { //$ FA(04/09/2001): Update current source position //DBGUpdatePosition(m, (pc == 0) ? 0 : pc-ALIGNMENT(1)); //$ FA(18/11/2000): Break if trace flag has been set if (m->tape[s+OFFPDBG] && debug.traceMode != kTraceNone) { MMechostr(MSKTRACE, "User break at function (%x)\n", fun); DBGRequestBreak(m, kBrksrcBreakpoint); } } #endif // Handle functions generated through 'newfun' while (optarg != NIL) { m->top[--m->pp] = optarg; checkOverflow(m, 1); optarg = m->top[m->pp++]; m->top[--m->pp] = m->tape[(optarg>>1)+SizeHeader]; // Swap int val = m->top[m->pp]; m->top[m->pp] = m->top[m->pp+1]; m->top[m->pp+1] = val; optarg = m->tape[(optarg>>1)+SizeHeader+1]; nargs++; } // while // Call a native function if (nlocs == NIL) { // nlocs is not a SCOL int here! int fun = m->top[m->pp]; Native native = (Native)m->tape[(m->tape[(fun>>1)+SizeHeader+OFFPBCD]>>1)+SizeHeader]; m->pp++; // drop function pointer #if defined(SCOL_DEBUG) || defined(RELEASE_DEVELOPER) int pp = m->pp; #endif if (native) { if (res = (*native)(m)) throw Exception(res); } else { #if defined(RELEASE_DEVELOPER) // This case never takes place given the actual definition // of native package linking int s = m->tape[(fun>>1)+SizeHeader+OFFPVAR]>>1; MMechostr(MSKRUNTIME, "(!) "MSGWNATIVEISNULL"\n", (char*)&m->tape[(m->tape[(m->tape[s+SizeHeader+OFFVPKG]>>1)+SizeHeader+OFFPKNAME]>>1)+SizeHeader], (char*)&m->tape[(m->tape[s+SizeHeader+OFFVNAME]>>1)+SizeHeader]); #endif m->pp += nargs; m->top[--m->pp] = NIL; checkOverflow(m, 0) break; } // Terminate Interpreter::exec() if returning from first call if (fp == 0) return MERREND; #if defined(SCOL_DEBUG) || defined(RELEASE_DEVELOPER) if (m->pp != pp+nargs-1) { # if defined(RELEASE_DEVELOPER) int s = m->tape[(fun>>1)+SizeHeader+OFFPVAR]>>1; MMechostr(MSKRUNTIME, "(!) "MSGENATIVEMISBEHAVED"\n", (char*)&m->tape[(m->tape[(m->tape[s+SizeHeader+OFFVPKG]>>1)+SizeHeader+OFFPKNAME]>>1)+SizeHeader], (char*)&m->tape[(m->tape[s+SizeHeader+OFFVNAME]>>1)+SizeHeader]); # else MMechostr(MSKRUNTIME, "(!) "MSGENATIVEMISBEHAVED"\n", native, nargs); # endif // Dump register values MMechostr(MSKRUNTIME, " sp = %x (expected at %x)\n", m->pp, pp+nargs-1); MMechostr(MSKRUNTIME, " fp = %x\n", fp); MMechostr(MSKRUNTIME, " bp = %x\n", bp); MMechostr(MSKRUNTIME, " pc = %x\n", pc); throw Exception(MERRRET); } #endif break; } #if !defined(RELEASE_DEVELOPER) if (tailcall) { int diff = fp-bp-5-nargs-nlocs; // locals area size difference int opc; // old program counter int obp; // old base pointer of operand stack int ofp; // old frame pointer // If there is not enough space in the locals area, save the values of // the caller's registers to reconstruct frame below if (diff < 0) { opc = m->top[bp]; obp = m->top[bp+1]; ofp = m->top[bp+2]; checkOverflow(m, -diff); } fun = m->top[m->pp]; // Overwrite caller's arguments. (Rather expensive; but effective.) int ap = m->pp+nargs; m->pp = fp+1; int i; for (i = 0; i < nargs; i++) m->top[--m->pp] = m->top[ap--]; // Initialise local variables for (i = 0; i < nlocs; i++) m->top[--m->pp] = NIL; if (diff < 0) { m->top[--m->pp] = fun; // pointer to function m->top[--m->pp] = m->tape[(fun>>1)+SizeHeader+OFFPBCD]; // pointer to code m->top[--m->pp] = m->tape[(fun>>1)+SizeHeader+OFFPREF]; // pointer to external references m->top[--m->pp] = ofp; // save caller's frame pointer m->top[--m->pp] = obp; // save caller's base pointer of operand stack m->top[--m->pp] = opc; // save caller's program counter bp = m->pp; } else { m->top[bp+5] = fun; // pointer to function m->top[bp+4] = m->tape[(fun>>1)+SizeHeader+OFFPBCD]; // pointer to code m->top[bp+3] = m->tape[(fun>>1)+SizeHeader+OFFPREF]; // pointer to external references m->pp = bp; // stack pointer points to base of operand stack } } else { #endif // Ensure that there is enough stack space checkOverflow(m, nlocs+FRAMESIZE); fun = m->top[m->pp]; int pp = (++m->pp)+nargs-1; // index of (supposed) first argument // Setup the new frame // Initialise local variables for (int i = 0; i < nlocs; i++) m->top[--m->pp] = NIL; #if defined(RELEASE_DEVELOPER) m->top[--m->pp] = NIL; // current list of local variables m->top[--m->pp] = NIL; // current source position #endif m->top[--m->pp] = fun; // pointer to function m->top[--m->pp] = m->tape[(fun>>1)+SizeHeader+OFFPBCD]; // pointer to code m->top[--m->pp] = m->tape[(fun>>1)+SizeHeader+OFFPREF]; // pointer to external references m->top[--m->pp] = fp<<1; // save current frame pointer m->top[--m->pp] = bp<<1; // save current base pointer of operand stack m->top[--m->pp] = pc<<1; // save current program counter bp = m->pp; fp = pp; #if !defined(RELEASE_DEVELOPER) } #endif pc = 0; break; } case kTailcall: tailcall = true; goto call; case kCallnative: // Reserved for calling a native function break; case kReturn: { // Return from a SCOL function #if defined(SCOL_DEBUG) || defined(RELEASE_DEVELOPER) if (m->pp != bp-1) { // Badly behaved function call MMechostr(MSKRUNTIME, "(!) "MSGIFUNRET"\n"); MMechostr(MSKRUNTIME, " sp = %x (expected at %x)\n", m->pp, bp-1); throw Exception(MERRRET); } #endif // Copy result int pp = fp; m->top[pp] = m->top[m->pp++]; // Restore caller's state pc = m->top[m->pp++]>>1; bp = m->top[m->pp++]>>1; fp = m->top[m->pp++]>>1; m->pp = pp; // Stop Interpreter::exec() if returning from first call if (fp == 0) return MERREND; break; } case kNewfun: { // Revise and rewrite int32 fun = m->top[m->pp+1]; if (fun == NIL) { m->pp++; break; } checkOverflow(m, 2) m->top[--m->pp] = m->tape[(fun>>1)+SizeHeader+OFFPOPT]; m->top[--m->pp] = 2<<1; if (res = MBdeftab(m)) throw Exception(res); int s = MMmalloc(m, SIZEPROG, TYPETAB); if (s == NIL) throw Exception(MERRMEM); fun = m->top[m->pp+1]>>1; m->tape[s+SizeHeader+OFFPARG] = m->tape[fun+SizeHeader+OFFPARG]-(1<<1); m->tape[s+SizeHeader+OFFPLOC] = m->tape[fun+SizeHeader+OFFPLOC]; m->tape[s+SizeHeader+OFFPBCD] = m->tape[fun+SizeHeader+OFFPBCD]; m->tape[s+SizeHeader+OFFPREF] = m->tape[fun+SizeHeader+OFFPREF]; m->tape[s+SizeHeader+OFFPOPT] = m->top[m->pp++]; #if defined(RELEASE_DEVELOPER) //$ FA(07/11/2000) m->tape[s+SizeHeader+OFFPVAR] = m->tape[fun+SizeHeader+OFFPVAR]; //$ FA(18/11/2000) // debugging options are inherited m->tape[s+SizeHeader+OFFPDBG] = m->tape[fun+SizeHeader+OFFPDBG]; //$ FA(23/11/2000) m->tape[s+SizeHeader+OFFPBPT] = m->tape[fun+SizeHeader+OFFPBPT]; // #endif m->top[m->pp] = s<<1|0x00000001; break; } case kPushstr: { // Push a string constant uint32 len = *(uint32*)&fetch(pc); // length of origin pc += ALIGNMENT(4); int s = MMmalloc(m, ((len+4)>>2)+1, TYPEBUF); if (s == NIL) throw Exception(MERRMEM); m->tape[s+SizeHeader] = len; char* org = (char*)&fetch(pc); // origin pc += len*ALIGNMENT(1); char* dst = (char*)&m->tape[s+SizeHeader+1]; // destination for (uint32 i = 0; i < len; i++) { *dst++ = *org; org += ALIGNMENT(1); } *dst = '\0'; m->top[--m->pp] = (s<<1)|0x00000001; checkOverflow(m, 0) break; }