⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 engine.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 4 页
字号:
};

class ODStack: public VStack<ODS_Record,ODS_STACKSIZE>  // wuz Stack<...
{
private:
    ODS_Record orec;
public:

 void push_object(PClass pc, void* obj)
 {
    orec.m_class = pc;
    orec.m_obj = obj;
    #ifdef DEBUG_ODS
    if (fb == Parser::temp_fun_block()) orec.m_fn = NULL;
    else orec.m_fn = Function::from_fun_block(fb);
    orec.m_offs = current_ip();
    #endif
    push(orec);
 }

 void pop_object(PClass& pc, void*& obj)
 {
   orec = pop();
   pc = orec.m_class;
   obj = orec.m_obj;
 }

 void fetch_object(int idx, PClass& pc, void*& obj)
 {
   orec = get(idx);
   //orec = *ref_to_TOS(-idx);
   pc = orec.m_class;
   obj = orec.m_obj;
 }

 #ifdef DEBUG_ODS
 void current_context(PClass& pc, PFunction& fn, int& offs)
 { // assumes basically that either pop_object() or fetch_object() has been called...
    fn = orec.m_fn;
    offs = orec.m_offs;
	pc = orec.m_class;
 }
 #endif

};

static ODStack mODS;

void end_function();  // forward...

#ifdef DEBUG_ODS
void destruct_error(char *msg)
{
     PFunction fn;
     int ofs;
	 PClass pc;
     mODS.current_context(pc,fn,ofs);
     string name = fn ? fn->name() : string("<temp>");
	 string cname = pc ? pc->name() : string("<none>");
     cerr << "bad ODS entry: class " << cname << " fn " << name << '(' << ofs << ')' << endl;
	 exec_message(msg,true);
}
#else
void destruct_error(char *msg) { exec_message(msg,true); }
#endif

void do_unwind(void *p, ODStack& o_ds)
{
// unwind the Object Destruction Stack (ODS)
  FBlock * old_fb = fb;
  Instruction *old_ppcode = ppcode;
  int *old_baseSP = baseSP;
  int *old_mSP = mSP;
  PClass pc;

  // *fix 0.9.5 Before unwinding, we must check whether this object is in fact on the ODS
  if (p != NULL) {
    bool found = false;
    int n  = o_ds.depth();
    if (!n) return; // ODS empty....
    for(int i = 0; i < n; i++)
    {
      void* s_obj; 
      o_ds.fetch_object(i,pc,s_obj);
      if (s_obj == p) {
        found = true;
        break;
      }
    }
    if (! found)
      return;    
  }

  // the stack unwinding loop
  char *lastOP = mOP;
  void *obj;
  if (o_ds.depth() > 0)
  do {
   o_ds.pop_object(pc,obj);
   mOP = (char *)obj;    
   Function *dfn;
   try {
     dfn = pc->destructor();
   } catch(...) {
       destruct_error("bad ODS entry ");
       break;
   }
   if (dfn != NULL) try {
     if (Engine::execute(dfn->fun_block())==CRASHED) 
	      destruct_error("destructor failed");
   } catch(...) {
     destruct_error("bad destructor");
     return;
   }
  } while (obj != p && o_ds.depth() > 0);
  mOP = lastOP;    
  fb = old_fb;
 // check_fun_block(fb);
  ppcode = old_ppcode;
  baseSP = old_baseSP;
  mSP = old_mSP;
}

#define DEFER_MARKER ((PClass *)(0x777))

#ifdef DEBUG_ODS
void check_ODS()
{
 int n  = mODS.depth();
 if (!n) return;
 for(int i = 0; i < n; i++)
 {
   PClass pc;
   void *obj;
   PFunction fn;
   int ofs;
   
   mODS.fetch_object(i,pc,obj);
   bool fooked = false;
   if (pc->has_VMT()) try {
     PClass *vmt = *VMT(obj);
     if (vmt != DEFER_MARKER) fooked = pc != *vmt;	 
   }
   catch(...) { fooked = true; }
   if (fooked) {
       mODS.current_context(pc,fn,ofs);
       string name = fn ? fn->name() : string("<temp>");
       cerr << "bad ODS: class " << pc->name() << " fn "
	        << name << '(' << ofs << ')' << "ptr " << obj << endl;
       exec_message("bad ODS entry ",true);
     break;
   }  
 }
}
#define CHECK_ODS check_ODS()
#else
#define CHECK_ODS
#endif


