VMFrameStack::~VMFrameStack() { while (PopFrame() != NULL) { } if (Blocks != NULL) { BlockHeader *block, *next; for (block = Blocks; block != NULL; block = next) { next = block->NextBlock; delete[] (VM_UBYTE *)block; } Blocks = NULL; } if (UnusedBlocks != NULL) { BlockHeader *block, *next; for (block = UnusedBlocks; block != NULL; block = next) { next = block->NextBlock; delete[] (VM_UBYTE *)block; } UnusedBlocks = NULL; } }
int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) { bool allocated = false; try { if (func->Native) { return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, numparams, results, numresults); } else { AllocFrame(static_cast<VMScriptFunction *>(func)); allocated = true; VMFillParams(params, TopFrame(), numparams); int numret = VMExec(this, static_cast<VMScriptFunction *>(func)->Code, results, numresults); PopFrame(); return numret; } } catch (VMException *exception) { if (allocated) { PopFrame(); } if (trap != NULL) { *trap = exception; return -1; } throw; } catch (...) { if (allocated) { PopFrame(); } throw; } }
void CObjectOStream::HandleEOF(CEofException&) { PopFrame(); throw; }
int VMCall(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults/*, VMException **trap*/) { bool allocated = false; try { if (func->VarFlags & VARF_Native) { return static_cast<VMNativeFunction *>(func)->NativeCall(params, func->DefaultArgs, numparams, results, numresults); } else { auto code = static_cast<VMScriptFunction *>(func)->Code; // handle empty functions consisting of a single return explicitly so that empty virtual callbacks do not need to set up an entire VM frame. // code cann be null here in case of some non-fatal DECORATE errors. if (code == nullptr || code->word == (0x00808000|OP_RET)) { return 0; } else if (code->word == (0x00048000|OP_RET)) { if (numresults == 0) return 0; results[0].SetInt(static_cast<VMScriptFunction *>(func)->KonstD[0]); return 1; } else { VMCycles[0].Clock(); VMCalls[0]++; auto &stack = GlobalVMStack; stack.AllocFrame(static_cast<VMScriptFunction *>(func)); allocated = true; VMFillParams(params, stack.TopFrame(), numparams); int numret = VMExec(&stack, code, results, numresults); stack.PopFrame(); VMCycles[0].Unclock(); return numret; } } } #if 0 catch (VMException *exception) { if (allocated) { PopFrame(); } if (trap != NULL) { *trap = exception; return -1; } throw; } #endif catch (...) { if (allocated) { GlobalVMStack.PopFrame(); } throw; } }
/* Execute - execute the main code */ int Execute(System *sys, ObjHeap *heap, VMHANDLE main) { size_t stackSize; Interpreter *i; VMVALUE tmp, tmp2, ind; VMHANDLE obj, htmp; int8_t tmpb; /* allocate the interpreter state */ if (!(i = (Interpreter *)AllocateFreeSpace(sys, sizeof(Interpreter)))) return VMFALSE; /* make sure there is space left for the stack */ if ((stackSize = (sys->freeTop - sys->freeNext) / sizeof(VMVALUE)) <= 0) return VMFALSE; /* setup the heap before/after compact functions */ heap->beforeCompact = NULL; heap->afterCompact = AfterCompact; heap->compactCookie = i; /* initialize the interpreter state */ i->sys = sys; i->heap = heap; i->stack = (VMVALUE *)((uint8_t *)i + sizeof(Interpreter)); i->stackTop = i->stack + stackSize; /* setup to execute the main function */ i->code = main; ObjAddRef(i->code); i->cbase = i->pc = GetCodePtr(main); i->sp = i->fp = i->stackTop; i->hsp = i->hfp = (VMHANDLE *)i->stack - 1; if (setjmp(i->sys->errorTarget)) { while (i->hsp > (VMHANDLE *)i->stack) ObjRelease(i->heap, PopH(i)); ObjRelease(i->heap, i->code); return VMFALSE; } for (;;) { #if 0 ShowStack(i); DecodeInstruction(0, 0, i->pc); #endif switch (VMCODEBYTE(i->pc++)) { case OP_HALT: return VMTRUE; case OP_BRT: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (Pop(i)) i->pc += tmp; break; case OP_BRTSC: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (*i->sp) i->pc += tmp; else Drop(i, 1); break; case OP_BRF: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (!Pop(i)) i->pc += tmp; break; case OP_BRFSC: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (!*i->sp) i->pc += tmp; else Drop(i, 1); break; case OP_BR: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); i->pc += tmp; break; case OP_NOT: *i->sp = (*i->sp ? VMFALSE : VMTRUE); break; case OP_NEG: *i->sp = -*i->sp; break; case OP_ADD: tmp = Pop(i); *i->sp += tmp; break; case OP_SUB: tmp = Pop(i); *i->sp -= tmp; break; case OP_MUL: tmp = Pop(i); *i->sp *= tmp; break; case OP_DIV: tmp = Pop(i); *i->sp = (tmp == 0 ? 0 : *i->sp / tmp); break; case OP_REM: tmp = Pop(i); *i->sp = (tmp == 0 ? 0 : *i->sp % tmp); break; case OP_CAT: StringCat(i); break; case OP_BNOT: *i->sp = ~*i->sp; break; case OP_BAND: tmp = Pop(i); *i->sp &= tmp; break; case OP_BOR: tmp = Pop(i); *i->sp |= tmp; break; case OP_BXOR: tmp = Pop(i); *i->sp ^= tmp; break; case OP_SHL: tmp = Pop(i); *i->sp <<= tmp; break; case OP_SHR: tmp = Pop(i); *i->sp >>= tmp; break; case OP_LT: tmp = Pop(i); *i->sp = (*i->sp < tmp ? VMTRUE : VMFALSE); break; case OP_LE: tmp = Pop(i); *i->sp = (*i->sp <= tmp ? VMTRUE : VMFALSE); break; case OP_EQ: tmp = Pop(i); *i->sp = (*i->sp == tmp ? VMTRUE : VMFALSE); break; case OP_NE: tmp = Pop(i); *i->sp = (*i->sp != tmp ? VMTRUE : VMFALSE); break; case OP_GE: tmp = Pop(i); *i->sp = (*i->sp >= tmp ? VMTRUE : VMFALSE); break; case OP_GT: tmp = Pop(i); *i->sp = (*i->sp > tmp ? VMTRUE : VMFALSE); break; case OP_LIT: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); CPush(i, tmp); break; case OP_GREF: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); obj = (VMHANDLE)tmp; CPush(i, GetSymbolPtr(obj)->v.iValue); break; case OP_GSET: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); obj = (VMHANDLE)tmp; GetSymbolPtr(obj)->v.iValue = Pop(i); break; case OP_LREF: tmpb = (int8_t)VMCODEBYTE(i->pc++); CPush(i, i->fp[(int)tmpb]); break; case OP_LSET: tmpb = (int8_t)VMCODEBYTE(i->pc++); i->fp[(int)tmpb] = Pop(i); break; case OP_VREF: ind = *i->sp; obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); *i->sp = GetIntegerVectorBase(obj)[ind]; DropH(i, 1); break; case OP_VSET: tmp2 = Pop(i); ind = Pop(i); obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); GetIntegerVectorBase(obj)[ind] = tmp2; DropH(i, 1); break; case OP_LITH: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); CPushH(i, (VMHANDLE)tmp); ObjAddRef(*i->hsp); break; case OP_GREFH: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); CPushH(i, GetSymbolPtr((VMHANDLE)tmp)->v.hValue); ObjAddRef(*i->hsp); break; case OP_GSETH: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); ObjRelease(i->heap, GetSymbolPtr((VMHANDLE)tmp)->v.hValue); GetSymbolPtr((VMHANDLE)tmp)->v.hValue = PopH(i); break; case OP_LREFH: tmpb = (int8_t)VMCODEBYTE(i->pc++); CPushH(i, i->hfp[(int)tmpb]); ObjAddRef(*i->hsp); break; case OP_LSETH: tmpb = (int8_t)VMCODEBYTE(i->pc++); ObjRelease(i->heap, i->hfp[(int)tmpb]); i->hfp[(int)tmpb] = PopH(i); break; case OP_VREFH: ind = Pop(i); obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); *i->hsp = GetStringVectorBase(obj)[ind]; ObjAddRef(*i->hsp); break; case OP_VSETH: htmp = PopH(i); ind = Pop(i); obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); ObjRelease(i->heap, GetStringVectorBase(obj)[ind]); GetStringVectorBase(obj)[ind] = htmp; DropH(i, 1); break; case OP_RESERVE: tmp = VMCODEBYTE(i->pc++); tmp2 = VMCODEBYTE(i->pc++); Reserve(i, tmp); ReserveH(i, tmp2); break; case OP_CALL: StartCode(i); break; case OP_RETURN: tmp = *i->sp; PopFrame(i); Push(i, tmp); break; case OP_RETURNH: htmp = *i->hsp; PopFrame(i); PushH(i, htmp); break; case OP_RETURNV: PopFrame(i); break; case OP_DROP: Drop(i, 1); break; case OP_DROPH: ObjRelease(i->heap, *i->hsp); DropH(i, 1); break; default: Abort(i->sys, str_opcode_err, VMCODEBYTE(i->pc - 1)); break; } } }
int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap) { bool allocated = false; try { if (func->Native) { return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, numparams, results, numresults); } else { AllocFrame(static_cast<VMScriptFunction *>(func)); allocated = true; VMFillParams(params, TopFrame(), numparams); int numret = VMExec(this, static_cast<VMScriptFunction *>(func)->Code, results, numresults); PopFrame(); return numret; } } catch (VMException *exception) { if (allocated) { PopFrame(); } if (trap != NULL) { *trap = exception; return -1; } throw; } catch (EVMAbortException exception) { if (allocated) { PopFrame(); } if (trap != nullptr) { *trap = nullptr; } Printf("VM execution aborted: "); switch (exception) { case X_READ_NIL: Printf("tried to read from address zero."); break; case X_WRITE_NIL: Printf("tried to write to address zero."); break; case X_TOO_MANY_TRIES: Printf("too many try-catch blocks."); break; case X_ARRAY_OUT_OF_BOUNDS: Printf("array access out of bounds."); break; case X_DIVISION_BY_ZERO: Printf("division by zero."); break; case X_BAD_SELF: Printf("invalid self pointer."); break; } Printf("\n"); return -1; } catch (...) { if (allocated) { PopFrame(); } throw; } }