--- /dev/null
+#ifndef _OVM_CODE_BUILDER_H
+#define _OVM_CODE_BUILDER_H
+
+#include "vm.h"
+
+typedef struct ovm_code_builder_t ovm_code_builder_t;
+
+//
+// A new code builder will be "made" for each function
+// being compiled.
+struct ovm_code_builder_t {
+ bh_arr(i32) execution_stack;
+
+ i32 param_count, local_count;
+
+ ovm_program_t *program;
+ i32 start_instr;
+};
+
+ovm_code_builder_t ovm_code_builder_new(ovm_program_t *program, i32 param_count, i32 local_count);
+void ovm_code_builder_add_binop(ovm_code_builder_t *builder, u32 instr);
+void ovm_code_builder_add_imm(ovm_code_builder_t *builder, u32 ovm_type, void *imm);
+
+
+#endif
--- /dev/null
+
+#include "vm_codebuilder.h"
+
+#define PUSH_VALUE(b, r) (bh_arr_push((b)->execution_stack, r))
+#define POP_VALUE(b) (bh_arr_length((b)->execution_stack) == 0 ? (assert(("invalid value pop", 0)), 0) : bh_arr_pop((b)->execution_stack))
+#define NEXT_VALUE(b) ((bh_arr_length((b)->execution_stack) == 0 ? (b)->param_count + (b)->local_count : bh_arr_last((b)->execution_stack)) + 1)
+
+// #define POP_VALUE(b) bh_arr_pop((b)->execution_stack)
+
+ovm_code_builder_t ovm_code_builder_new(ovm_program_t *program, i32 param_count, i32 local_count) {
+ ovm_code_builder_t builder;
+ builder.param_count = param_count;
+ builder.local_count = local_count;
+ builder.start_instr = bh_arr_length(program->code);
+ builder.program = program;
+
+ builder.execution_stack = NULL;
+ bh_arr_new(bh_heap_allocator(), builder.execution_stack, 32);
+
+ return builder;
+}
+
+
+void ovm_code_builder_add_binop(ovm_code_builder_t *builder, u32 instr) {
+ i32 right = POP_VALUE(builder);
+ i32 left = POP_VALUE(builder);
+ i32 result = NEXT_VALUE(builder);
+
+ ovm_instr_t binop;
+ binop.full_instr = instr;
+ binop.r = result;
+ binop.a = left;
+ binop.b = right;
+
+ ovm_program_add_instructions(builder->program, 1, &binop);
+ PUSH_VALUE(builder, result);
+}
+
+void ovm_code_builder_add_imm(ovm_code_builder_t *builder, u32 ovm_type, void *imm) {
+ ovm_instr_t imm_instr;
+ imm_instr.full_instr = OVM_TYPED_INSTR(OVMI_IMM, ovm_type);
+ imm_instr.r = NEXT_VALUE(builder);
+
+ switch (ovm_type) {
+ case OVM_TYPE_I8: imm_instr.i = (u32) *(u8 *) imm; break;
+ case OVM_TYPE_I16: imm_instr.i = (u32) *(u16 *) imm; break;
+ case OVM_TYPE_I32: imm_instr.i = *(u32 *) imm; break;
+ case OVM_TYPE_I64: imm_instr.l = *(u64 *) imm; break;
+ case OVM_TYPE_F32: imm_instr.f = *(f32 *) imm; break;
+ case OVM_TYPE_F64: imm_instr.d = *(f64 *) imm; break;
+ default: assert(("bad ovm type for add_imm", 0));
+ }
+
+ ovm_program_add_instructions(builder->program, 1, &imm_instr);
+ PUSH_VALUE(builder, imm_instr.r);
+}
+