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

📄 engine.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 4 页
字号:
		int offs,bit_offs,bit_size, mask;
		unpack_bitfield(ppcode->data,offs,bit_offs,bit_size);
		mask = (1 << bit_size)-1;
		data = mOP + offs;
		if (opcode == PUSHIF) {
           val = *(unsigned int *)data;
		   val >>= bit_offs;
		   push(val & mask);
        } else {
		   unsigned word = *(unsigned *)data;	 
           val = pop();
		   mask <<= bit_offs; 
		   mask = ~ mask;
		   word &= mask;
		   val <<= bit_offs;
		   word |= val;
		   *(unsigned *)data = word;
        } 
	 } break;

    //...Miscelaneous (not likely to remain forever!)
    case SHOWI:
    case SHOWV:
    {
        Type t, te;
        PEntry ve;
        if (opcode==SHOWI) {
            t = *(Type *)data; ve = NULL;
            te = t;
        } else { 
            t = t_void;  ve = *(PEntry *)data;
            te = ve->type;
        }
        bool is_double = te.is_double() && !te.is_pointer();
        void *ptr = is_double ? (void *)&tos2() : (void *)&tos();
        Parser::dump_expression(t,ptr,ve);
        if(is_double) pop2(); else pop();
    } break;
    case HALT:
	// *change 1.2.4 if the operand is out of range, it's a NOP instruction!
	    if (ppcode->data < MAX_BREAKPOINTS) {
          if (Breakpoint::from_id(ppcode->data)->execute()) return false;
          continue; // don't move to next instruction!
         } 
		 break;
    case SHOWD:  cout << "(double) " << (rmode ? *(double *)data : pop2()) << endl; break;
    } // switch(opcode)
    ppcode++;   
    CHECK_ODS;
    if (s_stepping) {
	 // *add 1.2.4 Profiling support
     if (s_stepping == STEP_PROFILE) { instr_count++; continue; }	 
     if (ppcode == end_of_code) return true; // finished...
    // *add 1.2.7 working single-stepping 
    // while in this state, we're just looking for the current function block fb
    // to switch back to the initial fb
     if (s_stepping==STEPPING_OVER) {
      if (s_initial_fb == fb) {
        s_stepping = 0;
        s_current_exec_line = get_current_exec_line();        
        if (s_current_exec_line != -1 && s_current_exec_line != s_old_exec_line) return false;
        // it's possible we're back in the original fn, but at its end. So keep going.
        else s_stepping = STEPPING;
      }
     } else
    // normal state while we're single-stepping; jump out if the current line num
    // changes.
     if (s_stepping==STEPPING) {
      int nl = get_current_exec_line();
      ///  cout << "l = " << nl << " ip = " << current_ip() << "fb = " << fb << endl;
      if (nl != -1 && nl != s_current_exec_line) {
           s_old_exec_line = s_current_exec_line;
	       s_current_exec_line = nl;
          // we want to step over; has the current function changed?
          if (s_initial_fb && s_initial_fb != fb) {
             int sdepth = stack_frame_depth();
             if (sdepth > s_initial_stack_depth) {
                // we're entering a new function - let's step over it
                s_stepping = STEPPING_OVER;
             } else {
                // we're leaving a function; continue single-stepping
                s_stepping = STEPPING;
                s_initial_fb = fb;
                s_initial_stack_depth = sdepth;
             }
          } else {
	        s_stepping = 0;
	        return false;  // we are halted on the next line
          }
      }
     } else if (s_stepping == STEP_WAIT) {
		  s_current_exec_line = get_current_exec_line();
		  s_stepping = STEPPING;    
     } 
    }
  } // while(true)
  return true;  // cool, everything ok.
} 

