📄 engine.cpp
字号:
get_stack_frame(i, xs);
Parser::state.push_context(xs.m_fb->context);
resume_state.m_baseSP = xs.m_baseSP;
if (verbose) dump_fun_frame(i,xs);
}
static int
s_stepping = 0,
s_current_exec_line = -1,
s_old_exec_line = -1;
static Breakpoint* s_brk = NULL;
const int STEP_WAIT=1,STEP_MAIN=2,STEPPING=3,STEPPING_OVER=4;
static FBlock* s_main_fb;
static FBlock* s_initial_fb;
static int s_initial_stack_depth;
// *add 1.2.4 Switches profiling mode; returns IC.
unsigned long instr_count = 0;
const int STEP_PROFILE = 5;
unsigned long* set_instruction_counter(bool do_profiling)
{
s_stepping = do_profiling ? STEP_PROFILE : 0;
return &instr_count;
}
#ifdef _DEBUG
int sh_offs() {
return (int)mSP-(int)_stack_;
}
CEXPORT char *sh_fun() {
static string tmp;
try {
tmp = fname_from_fblock(fb); // *change 1.2.4
return tmp.c_str();
}
catch(...) {
return "<dud>";
}
}
char *sh_var(char *sym)
{
static char buff[40];
PEntry pe = Parser::symbol_lookup(sym);
if (pe) {
unsigned int res = *(unsigned int *)pe->global_ptr();
sprintf(buff,"%x %d",res,res);
return buff;
}
else return "not found";
}
#endif
int current_ip()
{
return ((int)ppcode - (int)fb->pstart)/4;
}
bool start_exec()
//---------------------------
{
static int rmode,rdata,val,nargs,tmp;
static Opcodes opcode;
static double fval, gval;
static void *data;
static int buff[TMP_BUFF_SIZE];
NFBlock *pfb; // *fix 1.2.4 Must _not_ be static!
while (ppcode != end_of_code) {
top:
opcode = (Opcodes)ppcode->opcode;
rmode = ppcode->rmode;
if (rmode) {
rdata = ppcode->data;
if (rmode == DIRECT) data = mDataSeg + rdata; else
if (rmode == SREL) data = baseSP + rdata;
else data = mOP + rdata;
}
switch(opcode) {
//...pushing effective address.
case PEA: push((int)data); break;
case PERA: push(rdata); break;
//.....pushing onto the exec stack...........................
case PUSHC: push(REF(char,data)); break;
case PUSHW: push(REF(short,data)); break;
case PUSHI: push(REF(int,data)); break;
case PUSHF: push2(REF(float,data)); break; // push as qword
case PUSHD: push2(REF(double,data)); break;
case PUSHS: pushf(REF(float,data)); break; // push as dword
//....popping off the exec stack into a variable.............
case POPC: REF(char,data) = pop(); break;
case POPW: REF(short,data) = pop(); break;
case POPI: REF(int,data) = pop(); break;
case POPF: REF(float,data) = pop2(); break;
case POPD: REF(double,data) = pop2(); break;
//....stack-relative pushes/pops
case PUSHSC: push(REF(char,popp())); break;
case PUSHSW: push(REF(short,popp())); break;
case PUSHSI: push(REF(int,popp())); break;
case PUSHSF: push2(REF(float,popp())); break;
case PUSHSD: push2(REF(double,popp())); break;
case POPSC: val=popp(); REF(char,val) = pop(); break;
case POPSW: val=popp(); REF(short,val) = pop(); break;
case POPSI: val=popp(); REF(int,val) = pop(); break;
case POPSD: val=popp();REF(double,val) = pop2(); break;
case DROP: drop(); break;
case DROP2: drop2(); break; // *add 1.2.3b missing opcode!
case DUP: push(tos()); break;
case DUP2: push2(tos2()); break; // *fix 1.2.4 was taken out by mistake in 1.2.3b!
case SWAP: //....swap top two dwords on stack....
val = pop();
tmp = tos();
tos() = val;
push(tmp);
break;
case SWAPD: // swap top qword with next dword...
fval = pop2();
val = pop();
push2(fval);
push(val);
break;
//.....integer arithmetric operations.......................
case NEG: tos() = -tos(); break;
case ADD: val=pop(); tos() += val; break;
case SUB: val=pop(); tos() -= val; break;
case MUL: val=pop(); tos() *= val; break;
case DIV: val=pop(); tos() /= val; break;
case IDIV: val=pop(); (unsigned&)tos() /= val; break;
case AND: val=pop(); tos() &= val; break; // binary and
case OR: val=pop(); tos() |= val; break; // binary or
case XOR: val=pop(); tos() ^= val; break;
case SHL: val=pop(); tos() <<= val; break;
case SHR: val=pop(); tos() >>= val; break;
case NOT: tos() = ! tos(); break;
case BNOT: tos() = ~ tos(); break;
case EQ: val=pop(); tos() = tos() == val; break;
case NEQ: val=pop(); tos() = tos() != val; break;
case MOD: val=pop(); tos() = tos() % val; break;
case LESS: val=pop(); tos() = tos() < val; break;
case GREAT: val=pop(); tos() = tos() > val; break;
case LE: val=pop(); tos() = tos() <= val; break;
case GE: val=pop(); tos() = tos() >= val; break;
//....floating-point arithmetric
case FNEG: tos2() = -tos2(); break;
case FADD:
fval=pop2();
tos2() += fval;
break;
case FSUB: fval=pop2(); tos2() -= fval; break;
case FMUL: fval=pop2(); tos2() *= fval; break;
case FDIV: fval=pop2(); tos2() /= fval; break;
case FEQ: fval=pop2(); push(pop2() == fval); break;
case FNEQ: fval=pop2(); push(pop2() != fval); break;
case FLESS: fval=pop2(); push(pop2() < fval); break;
case FGREAT: fval=pop2(); push(pop2() > fval); break;
case FLE: fval=pop2(); push(pop2() <= fval); break;
case FGE: fval=pop2(); push(pop2() >= fval); break;
//...array operations
case ADDCC: val=pop(); push((int)data + sizeof(char)*val); break;
case ADDCW: val=pop(); push((int)data + sizeof(short)*val); break;
case ADDCI: val=pop(); push((int)data + sizeof(int)*val); break;
case ADDCD: val=pop(); push((int)data + sizeof(double)*val); break;
case ADDPC: val=pop(); push(REF(int,data) + sizeof(char)*val); break;
case ADDPW: val=pop(); push(REF(int,data) + sizeof(short)*val); break;
case ADDPI: val=pop(); push(REF(int,data) + sizeof(int)*val); break;
case ADDPD: val=pop(); push(REF(int,data) + sizeof(double)*val); break;
// ADDSC is ADD!
case ADDSW: val=pop(); push(val + sizeof(short)*pop()); break;
case ADDSI: val=pop(); push(val + sizeof(int)*pop()); break;
case ADDSD: val=pop(); push(val + sizeof(double)*pop()); break;
case ADDSN: val=pop(); push(val + pop()*pop()); break;
case COPY: memcpy((void *)pop(),(void *)pop(),ppcode->data); break;
//...jumps (all relative) and calls (pcode and native)........
//...These set ppcode directly, and so we jump to the end of the loop....
case CCALLX: // *add 1.2.0 Associate VMT with imported ptr
PFBlock(data)->class_ptr->attach_VMT(mOP);
goto call_the_function;
case CCALL: //....patch the hidden VMT pointer......
*VMT(mOP) = PFBlock(data)->class_ptr->get_VMT();
// and fall through....
call_the_function:
case CALL:
start_function(PFBlock(data));
continue;
case VCALL: //....lookup the proc in the VMT table....
start_function(virtual_method_lookup(rdata));
continue;
case VCALLX: //....lookup proc in associated VMT table (for imports)
start_function(virtual_method_imported_lookup(rdata));
continue;
case CALLN: // native code interface
pfb = (NFBlock *)data;
nargs = pfb->nargs;
if (nargs == -1) nargs = pop();
callfn(pfb->pfn,mSP-1,nargs,mOP,pfb->flags,buff);
mSP += nargs;
if (pfb->flags & DC_QWORD) push2(*(double *)buff); else
if (pfb->flags & DC_NOWORD) ;
else push(*buff);
break;
case CCALLV: {// vector constructor/destructor call
ConstructBlock *pcb = (ConstructBlock *)data;
PPClass vtable = pcb->get_VMT();
PClass pc = pcb->class_ptr();
int num;
if (pcb->dynamic()) { // i.e new[] has generated a ptr for us;
char *ptr = mOP - sizeof(void *);
num = Builtin::alloc_size(ptr);
} else num = pcb->num();
char *old_mOP = mOP;
for(int i = 0, sz = pcb->size(); i < num; i++) {
if (vtable != NULL) { // patch VMT, if needed
if (! pc->has_true_VMT()) pc->attach_VMT(vtable);
else *VMT(mOP) = vtable;
}
// push ODS, if needed
// *add 1.2.3 static objects get their own ODS
// *change 1.2.9 static objects are handled at compile-time w/ the ODL
// (see LoadedModuleList in program.cpp)
if (pcb->load_ODS())
mODS.push_object(pc, mOP);
if (Engine::execute(pcb->fblock())==CRASHED)
throw Exception("Construction failed");
mOP += sz;
}
mOP = old_mOP;
if (pcb->dynamic()) push((int)mOP); // leave obj on XS
opop(); // drop the OS
}
break;
// *NOTE* The continue seems strange, but it is important to skip ppcode++!
case CALLS:
start_function(PFBlock(pop()));
continue;
case VCALLS:
start_function(virtual_method_lookup((int)pop()));
continue;
JMP_case:
case JMP: ppcode = fb->pstart + ppcode->data; goto top; break;
case JZ: if(!pop()) goto JMP_case; break;
case JNZ: if(pop()) goto JMP_case; break;
case JZND: if(!tos()) goto JMP_case; else drop(); break;
case JNZND: if(tos()) goto JMP_case; else drop(); break;
case JSWITCH: ppcode = fb->pstart + switch_jump((int *)data,pop()); goto top;
case RET:
mSP = baseSP;
mSP += fb->nargs;
end_function();
break;
case RETI: //......returning dword..........
val = pop(); // pop the return value
mSP = baseSP; // restore stack frame
mSP += fb->nargs; // drop the args (STDCALL!)
push(val); // push return value
end_function();
break;
case RETD: //.....returning qword............
fval = pop2();
mSP = baseSP;
mSP += fb->nargs;
push2(fval);
end_function();
break;
case ADDSP: // *add 1.2.3b True cdecl calling convention implemented
{
int data = ppcode->data;
int tp = lo_byte(data);
int sz = hi_byte(data);
if (tp==1) val = pop();
else if (tp==2) fval = pop2();
mSP += sz;
if (tp==1) push(val);
else if (tp==2) push2(fval);
}
break;
case UNWIND:
{
int* old_sp = mSP;
char *old_op = mOP;
do_unwind((char *)data, mODS);
if (old_sp != mSP || old_op != mOP)
cerr << "SP/OP changed!\n";
#ifdef TRACK_ODS
cout << "unwind " << data << ' ' << current_ip() << ' ' << sh_fun() <<endl;
#endif
}
break;
case DCAST: { // *add 0.9.5 dynamic cast
Type t = *(Type *)data;
Class *tc = t.as_class(); // hm...what about the (void *) possibility?
void *ptr = (void *)pop();
Class *oc = get_class_object(ptr);
if (! oc->inherits_from(tc)) {
if (t.is_pointer()) push(0);
else {
int ip = throw_exception(t_char_ptr,(char *)"bad cast"); // for now!!
if (ip == -1) throw Exception("bad dynamic typecast");
else { ppcode = fb->pstart + ip; continue; }
}
} else push((int)ptr);
}
break;
// INC and DEC
case INCC: REF(char,data)++; break;
case INCW: REF(short,data)++; break;
case INCI: REF(int,data)++; break;
case INCS: tos()++; break;
case DECC: REF(char,data)--; break;
case DECW: REF(short,data)--; break;
case DECI: REF(int,data)--; break;
case DECS: tos()--; break;
// INCP and DECP
case INCPC: REFP(char,data)++; break;
case INCPW: REFP(short,data)++; break;
case INCPI: REFP(int,data)++; break;
case INCPD: REFP(double,data)++; break;
case DECPC: REFP(char,data)--; break;
case DECPW: REFP(short,data)--; break;
case DECPI: REFP(int,data)--; break;
case DECPD: REFP(double,data)--; break;
// INCS and DECS
case INCSC: REFS(char)++; break;
case INCSW: REFS(short)++; break;
case INCSI: REFS(int)++; break;
case DECSC: REFS(char)--; break;
case DECSW: REFS(short)--; break;
case DECSI: REFS(int)--; break;
//...conversions...............................................
case D2I: push((int)pop2()); break;
case I2D: push2((double)pop()); break;
case F2D: push2((double)popf()); break;
case D2F: pushf((float)pop2()); break;
case I2F: pushf((float)pop()); break;
case F2I: push((int)popf()); break;
case I2B: push(0xFF & pop()); break; // *add 1.2.9 32-bit to 8-bit bool
//...object-stack manipulation
case LOS:
//depth = ostack.depth();
opush(data);
break;
case LOSS:
opush((void *)pop());
break;
case DOS:
opop();
break;
case TOSX:
push((int)mOP);
opop();
break;
case TOSD:
mODS.push_object(*(PClass *)data, mOP);
#ifdef TRACK_ODS
cout << "TOSD " << (void *)mOP << ' ' << current_ip() << ' ' << sh_fun() << endl;
#endif
opop();
break;
case TPODS: // pushing temporary for functions returning object values
{
PClass pc = *(PClass *)data;
#ifdef DEBUG_ODS
if (pc->has_VMT()) *VMT(mOP) = DEFER_MARKER;
#endif
mODS.push_object(pc,mOP);
push((int)mOP);
#ifdef TRACK_ODS
cout << "TPODS " << mOP << ' ' << sh_fun() << endl;
#endif
opop();
}
break;
case PUSH_THIS:
push((int)mOP);
break;
case STALC: // allocate object directly on stack (needed for MS object-passing)
// *fix 1.2.0 The UC stack now grows downwards!
mSP -= ppcode->data;
opush(mSP);
break;
case THROW_EX: {
Type et = *(Type *)data;
void *obj = (void *)pop();
int ip = throw_exception(et,obj);
if (ip == -1) { // couldn't catch the exception
// *add 1.2.4 if the thrown type is derived from Exception,
// then pass on the message! (Warning: this depends on Exception defined in <uc_except.h>
// having precisely this layout, w/ a char pointer as the first field)
if (match(Parser::mEException->type,et) != NO_MATCH)
throw Exception(*(char **)obj);
else
throw Exception("uncaught exception");
} // otherwise, can continue excuting at the given catch block address...
else { ppcode = fb->pstart + ip; continue; }
}
case CHKVMT: // *NOTE64*
push((int)(*(PClass *)(data))->check_object_pointer((char *)pop()));
break;
case VTABLE_PATCH:
// *fix 1.2.8 in classes derived indirectly from imported classes,
// Class::update_vtable() was _not_ being called for the specific
// class in question!
// get_class_object(mOP)->update_vtable(mOP);
(*(PClass *)(data))->update_vtable(mOP);
break;
case POPIF:
case PUSHIF: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -