#ifndef VM_HPP__ #define VM_HPP__ #include #include #include #include #include #include #include #include #include "value.hpp" #include "instr.hpp" #include "vm_func.hpp" using namespace std; using namespace boost; namespace BMD { class Actor; /** * function information on the stack */ struct function_call_data { function_call_data(string _func, vector::iterator beg, vector::iterator end, bool _local); string func_name; vector args; bool local_call; }; ostream& operator<< (ostream& o, const function_call_data& fcd); /** * Virtual Machine class. * Contains the logic for executing instructions from its parent actor. */ class VM { public: Actor* get_actor() const { return parent_actor; } /** stack pushing */ void push(); void push(Value vr); /** stack popping */ Value pop(); void pop(unsigned int num_entries); void pop_unsafe(unsigned int num_entries); /* stack element access */ Value get_stack_element(unsigned int stack_loc) const; void get_stack_elements(unsigned int num_elements, vector::iterator result) const; unsigned int get_stack_elements_unsafe(unsigned int num_elements, vector::iterator result) const; void set_stack_element(unsigned int stack_loc, Value vr); //! fills a vector with the stack arguments void get_call_arguments(vector& args) const; //! returns the number of arguments on the stack int get_num_call_arguments() const; //! reset running parameters void reset(); //! execute instruction void execute(InstructionRef i); //! execute instructions, starting at the current ip, given certain break //! conditions void run(int flags = 0); //! call a function from the active actor Value call_function(string func_name, const vector&, bool debug = false); Value get_accumulator() const; void set_accumulator(Value v); /** instruction pointer access */ int get_instruction_pointer() const { return ip; } void set_instruction_pointer(int i) { ip = i; } //! go up a stack frame void pop_stack_frame(); //! locate the position of the stack frame int get_stack_frame_location(); //! push a stack frame void push_stack_frame(int ret_addr); //! halt current program execution void stop() { running = false; } //! check program execution bool is_running() const { return running; } //! check the validity of the instruction pointer bool is_valid_ip() const; bool has_function(string& s) const { return vm_function_map.find(s) != vm_function_map.end(); } VMFunction get_function(string& s) const; void add_function(string name, VMFunction func); //! add a func void push_function_call(string name, int num_args = -1, bool local = true); void pop_function_call(); void print_call_stack(ostream& o = cout); void get_call_stack(vector& fc_stack, bool local); /* debugging functions */ void stack_dump(ostream& o); void set_debug_output(bool b) { debug_output = b; } static const int ALL_ARGUMENTS = -1; static const int STOP_AT_BREAKPOINTS = 1; static const int STOP_AT_RETURNS = 2; static const int STOP_AT_ASSERTIONS = 4; protected: static const unsigned int RETURN_ADDRESS_SIZE; private: friend class Actor; //! signals the compiler to be in "running" mode without actually executing //! any instructions void start() { running = true; } // virtual machines can only be created by // their parent actors VM(Actor* _parent_actor); VM(const VM& vm); ~VM() { } //! transform an internal stack location to an external stack location. int int_to_ext_stack(int loc) const { return stack.size() - 1 - loc; } int ext_to_int_stack(int loc) const { return stack.size() - 1 - loc; } /** Pointer to the actor where the VM gets its information. The VM is *not* responsible for deleting its parent actor. */ Actor* parent_actor; //! stack for local variables, function parameters, and call frames vector< Value > stack; //! stack for function call details vector< function_call_data > call_stack; //! registered vm functions map vm_function_map; //! instruction pointer int ip; //! accumulator (register) Value acc; /** stores the position of current stack frame * the position is in internal representation, *not* * in terms of the stack position */ int curr_sfp; //! true if an actor is currently executing bool running; //! controls whether or not stack information is printed while running bool debug_output; }; } #endif