// // Instructions // enum{ INS_PUSH_S64, INS_PUSH_S32, INS_PUSH_S16, INS_PUSH_S8 , INS_PUSH_U64, INS_PUSH_U32, INS_PUSH_U16, INS_PUSH_U8 , INS_PUSH_F64 , INS_PUSH_F32 , INS_POP, INS_ADD, INS_SUB, INS_MUL, INS_DIV, }; // // Bytecode interpreter context // struct Bc{ U8 *ins_pointer; U8 *stack_pointer; U8 *stack_bottom; Arena instructions; Arena stack; }; #define C(type, data) ((type *)data)[0] // Cast value to type and unpack the pointer so you can write to it #include "bytecode_interpreter_generated.cpp" function Bc create_bytecode_interp(){ Bc b = {}; { arena_init(&b.instructions, "Bytecode instructions"_s); b.instructions.alignment = 1; // Commit arena_push_size(&b.instructions, 16); arena_clear(&b.instructions); b.ins_pointer = b.instructions.memory.data; } { arena_init(&b.stack, "Bytecode stack"_s); b.stack.alignment = 8; // Commit arena_push_size(&b.stack, 16); arena_clear(&b.stack); b.stack_pointer = b.stack_bottom = b.stack.memory.data; } return b; } force_inline void emit_pop(Bc *bc){ U8 *instruction = (U8 *)arena_push_size(&bc->instructions, sizeof(U8)); *instruction = INS_POP; } force_inline void * stack_pop(Bc *b){ assert_msg(b->stack_pointer != b->stack_bottom, "Reached bottom of bytecode interpreter stack"); b->stack_pointer -= sizeof(U64); // @warning we don't do anything with type for now Ast_Type_Kind *type = (Ast_Type_Kind *)b->stack_pointer; b->stack_pointer -= sizeof(U64); return b->stack_pointer; } function void run_bytecode_interp(Bc *b){ for(;;){ U8 instruction = *b->ins_pointer++; switch(instruction){ case INS_POP:{ void *value = stack_pop(b); S64 *s64 = (S64 *)value; F64 *f64 = (F64 *)value; U64 *u64 = (U64 *)value; } break; // // Generated using code_generating_script.py // case INS_PUSH_S64:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (S64 *)b->ins_pointer; b->ins_pointer += sizeof(S64); stack_push_s64(b, *value); } break; case INS_PUSH_S32:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (S32 *)b->ins_pointer; b->ins_pointer += sizeof(S32); stack_push_s32(b, *value); } break; case INS_PUSH_S16:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (S16 *)b->ins_pointer; b->ins_pointer += sizeof(S16); stack_push_s16(b, *value); } break; case INS_PUSH_S8:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (S8 *)b->ins_pointer; b->ins_pointer += sizeof(S8); stack_push_s8(b, *value); } break; case INS_PUSH_U64:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (U64 *)b->ins_pointer; b->ins_pointer += sizeof(U64); stack_push_u64(b, *value); } break; case INS_PUSH_U32:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (U32 *)b->ins_pointer; b->ins_pointer += sizeof(U32); stack_push_u32(b, *value); } break; case INS_PUSH_U16:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (U16 *)b->ins_pointer; b->ins_pointer += sizeof(U16); stack_push_u16(b, *value); } break; case INS_PUSH_U8:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (U8 *)b->ins_pointer; b->ins_pointer += sizeof(U8); stack_push_u8(b, *value); } break; case INS_PUSH_F32:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (F32 *)b->ins_pointer; b->ins_pointer += sizeof(F32); stack_push_f32(b, *value); } break; case INS_PUSH_F64:{ // Fetch value from instruction // instructions are tightly packed so we // move pointer by the type size auto value = (F64 *)b->ins_pointer; b->ins_pointer += sizeof(F64); stack_push_f64(b, *value); } break; // // **End** of generated using code_generating_script.py // default: invalid_codepath; } } } function void test_interpreter(){ Bc b = create_bytecode_interp(); emit_push_s64(&b, 1); emit_push_f64(&b, 2.42f); emit_push_s8(&b, 3); emit_push_u16(&b, 4); emit_pop(&b); emit_pop(&b); emit_pop(&b); emit_pop(&b); run_bytecode_interp(&b); }