bool Engine::set_single_stepping(bool single_step)
{
   Function* mfn = Function::lookup("main"); 
   s_main_fb = mfn->fun_block();
  // check to see if we are already halted at a breakpoint....
   if (paused() && s_brk != NULL) {
       s_stepping = STEPPING; //STEP_WAIT; 
   	   s_current_exec_line = get_current_exec_line();
   } else s_stepping = STEPPING; 
   s_initial_stack_depth = stack_frame_depth();
   if (single_step) s_initial_fb = NULL;
   else if (paused()) s_initial_fb = resume_state.m_fb;    
   else { // we're starting afresh w/ main
       s_initial_fb = s_main_fb;
       s_stepping = STEPPING_OVER;
   }	  
  return true;
}

//*fix 1.2.8 must explicitly reset single stepping
void Engine::reset_single_stepping()
{
	s_stepping = 0; 
}

FBlock *mStartFB;

extern FBlock mCodeBlock;
Instruction *old_immediate_code;

namespace Parser {
Instruction *immediate_code_ptr();
void immediate_code_ptr(Instruction *pi);
FBlock *immediate_code_block();
};

void dissemble(PFBlock fb); // in DISSEM

bool Engine::paused()   { return resume_state.m_fb != NULL; }
bool Engine::running()  { return fb != START_FB;          } 

bool get_current_exec_pos(int& ip_offs, string& fname,  LineInfo& li)
{
   FunctionContext *fcxt = NULL;
   if (fb) {
     fcxt = (FunctionContext *)fb->context;      
     fname = fname_from_fblock(fb);  // *change 1.2.4
   }
   ip_offs = current_ip();
   if (! fcxt) return false;
   li.ip_offset = ip_offs;
   return fcxt->ip_to_line(li); 
}


Table* context_of_function(LocalContext* lc)
{
   FunctionEntry* pfe = lc->function()->fun_entry();
   return pfe->reference()->context;
}

bool function_is_in_std(LocalContext* lc)
{
    return context_of_function(lc) == Parser::std_namespace();
}

// add 1.2.7 when single-stepping, we can avoid going
// into any function w/in the std namespace.
// *NOTE* 
// 1. wd it apply to methods of classes w/in std?
// 2. shd be a Function method - need it elsewhere.
int get_current_exec_line()
{
	LineInfo li;
	int ip_offs;
	string fname;
	bool ret = get_current_exec_pos(ip_offs,fname,li);
    if (ret && !(Parser::debug.no_trace_std 
        && function_is_in_std((LocalContext*)li.cntxt))) return li.line;
	else return -1;
}

void  exec_message(char *msg, bool was_error, bool dont_unwind_error)
{
 if (fb == START_FB) {
   cerr << msg << endl << "poppped!!" << endl;
   return;
 }
 int ip_offs;
 string fname;
 LineInfo li;
 bool trace_function = Parser::debug.function_trace;
 bool tracing_lines = true; // !trace_function;
 bool back_trace = false;
 
 if (trace_function && Parser::debug.verbose) {
  cerr << "*CRASH " << (void *)mOP << ' ' << (void *)mSP 
       << ' ' << (void *)baseSP << endl;
  }
  // set the error state!

 int kount = 0; // limit the number of trace back levels...
 try {
     do {
        bool have_info = get_current_exec_pos(ip_offs,fname,li);
        if (back_trace && ppcode != NULL) {
          if (have_info) cerr << li.file << ' ' << li.line << ": " << fname << endl;
          else cerr << "(" << ip_offs << ") " << fname << endl;
          if (++kount > 50) {
             cerr << "Too many trace messages" << endl;
             reset_stacks();
             return;
          }
        } else
        if(tracing_lines && have_info) {
            if (!was_error || dont_unwind_error) { 
                // *fix 1.2.8 set the local context _before_ we tell the IDE it's a break....
                Parser::state.push_context(li.cntxt);                          
                resume_state.save(ppcode,true);
                old_immediate_code = Parser::immediate_code_ptr();
                Errors::set_halt_state(msg,fname,li.file,li.line, was_error); 
                return;             
            }
            Errors::set_halt_state(msg,fname,li.file,li.line, was_error);           
            // Halted at breakpoint - prepare to resume, set up context
            // *add 1.2.8 or an error, but we want to preserve the context...
            // *add 0.9.2 Can stop as soon as we have a line no, unless we're tracing...
            mODS.clear();
            if (! trace_function) { reset_stacks(); return; } 
            else {
               cerr << "in " << fname << ":\n";
               back_trace = true;
            }
        }
        if (fs.depth()==0) break;  // *fix 0.9.6 Function Stack Overflow has already cleared this
        end_function();
        check_fun_block(fb);
     } while (fb != START_FB);
     reset_stacks();
     // *fix 1.2.4 Dump out final error message if we haven't found a line number...
     if (! tracing_lines || ! back_trace)
         Errors::set_halt_state(msg,fname,"",ip_offs,true);   
 } catch(...) {
  cerr << "Unknown crash" << endl;
 // *add 0.9.4 Must restore execution stack, esp. for stack overflow errors 
   reset_stacks();
 }  
}

