#ifndef INSTR_HPP__ #define INSTR_HPP__ /** * \file instr.hpp * \author Mason Smith * Contains all of the non-arithmetic VM instructions */ #include #include #include #include #include #include "value.hpp" #include "exception.hpp" using boost::shared_ptr; using std::string; namespace BMD { class Actor; class VM; //! an instruction is merely a functor typedef void (* InstructionFunc)(VM*); /** * Instruction. * base instruction class that all operations must inherit from */ class Instruction { public: virtual void execute(VM* vm) = 0; virtual bool is_return() const { return false; } int get_line_number() const { return line_number; } void set_line_number(int _line_number) { line_number = _line_number; } virtual ~Instruction() { } private: int line_number; int op_num; }; /** * Some instructions take optional arguments. Internally, they are sometimes * represented with different classes. Instructions where the *opcode* * doesn't not take an argument is denoted by a _NP prefix after the name. * For instance, the class getelem_NP_instr corresponds to the opcode that * takes no arguments. */ /** * const Instruction. * loads a constant value into the accumulator */ class const_instr : public Instruction { public: const_instr() { } const_instr(Value cvr) : v(cvr) { } void execute(VM* vm); private: Value v; }; class pop_instr : public Instruction { public: pop_instr(int _n = 1) : num_elements(_n) { } void execute(VM* vm); private: int num_elements; }; /** * push_sf instruction. * pushes the stack frame */ class push_sf_instr : public Instruction { public: push_sf_instr(int _ret_addr) : ret_addr(_ret_addr) { } void execute(VM* vm); private: int ret_addr; }; /** * assign instruction. * sets a certain stack position to the accumulator */ class assign_instr : public Instruction { public: assign_instr(int _pos) : pos(_pos) { } void execute(VM* vm); private: int pos; }; /** * acc instruction. * Load a stack element into the accumulator */ class acc_instr : public Instruction { public: acc_instr(int _pos) : pos(_pos) { } void execute(VM* vm); private: int pos; }; /** * rev_instr * Reverses the top [n] elements of the stack */ class rev_instr : public Instruction { public: rev_instr(int num_to_rev) : rev_num(num_to_rev) { } void execute(VM* vm); private: int rev_num; }; /************************************* * actor instructions ************************************/ /** * getfield instruction. * sets the accumulator to the specified actor field */ class get_field_instr : public Instruction { public: get_field_instr(int field_index) : index(field_index) { } void execute(VM* vm); private: int index; }; /** * setfield instruction. * sets the accumulator to the specified actor field */ class set_field_instr : public Instruction { public: set_field_instr(int field_index) : index(field_index) { } void execute(VM* vm); private: int index; }; /************************************* * block instructions ************************************/ /** * make_block instruction. * Creates a block with a particular runtime tag */ class make_block_instr : public Instruction { public: make_block_instr(Block::Tag t) : tag(t) { } void execute(VM* vm); private: Block::Tag tag; }; /** * makes a block with [n] copies of some element */ class make_filled_block_instr : public Instruction { public: make_filled_block_instr(Block::Tag t) : tag(t) { } void execute(VM* vm); private: Block::Tag tag; }; /** * make_block_static instruction. * Creates a block with a particular runtime tag, initialized * with elements from the stack */ class make_block_static_instr : public Instruction { public: make_block_static_instr(Block::Tag t, unsigned int _size) : tag(t), size(_size) { } void execute(VM* vm); private: Block::Tag tag; unsigned int size; }; /** * getelem instruction. * grabs a value from a block at a predetermined index */ class getelem_instr : public Instruction { public: getelem_instr(unsigned int _idx) : index(_idx) { } void execute(VM* vm); private: unsigned int index; }; /** * setelem instruction. * set a value in a block at a predetermined index */ class setelem_instr : public Instruction { public: setelem_instr(unsigned int _idx) : index(_idx) { } void execute(VM* vm); private: unsigned int index; }; /************************************* * jump instructions ************************************/ /** * call instruction. * Calls a function after the stack frame has been set up */ class call_instr : public Instruction { public: call_instr(string name, int _func_loc) : func_loc(_func_loc), func_name(name) { } void execute(VM* vm); private: int func_loc; string func_name; }; /** * apply instruction. * Applies a function, whose name is in the accumulator, to the arguments on * the stack. The stack must look like the stack would on a normal call. */ class apply_instr : public Instruction { public: apply_instr() { } void execute(VM* vm); }; /** * jump instruction * Jump unconditionally to a particularly location */ class jmp_instr : public Instruction { public: jmp_instr(int _loc) : loc(_loc) { } void execute(VM* vm); private: int loc; }; /** * jump-if-zero instruction * Jump to a particularly location if the accumulator is zero */ class jz_instr : public Instruction { public: jz_instr(int _loc) : loc(_loc) { } void execute(VM* vm); private: int loc; }; /** * jump-if-not-zero instruction * Jump to a particularly location if the accumulator is zero */ class jnz_instr : public Instruction { public: jnz_instr(int _loc) : loc(_loc) { } void execute(VM* vm); private: int loc; }; /** * rpc instruction * performs a remote procedure call */ class rpc_instr : public Instruction { public: rpc_instr(string _func_name) : func_name(_func_name) { } void execute(VM* vm); private: // helper functions for calling the vm bool handle_vm_call(VM* vm, Value& ret); bool handle_actor_call(VM* vm, Value& ret); string func_name; }; /************************************* * debugging opcodes ************************************/ /** * dumping instruction * prints a stack dump of the vm */ class stack_dump_instr : public Instruction { public: stack_dump_instr(string _title, int _num = 0) : title(_title), num_elements(_num) { } void execute(VM* vm); private: string title; int num_elements; }; /** * instruction-building instruction, useful for state-less instructions. * Creates an object which just calls the specified function */ template class InstructionNoParam : public Instruction { public: void execute(VM* vm) { f(vm); } }; /** * creates an instruction with name instr_name based on a function * func_name with header: * void func_name(VM* vm); */ #define MAKE_STATELESS_INSTR(func_name, instr_name) \ void func_name(VM* vm); \ typedef InstructionNoParam instr_name // stack operations MAKE_STATELESS_INSTR(push_func, push_instr); MAKE_STATELESS_INSTR(swap_func, swap_instr); // input/output operations MAKE_STATELESS_INSTR(read_func, read_instr); MAKE_STATELESS_INSTR(print_func, print_instr); MAKE_STATELESS_INSTR(println_func, println_instr); // VM state ops MAKE_STATELESS_INSTR(stop_func, stop_instr); MAKE_STATELESS_INSTR(return_func, return_temp_instr); class return_instr : public return_temp_instr { public: bool is_return() const { return true; } }; // list ops MAKE_STATELESS_INSTR(cons_func, cons_instr); MAKE_STATELESS_INSTR(car_func, car_instr); MAKE_STATELESS_INSTR(cdr_func, cdr_instr); MAKE_STATELESS_INSTR(nil_func, nil_instr); MAKE_STATELESS_INSTR(isnull_func, isnull_instr); // list/string opp MAKE_STATELESS_INSTR(concat_func, concat_instr); // block ops MAKE_STATELESS_INSTR(getelem_NP_func, getelem_NP_instr); MAKE_STATELESS_INSTR(setelem_NP_func, setelem_NP_instr); MAKE_STATELESS_INSTR(deref_func, deref_instr); MAKE_STATELESS_INSTR(setref_func, setref_instr); typedef shared_ptr InstructionRef; } #endif