int throw_exception(Type t, void *thrown_obj)
// returns a valid offset into the catching function if successful;
// -1 otherwise
{
 try {
 static CatchHandler *curr_except = NULL;
 if (t == t_void) {
  // we are re-raising this exception! (see Parser::do_throw())
   // we assume that the stack has already been unwound past the 
   // try block marker we hit last...
   t = curr_except->thrown_type();
   thrown_obj = curr_except->thrown_object();
 } else curr_except = NULL;
 int n  = mODS.depth();
 if (!n) return -1;
 for(int i = 0; i < n; i++)
 {
   PClass pc;
   void *obj;
   mODS.fetch_object(i,pc,obj);
   if (pc == Parser::try_block_class()) {
     // first field is our catch handler
     curr_except = (CatchHandler *) *(unsigned int *)obj;
     int ip = curr_except->match_thrown_object(t,thrown_obj);
     if (ip != -1) {
        do_unwind(obj,mODS);  // unwind up to (&including) the try block marker  
        while (fb != curr_except->fun_block()) end_function();
        return ip;
     }// if (...we matched a catch block...) 
   } // if (...we hit a try block marker ...)
 } // for(...all entries in ODS .....
 } catch(...) {
   cerr << "bomb out handling exception" << endl;
 }
 // *fix 0.9.5 Will attempt to unwind the stack if the exception is uncaught
 do_unwind(NULL,mODS);
 return -1; // nobody wanted to catch this type!!
}

void *ventry(int slot, int offs)
{
  return (*(void ***)(mOP+offs))[slot];
}


//--------------- THE STACK ENGINE --------------------------
#define REF(T,p)    (*(T *)(p))
#define REFS(T)     (*(T *)pop())
#define REFA(T,p,a) (*((T *)(p)+(a)))
#define REFP(T,p)   (*(T **)(p))
#define NEXT(p)     ((int *)p)+1


int switch_jump(int *sb, int val)
// Switch jump tables look like this:
//  (num. entries) (default jump) (1st val) (1st jmp) .....
{
  int sz = *sb++, def = *sb++;
  while (sz && *sb != val) { sb++; sb++; sz--; }
  if (sz)  return *(sb+1);
      else return def;
}

void Engine::kill(int retcode)
{ 
  ppcode = (Instruction *)end_of_code;
}

void reset_stacks()
{
 if (fs.depth() > 0) {
   cerr << "reseting stacks\n";
   reset_execution_stack();
   fs.clear();   
 }
 // *fix 1.2.8 reset_stacks() will ALWAYS clear out the resume state
 resume_state.m_fb = NULL;  // flag us as NOT paused    
}

// *change 1.2.4 separated out code for determining full function name
string fname_from_fblock(FBlock* fun_block)
{
   if (fun_block == Parser::temp_fun_block()) return "<temp>";
   return Function::from_fun_block(fun_block)->as_str();
}

// *change 1.2.3 Function tracing is now controlled by the XTrace object
// *add 1.2.4 Can switch off default exit behaviour
// *change 1.2.4 Now dumps out full function name when tracing
// *change 1.2.4 No return value for enter() and leave() methods
XTrace::XTrace(bool on_exit)
  : m_on_entry(true), m_on_exit(on_exit) { }

void XTrace::enter(XExecState* xs)
{
   cerr << "*ENTER " << fname_from_fblock(xs->fb) << endl;
}

void XTrace::leave(XExecState* xs)
{
   cerr << "*LEAVE " << fname_from_fblock(xs->fb) << endl;
}

void get_stack_frame(int fi, ExecutionState& xs);

XExecState* get_exec_state()
{
  static XExecState xs;
  ExecutionState exs;
  get_stack_frame(1,exs);
  xs.fb = fb;
  xs.ip = ppcode;
  xs.op = mOP;
  xs.sp = mSP;
  xs.bp = baseSP;
  xs.last_fb = exs.m_fb;
  xs.last_ip = exs.m_ppcode;
  xs.last_bp = exs.m_baseSP;
  return &xs;
}

// *add 1.2.4 Can switch tracing on & off globally
static bool gCanTrace = true;

void engine_set_tracing(bool yesno)
{ gCanTrace = yesno; }