// *change 1.2.9 the 'static ODS' has been retired.
void Engine::global_unwind()
{
  //do_unwind(NULL,mStaticODS);
   LoadedModuleList::run_global_finalization();
}

int handle_exception(PEntry epe, char *msg);

// *add 1.2.8 this is the entry point used by native code to call the interpreter
// so that we can pause the thread for debugging.
int __STDCALL Engine::stub_execute(FBlock* _fb, int flags, ArgBlock *xargs)
//-------------------------------------------------------------------------
{
    int ret;
    do {
     ret = execute(_fb,flags | FROM_OUTSIDE,xargs);
     if (ret == HALTED) {
         if (! Program::in_main_thread()) {
             Program::pause_thread();
             flags = RESUME;
         } 
         else ret = OK;
     }
    } while (ret == HALTED);
    return ret;
}

int __STDCALL Engine::execute(FBlock *_fb, int flags, ArgBlock *xargs)
//--------------------------------------------------------------------
{
  FBlock * old_fb = fb;
  Instruction *old_ppcode = ppcode;
  int *old_mSP = mSP;
  PEntry epe;
  char *except_msg;
resume_execution:
  try {
   if (flags & ARGS_PASSED) {              // only if execute() is called from outside UC
     xargs->flags = flags;                   // *fix 1.1.1 save flags and arg block so we can resume properly!
	 resume_state.m_xargs = xargs;
     if (flags & METHOD_CALL) opush(xargs->OPtr);  // the 'this' pointer 
     for(int i=0,n = xargs->no; i < n; i++)  // these are set by the native stub!!
         push(xargs->values[i]);
   }
   if (flags & RESUME) {     
	 bool context_pushed;
	 set_frame(0,false);                                 // *fix 1.1.1 ensure we're in proper frame!
     resume_state.restore(context_pushed,xargs);
	 if (xargs) flags = xargs->flags;                 // *fix 1.1.1 restore flags and arg block as well!
	 if (context_pushed) Parser::state.pop_context(); // i.e, we were halted by a breakpoint, which pushed the context..
     resume_state.m_fb = NULL;                          // flag us as NOT paused    
     Parser::immediate_code_ptr(old_immediate_code);  // and restore immediate execution context!
   } else { 
    mStartFB = _fb;
    // *fix 1.2.8 we only push START_FB if execute() is called from
    // w/in UCW; its only purpose is to give a 'false bottom' to
    // the function stack.
    if (flags & FROM_OUTSIDE) {
       fs.push(ppcode);
       fs.push(fb);
       fs.push(mSP);
    }
    fb = START_FB;
    ppcode = NULL;
    start_function(_fb);
   }

   // *fix 1.0.0L Some platforms need this to translate signals into C++ exceptions
   // See hard_except.h for the definition and hard_except.cpp for explanation
   CATCH_SIGNALS
   for(;;) {
    if (! start_exec()) { exec_message("halted at ",false); return HALTED; }
     else {
        if (flags & FROM_OUTSIDE) {
          old_mSP = (int*)fs.pop();
          old_fb = (FBlock*)fs.pop();
          old_ppcode = (Instruction*)fs.pop();
        }
        fb = old_fb;		
        ppcode = old_ppcode;        
        if (flags & ARGS_PASSED) {
           if (flags & METHOD_CALL) opop();
           if (flags & RETURN_32) xargs->ret1 = pop(); else
           if (flags & RETURN_64) xargs->ret2 = pop2();
        } else mSP = old_mSP;
        return OK; 
     }
   }
  }
  catch(Exception& e) {
  // map onto the corresp UC exception types. Note that uc_except.h
  // must be included for these to operate properly. (see Parser::init_lib())

    switch (e.type()) {
    case Exception::INT_DIV0:    epe = Parser::mEIntDivByZero;      break;
    case Exception::ACCESS:      epe = Parser::mEAccessViolation;   break;
    case Exception::FLOAT_DIV0:  epe = Parser::mEFloatDivByZero;    break;
    case Exception::RANGE_ERROR: epe = Parser::mERangeError;        break;
	case Exception::UNKNOWN:     epe = Parser::mEException;         break;
    default: epe = NULL;
    }
    except_msg = strdup(e.what()); //*??
  }
  catch(...) {
    // *fix 1.1.0 Translate as an unknown exception....
	epe = Parser::mEException;
    except_msg = "unknown";
  }
  // managing exceptions
  // *add 1.2.8 evaluating stuff which explodes during a debug session
  if (Engine::paused()) return HALTED;
   int ip = -1;
   if (epe != NULL) ip = throw_exception(epe->type,epe->global_ptr());
   if (ip == -1) { // plain uncaught exception message...
       // *add 1.2.8 treating errors as a break is now an option (doesn't unwind fun stack)
         bool break_on_error = Parser::debug.errors_as_break;
         exec_message(except_msg,true,break_on_error);
         return break_on_error ? HALTED : CRASHED;
   } else { // force execution to resume in catch block...!
     // *fix 0.9.4 Point is that throw_exception() will have dropped us 
     // into the right function context...
     // *fix 1.1.0 In this case we are _not_ pushing the local context!
      resume_state.save(fb->pstart+ip,false);
      flags = Engine::RESUME;
      goto resume_execution;
    }
}

int handle_exception(PEntry epe, char *msg)
{
    int ip = -1;
    if (epe != NULL) ip = throw_exception(epe->type,epe->global_ptr());
    if (ip == -1) { // plain uncaught exception message...
       try {
         exec_message(msg,true); return CRASHED;
       } catch(...) {
         cerr << "Disturbed....\n";   return CRASHED;
       }
    } else { // force execution to resume in catch block...!
     // *fix 0.9.4 Point is that throw_exception() will have dropped us 
     // into the right function context...
     // *fix 1.1.0 In this case we are _not_ pushing the local context!
      resume_state.save(fb->pstart+ip,false);
      return Engine::execute(NULL,Engine::RESUME);
    }
}

CatchHandler::CatchHandler(FBlock *fb)
  : m_fb(fb)
{
  m_end_label = new Label(&Parser::code());
}

void CatchHandler::add_catch_block(Type t, int ip_offs)
{
  CatchBlock *pcb = new CatchBlock;
  pcb->type = t;
  pcb->ip_offset = ip_offs;
  m_catch_blocks.push_back(pcb);
}

int CatchHandler::match_thrown_object(Type t, void *obj)
{
  CatchBlockList::iterator cbli;
  FORALL(cbli,m_catch_blocks) {
    Type ct = (*cbli)->type; 
 // *fix 0.9.5. Catch-block must match any derived class..
    if (ct == t || ct == t_void || t.inherits_from(ct)) {
      m_thrown_object = obj;
      m_thrown_type = t;
      *(void **)(Parser::mExceptObj->global_ptr()) = obj;
      return (*cbli)->ip_offset;
    }
  }
 return -1;
}

⌨️ 快捷键说明

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