void start_function(FBlock *_fb)
{
#ifdef _DEBUG
 if (gFunBlock == fb)
      __break(3);
#endif
  fs.push(ppcode);
  if (fs.depth() > FUNCTION_STACK_DEPTH) {
      reset_stacks();
      throw Exception("Function Stack Overflow");
  }
  fs.push(fb);
  ppcode = _fb->pstart;
  fb = _fb;
  fs.push(baseSP);  
  if (ppcode == NULL) { // *add 1.2.4 report full function name
      static string tmps = fname_from_fblock(_fb) + " is not defined yet";
      throw Exception(tmps.c_str());   // shd be cool for a _static_ string...
  }
  if (resume_state.m_fb == NULL) baseSP = mSP;
  else if (_fb->nlocal == 100) { baseSP = resume_state.m_baseSP; return; } //fiddle!
  else baseSP = mSP;
  mSP -= _fb->nlocal;
  // *add 0.9.4 Stack Overflow check in start_function
  if ((long)mSP < (long)_stack_) throw Exception("Exec Stack overflow");

  ptr_check = Parser::debug.ptr_check;

// *add 1.2.4 Can control default entry behaviour for trace
  if (gCanTrace && _fb->trace && _fb->trace->do_enter()) {
     // suppress tracing while in custom trace method
	  XExecState* xs = get_exec_state();
      gCanTrace = false;
      _fb->trace->enter(xs);
	  gCanTrace = true;
     // and copy function state back to allow for re-dispatching
	  fb = xs->fb;
	  ppcode = (Instruction*)xs->ip;
	  mSP = xs->sp;
      baseSP = xs->bp;
  }
}

// *add 1.2.4 Can switch off default exit behaviour for trace
void end_function()
{
#ifdef _DEBUG
 if (gFunBlock == fb)
      __break(3);
#endif
 if (fb->trace && gCanTrace && fb->trace->do_leave()) {
      gCanTrace = false;
      fb->trace->leave(get_exec_state());
	  gCanTrace = true;
 }
 baseSP = (int *)fs.pop();
 fb = (FBlock *)fs.pop();
 ppcode = (Instruction *)fs.pop();  
}

void *fs_ptr(int offs)
{
    return *fs.ref_to_TOS(offs);
}


// *add 1.1.1 Dumping the stack frame after a breakpoint halt
void get_stack_frame(int fi, ExecutionState& xs)
{
  if (fi == 0) {
    xs.m_baseSP = baseSP;
    xs.m_fb = fb;
    xs.m_ppcode = ppcode;
  } else {
    int offs = -3*(fi-1);
    xs.m_baseSP = (int *)fs_ptr(offs);
    xs.m_fb     = (FBlock *)fs_ptr(offs-1);
    xs.m_ppcode = (Instruction *)fs_ptr(offs-2);
  }
}

int stack_frame_depth()
{ return fs.depth()/3 - 1; }  // i.e. not interested in <temp>!

// *change 1.2.8 write out full name of function....
// the report is now in a more parser-friendly format.
void dump_fun_frame(int i, const ExecutionState& xs)
{  
	LineInfo li;
    FBlock *this_fb = xs.m_fb;
    if (this_fb == START_FB) cmsg << i << " <DLL> 0 <function>" << endl;
    else {
      FunctionContext *fcxt = (FunctionContext *)this_fb->context;
      li.ip_offset = (xs.m_ppcode - this_fb->pstart)/sizeof(Instruction);
      if (fcxt && fcxt->ip_to_line(li)) 
          ;           
      else {
          li.file = "<none>";
          li.line = -2;
      }
      cmsg << i << ' ' << li.file << ' ' << li.line+2 << ' '
           << fname_from_fblock(this_fb) << endl;
    }
}

void dump_fun_stack()
{
    ExecutionState xs;

    for(int i = 0, n = stack_frame_depth(); i < n; i++) {
       get_stack_frame(i,xs);
	   dump_fun_frame(i,xs);
    }
}

int *find_main_baseSP(char *fct)
{
   ExecutionState xs;

   for(int i = 0, n = stack_frame_depth(); i < n; i++) {
       get_stack_frame(i,xs);
	   if (xs.m_fb->function->name()==fct) {
		   get_stack_frame(i-1,xs);
		   cout << "called from main: " << xs.m_fb->function->name() << endl;
		   return xs.m_baseSP;
       }
   }
   return NULL;
}

void Engine::attach_main_context(char *fct)
{
	Table *cntxt = Function::lookup(fct)->context();
	Parser::state.push_context(cntxt);
	baseSP = find_main_baseSP(fct);
}

// *add 1.1.1 Selecting a stack frame while halted
void Engine::set_frame(int i, bool verbose)
{
    ExecutionState xs;
    LineInfo li;
    Parser::state.pop_context();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -