#include "vm_codebuilder.h"
+#define BUILDER_DEBUG
+
+#if defined(BUILDER_DEBUG)
+ #define POP_VALUE(b) (bh_arr_length((b)->execution_stack) == 0 ? (assert(("invalid value pop", 0)), 0) : bh_arr_pop((b)->execution_stack))
+#else
+ #define POP_VALUE(b) bh_arr_pop((b)->execution_stack)
+#endif
+
#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 POP_VALUE(b) bh_arr_pop((b)->execution_stack)
static inline int NEXT_VALUE(ovm_code_builder_t *b) {
+#if defined(BUILDER_DEBUG)
+ b->highest_value_number += 1;
+ return b->highest_value_number;
+
+#else
if (bh_arr_length(b->execution_stack) == 0) {
return b->param_count + b->local_count;
}
-
+
b->highest_value_number = bh_max(b->highest_value_number, bh_arr_last(b->execution_stack));
return bh_arr_last(b->execution_stack) + 1;
+#endif
}
ovm_code_builder_t ovm_code_builder_new(ovm_program_t *program, i32 param_count, i32 local_count) {
bh_arr_free(builder->branch_patches);
}
+label_target_t ovm_code_builder_wasm_target_idx(ovm_code_builder_t *builder, i32 idx) {
+ i32 walker = bh_arr_length(builder->label_stack) - 1 - idx;
+ assert(walker >= 0);
+ return builder->label_stack[walker];
+}
+
+i32 ovm_code_builder_push_label_target(ovm_code_builder_t *builder, label_kind_t kind) {
+ label_target_t target;
+ target.kind = kind;
+ target.idx = builder->next_label_idx++;
+ target.instr = -1;
+
+ if (kind == label_kind_loop) {
+ target.instr = bh_arr_length(builder->program->code);
+ }
+
+ bh_arr_push(builder->label_stack, target);
+
+ return target.idx;
+}
+
+void ovm_code_builder_pop_label_target(ovm_code_builder_t *builder) {
+ label_target_t target = bh_arr_pop(builder->label_stack);
+ if (target.instr == -1) {
+ target.instr = bh_arr_length(builder->program->code);
+ }
+
+ fori (i, 0, bh_arr_length(builder->branch_patches)) {
+ branch_patch_t patch = builder->branch_patches[i];
+ if (patch.label_idx != target.idx) continue;
+
+ int br_delta = target.instr - patch.branch_instr - 1;
+
+ switch (patch.kind) {
+ case branch_patch_instr_a:
+ builder->program->code[patch.branch_instr].a = br_delta;
+ break;
+
+ case branch_patch_static_idx:
+ ovm_program_modify_static_int(builder->program, patch.static_arr, patch.static_idx, br_delta);
+ break;
+ }
+
+ bh_arr_fastdelete(builder->branch_patches, i);
+ i--;
+ }
+}
+
void ovm_code_builder_add_binop(ovm_code_builder_t *builder, u32 instr) {
i32 right = POP_VALUE(builder);
i32 left = POP_VALUE(builder);
ovm_program_add_instructions(builder->program, 1, &branch_instr);
}
-void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx) {
+void ovm_code_builder_add_cond_branch(ovm_code_builder_t *builder, i32 label_idx, bool branch_if_true) {
ovm_instr_t branch_instr = {0};
- branch_instr.full_instr = OVMI_BR_Z;
+ if (branch_if_true) {
+ branch_instr.full_instr = OVMI_BR_NZ;
+ } else {
+ branch_instr.full_instr = OVMI_BR_Z;
+ }
+
branch_instr.a = -1;
branch_instr.b = POP_VALUE(builder);
}
void ovm_code_builder_add_load(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
- if (offset == 0) {
- ovm_instr_t load_instr = {0};
- load_instr.full_instr = OVM_TYPED_INSTR(OVMI_LOAD, ovm_type);
- load_instr.a = POP_VALUE(builder);
- load_instr.r = NEXT_VALUE(builder);
-
- ovm_program_add_instructions(builder->program, 1, &load_instr);
-
- PUSH_VALUE(builder, load_instr.r);
- return;
- }
+ ovm_instr_t load_instr = {0};
+ load_instr.full_instr = OVM_TYPED_INSTR(OVMI_LOAD, ovm_type);
+ load_instr.b = offset;
+ load_instr.a = POP_VALUE(builder);
+ load_instr.r = NEXT_VALUE(builder);
- ovm_instr_t instrs[3] = {0};
- // imm.i32 %n, offset
- instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32);
- instrs[0].i = offset;
- instrs[0].r = NEXT_VALUE(builder);
+ ovm_program_add_instructions(builder->program, 1, &load_instr);
- // add.i32 %n, %n, %i
- instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32);
- instrs[1].r = instrs[0].r;
- instrs[1].a = POP_VALUE(builder);
- instrs[1].b = instrs[0].r;
-
- // load.x %m, %n
- instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_LOAD, ovm_type);
- instrs[2].r = NEXT_VALUE(builder);
- instrs[2].a = instrs[1].r;
-
- ovm_program_add_instructions(builder->program, 3, instrs);
-
- PUSH_VALUE(builder, instrs[2].r);
+ PUSH_VALUE(builder, load_instr.r);
}
void ovm_code_builder_add_store(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
- if (offset == 0) {
- ovm_instr_t store_instr = {0};
- store_instr.full_instr = OVM_TYPED_INSTR(OVMI_STORE, ovm_type);
- store_instr.b = POP_VALUE(builder);
- store_instr.a = POP_VALUE(builder);
-
- ovm_program_add_instructions(builder->program, 1, &store_instr);
- return;
- }
-
- ovm_instr_t instrs[3] = {0};
-
- // TODO: explain the ordering here.
-
- // imm.i32 %n, offset
- instrs[0].full_instr = OVM_TYPED_INSTR(OVMI_IMM, OVM_TYPE_I32);
- instrs[0].i = offset;
- instrs[0].r = NEXT_VALUE(builder);
-
- instrs[2].b = POP_VALUE(builder);
-
- // add.i32 %n, %n, %i
- instrs[1].full_instr = OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32);
- instrs[1].r = instrs[0].r;
- instrs[1].a = POP_VALUE(builder);
- instrs[1].b = instrs[0].r;
-
- // store.x %m, %n
- instrs[2].full_instr = OVM_TYPED_INSTR(OVMI_STORE, ovm_type);
- instrs[2].a = instrs[1].r;
-
- ovm_program_add_instructions(builder->program, 3, instrs);
+ ovm_instr_t store_instr = {0};
+ store_instr.full_instr = OVM_TYPED_INSTR(OVMI_STORE, ovm_type);
+ store_instr.b = offset;
+ store_instr.a = POP_VALUE(builder);
+ store_instr.r = POP_VALUE(builder);
+
+ ovm_program_add_instructions(builder->program, 1, &store_instr);
+ return;
}
void ovm_code_builder_add_cmpxchg(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
ovm_program_add_instructions(builder->program, 1, &instr);
}
+
+//
+// CopyNPaste from _add_load
+void ovm_code_builder_add_atomic_load(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
+ ovm_instr_t load_instr = {0};
+ load_instr.full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_LOAD, ovm_type);
+ load_instr.b = offset;
+ load_instr.a = POP_VALUE(builder);
+ load_instr.r = NEXT_VALUE(builder);
+
+ ovm_program_add_instructions(builder->program, 1, &load_instr);
+
+ PUSH_VALUE(builder, load_instr.r);
+}
+
+//
+// CopyNPaste from _add_store
+void ovm_code_builder_add_atomic_store(ovm_code_builder_t *builder, u32 ovm_type, i32 offset) {
+ ovm_instr_t store_instr = {0};
+ store_instr.full_instr = OVM_TYPED_INSTR(OVMI_ATOMIC | OVMI_STORE, ovm_type);
+ store_instr.b = offset;
+ store_instr.a = POP_VALUE(builder);
+ store_instr.r = POP_VALUE(builder);
+
+ ovm_program_add_instructions(builder->program, 1, &store_instr);
+}
#include <math.h> // REMOVE THIS!!! only needed for sqrt
#include <pthread.h>
+
+static inline void ovm_print_val(ovm_value_t val) {
+ switch (val.type) {
+ case OVM_TYPE_I32: printf("i32[%d]", val.i32); break;
+ case OVM_TYPE_I64: printf("i64[%ld]", val.i64); break;
+ case OVM_TYPE_F32: printf("f32[%f]", val.f32); break;
+ case OVM_TYPE_F64: printf("f64[%lf]", val.f64); break;
+ }
+}
+
+
//
// Store
ovm_store_t *ovm_store_new() {
C(OVM_TYPED_INSTR(OVMI_DIV, OVM_TYPE_F32))
C(OVM_TYPED_INSTR(OVMI_DIV, OVM_TYPE_F64))
+ C(OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I8))
+ C(OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I16))
+ C(OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I32))
+ C(OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I64))
+ C(OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_F32))
+ C(OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_F64))
+
C(OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I8))
C(OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I16))
C(OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I32))
C(OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I64))
+ C(OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I8))
+ C(OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I16))
+ C(OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I32))
+ C(OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I64))
+
C(OVM_TYPED_INSTR(OVMI_AND, OVM_TYPE_I8))
C(OVM_TYPED_INSTR(OVMI_AND, OVM_TYPE_I16))
C(OVM_TYPED_INSTR(OVMI_AND, OVM_TYPE_I32))
state->params = NULL;
state->stack_frames = NULL;
state->registers = NULL;
- bh_arr_new(store->heap_allocator, state->numbered_values, 64);
+ bh_arr_new(store->heap_allocator, state->numbered_values, 128);
bh_arr_new(store->heap_allocator, state->params, 16);
bh_arr_new(store->heap_allocator, state->stack_frames, 32);
bh_arr_new(store->heap_allocator, state->registers, program->register_count);
OVM_OP(OVMI_MUL, OVM_TYPE_F32, *, f32)
OVM_OP(OVMI_MUL, OVM_TYPE_F64, *, f64)
- OVM_OP(OVMI_DIV, OVM_TYPE_I8 , /, i8)
- OVM_OP(OVMI_DIV, OVM_TYPE_I16, /, i16)
- OVM_OP(OVMI_DIV, OVM_TYPE_I32, /, i32)
- OVM_OP(OVMI_DIV, OVM_TYPE_I64, /, i64)
+ OVM_OP(OVMI_DIV, OVM_TYPE_I8 , /, u8)
+ OVM_OP(OVMI_DIV, OVM_TYPE_I16, /, u16)
+ OVM_OP(OVMI_DIV, OVM_TYPE_I32, /, u32)
+ OVM_OP(OVMI_DIV, OVM_TYPE_I64, /, u64)
OVM_OP(OVMI_DIV, OVM_TYPE_F32, /, f32)
OVM_OP(OVMI_DIV, OVM_TYPE_F64, /, f64)
- OVM_OP(OVMI_REM, OVM_TYPE_I8 , %, i8)
- OVM_OP(OVMI_REM, OVM_TYPE_I16, %, i16)
- OVM_OP(OVMI_REM, OVM_TYPE_I32, %, i32)
- OVM_OP(OVMI_REM, OVM_TYPE_I64, %, i64)
+ OVM_OP(OVMI_DIV_S, OVM_TYPE_I8 , /, i8)
+ OVM_OP(OVMI_DIV_S, OVM_TYPE_I16, /, i16)
+ OVM_OP(OVMI_DIV_S, OVM_TYPE_I32, /, i32)
+ OVM_OP(OVMI_DIV_S, OVM_TYPE_I64, /, i64)
+ OVM_OP(OVMI_DIV_S, OVM_TYPE_F32, /, f32)
+ OVM_OP(OVMI_DIV_S, OVM_TYPE_F64, /, f64)
+
+ OVM_OP(OVMI_REM, OVM_TYPE_I8 , %, u8)
+ OVM_OP(OVMI_REM, OVM_TYPE_I16, %, u16)
+ OVM_OP(OVMI_REM, OVM_TYPE_I32, %, u32)
+ OVM_OP(OVMI_REM, OVM_TYPE_I64, %, u64)
+
+ OVM_OP(OVMI_REM_S, OVM_TYPE_I8 , %, i8)
+ OVM_OP(OVMI_REM_S, OVM_TYPE_I16, %, i16)
+ OVM_OP(OVMI_REM_S, OVM_TYPE_I32, %, i32)
+ OVM_OP(OVMI_REM_S, OVM_TYPE_I64, %, i64)
OVM_OP(OVMI_AND, OVM_TYPE_I8 , &, i8)
OVM_OP(OVMI_AND, OVM_TYPE_I16, &, i16)
OVM_OP(OVMI_OR, OVM_TYPE_I32, |, i32)
OVM_OP(OVMI_OR, OVM_TYPE_I64, |, i64)
+ OVM_OP(OVMI_XOR, OVM_TYPE_I8 , ^, i8)
+ OVM_OP(OVMI_XOR, OVM_TYPE_I16, ^, i16)
+ OVM_OP(OVMI_XOR, OVM_TYPE_I32, ^, i32)
+ OVM_OP(OVMI_XOR, OVM_TYPE_I64, ^, i64)
+
OVM_OP(OVMI_SHL, OVM_TYPE_I8 , <<, i8)
OVM_OP(OVMI_SHL, OVM_TYPE_I16, <<, i16)
OVM_OP(OVMI_SHL, OVM_TYPE_I32, <<, i32)
OVM_OP(OVMI_SHL, OVM_TYPE_I64, <<, i64)
- OVM_OP(OVMI_SHR, OVM_TYPE_I8 , >> (u8), i8)
- OVM_OP(OVMI_SHR, OVM_TYPE_I16, >> (u16), i16)
- OVM_OP(OVMI_SHR, OVM_TYPE_I32, >> (u32), i32)
- OVM_OP(OVMI_SHR, OVM_TYPE_I64, >> (u64), i64)
+ OVM_OP(OVMI_SHR, OVM_TYPE_I8 , >>, u8)
+ OVM_OP(OVMI_SHR, OVM_TYPE_I16, >>, u16)
+ OVM_OP(OVMI_SHR, OVM_TYPE_I32, >>, u32)
+ OVM_OP(OVMI_SHR, OVM_TYPE_I64, >>, u64)
- OVM_OP(OVMI_SAR, OVM_TYPE_I8 , >> (i8), i8)
- OVM_OP(OVMI_SAR, OVM_TYPE_I16, >> (i16), i16)
- OVM_OP(OVMI_SAR, OVM_TYPE_I32, >> (i32), i32)
- OVM_OP(OVMI_SAR, OVM_TYPE_I64, >> (i64), i64)
+ OVM_OP(OVMI_SAR, OVM_TYPE_I8 , >>, i8)
+ OVM_OP(OVMI_SAR, OVM_TYPE_I16, >>, i16)
+ OVM_OP(OVMI_SAR, OVM_TYPE_I32, >>, i32)
+ OVM_OP(OVMI_SAR, OVM_TYPE_I64, >>, i64)
#undef OVM_OP
VAL(instr.r).ctype = func( VAL(instr.a).ctype, VAL(instr.b).ctype ); \
break;
- OVM_OP(OVMI_ROTL, OVM_TYPE_I8 , __rolb, i8)
- OVM_OP(OVMI_ROTL, OVM_TYPE_I16, __rolw, i16)
- OVM_OP(OVMI_ROTL, OVM_TYPE_I32, __rold, i32)
- OVM_OP(OVMI_ROTL, OVM_TYPE_I64, __rolq, i64)
+ OVM_OP(OVMI_ROTL, OVM_TYPE_I8 , __rolb, u8)
+ OVM_OP(OVMI_ROTL, OVM_TYPE_I16, __rolw, u16)
+ OVM_OP(OVMI_ROTL, OVM_TYPE_I32, __rold, u32)
+ OVM_OP(OVMI_ROTL, OVM_TYPE_I64, __rolq, u64)
- OVM_OP(OVMI_ROTR, OVM_TYPE_I8 , __rorb, i8)
- OVM_OP(OVMI_ROTR, OVM_TYPE_I16, __rorw, i16)
- OVM_OP(OVMI_ROTR, OVM_TYPE_I32, __rord, i32)
- OVM_OP(OVMI_ROTR, OVM_TYPE_I64, __rorq, i64)
+ OVM_OP(OVMI_ROTR, OVM_TYPE_I8 , __rorb, u8)
+ OVM_OP(OVMI_ROTR, OVM_TYPE_I16, __rorw, u16)
+ OVM_OP(OVMI_ROTR, OVM_TYPE_I32, __rord, u32)
+ OVM_OP(OVMI_ROTR, OVM_TYPE_I64, __rorq, u64)
OVM_OP(OVMI_MIN, OVM_TYPE_F32, bh_min, f32)
OVM_OP(OVMI_MAX, OVM_TYPE_F32, bh_max, f32)
VAL(instr.r).ctype = (ctype) op (VAL(instr.a).ctype); \
break;
- OVM_OP(OVMI_CLZ, OVM_TYPE_I8 , __builtin_clz, i8)
- OVM_OP(OVMI_CLZ, OVM_TYPE_I16, __builtin_clz, i16)
- OVM_OP(OVMI_CLZ, OVM_TYPE_I32, __builtin_clz, i32)
- OVM_OP(OVMI_CLZ, OVM_TYPE_I64, __builtin_clz, i64)
+ OVM_OP(OVMI_CLZ, OVM_TYPE_I8 , __builtin_clz, u8)
+ OVM_OP(OVMI_CLZ, OVM_TYPE_I16, __builtin_clz, u16)
+ OVM_OP(OVMI_CLZ, OVM_TYPE_I32, __builtin_clz, u32)
+ OVM_OP(OVMI_CLZ, OVM_TYPE_I64, __builtin_clz, u64)
- OVM_OP(OVMI_CTZ, OVM_TYPE_I8 , __builtin_ctz, i8)
- OVM_OP(OVMI_CTZ, OVM_TYPE_I16, __builtin_ctz, i16)
- OVM_OP(OVMI_CTZ, OVM_TYPE_I32, __builtin_ctz, i32)
- OVM_OP(OVMI_CTZ, OVM_TYPE_I64, __builtin_ctz, i64)
+ OVM_OP(OVMI_CTZ, OVM_TYPE_I8 , __builtin_ctz, u8)
+ OVM_OP(OVMI_CTZ, OVM_TYPE_I16, __builtin_ctz, u16)
+ OVM_OP(OVMI_CTZ, OVM_TYPE_I32, __builtin_ctz, u32)
+ OVM_OP(OVMI_CTZ, OVM_TYPE_I64, __builtin_ctz, u64)
- OVM_OP(OVMI_POPCNT, OVM_TYPE_I8 , __builtin_popcount, i8)
- OVM_OP(OVMI_POPCNT, OVM_TYPE_I16, __builtin_popcount, i16)
- OVM_OP(OVMI_POPCNT, OVM_TYPE_I32, __builtin_popcount, i32)
- OVM_OP(OVMI_POPCNT, OVM_TYPE_I64, __builtin_popcount, i64)
+ OVM_OP(OVMI_POPCNT, OVM_TYPE_I8 , __builtin_popcount, u8)
+ OVM_OP(OVMI_POPCNT, OVM_TYPE_I16, __builtin_popcount, u16)
+ OVM_OP(OVMI_POPCNT, OVM_TYPE_I32, __builtin_popcount, u32)
+ OVM_OP(OVMI_POPCNT, OVM_TYPE_I64, __builtin_popcount, u64)
OVM_OP(OVMI_ABS, OVM_TYPE_F32, __ovm_abs, f32);
OVM_OP(OVMI_NEG, OVM_TYPE_F32, -, f32);
#define OVM_OP(i, t, op, ctype, cast_type) \
case OVM_TYPED_INSTR(i, t): \
VAL(instr.r).type = OVM_TYPE_I32; \
- VAL(instr.r).i32 = (i32) ((cast_type) VAL(instr.a).ctype op (cast_type) VAL(instr.b).ctype); \
+ VAL(instr.r).i32 = (i32) (VAL(instr.a).ctype op VAL(instr.b).ctype); \
break;
- OVM_OP(OVMI_LT, OVM_TYPE_I8 , <, i8, u8)
- OVM_OP(OVMI_LT, OVM_TYPE_I16, <, i16, u16)
- OVM_OP(OVMI_LT, OVM_TYPE_I32, <, i32, u32)
- OVM_OP(OVMI_LT, OVM_TYPE_I64, <, i64, u64)
+ OVM_OP(OVMI_LT, OVM_TYPE_I8 , <, u8, u8)
+ OVM_OP(OVMI_LT, OVM_TYPE_I16, <, u16, u16)
+ OVM_OP(OVMI_LT, OVM_TYPE_I32, <, u32, u32)
+ OVM_OP(OVMI_LT, OVM_TYPE_I64, <, u64, u64)
OVM_OP(OVMI_LT, OVM_TYPE_F32, <, f32, f32)
OVM_OP(OVMI_LT, OVM_TYPE_F64, <, f64, f32)
OVM_OP(OVMI_LT_S, OVM_TYPE_F32, <, f32, f32)
OVM_OP(OVMI_LT_S, OVM_TYPE_F64, <, f64, f32)
- OVM_OP(OVMI_LE, OVM_TYPE_I8 , <=, i8, u8)
- OVM_OP(OVMI_LE, OVM_TYPE_I16, <=, i16, u16)
- OVM_OP(OVMI_LE, OVM_TYPE_I32, <=, i32, u32)
- OVM_OP(OVMI_LE, OVM_TYPE_I64, <=, i64, u64)
+ OVM_OP(OVMI_LE, OVM_TYPE_I8 , <=, u8, u8)
+ OVM_OP(OVMI_LE, OVM_TYPE_I16, <=, u16, u16)
+ OVM_OP(OVMI_LE, OVM_TYPE_I32, <=, u32, u32)
+ OVM_OP(OVMI_LE, OVM_TYPE_I64, <=, u64, u64)
OVM_OP(OVMI_LE, OVM_TYPE_F32, <=, f32, f32)
OVM_OP(OVMI_LE, OVM_TYPE_F64, <=, f64, f64)
OVM_OP(OVMI_EQ, OVM_TYPE_F32, ==, f32, f32)
OVM_OP(OVMI_EQ, OVM_TYPE_F64, ==, f64, f64)
- OVM_OP(OVMI_GE, OVM_TYPE_I8 , >=, i8, u8)
- OVM_OP(OVMI_GE, OVM_TYPE_I16, >=, i16, u16)
- OVM_OP(OVMI_GE, OVM_TYPE_I32, >=, i32, u32)
- OVM_OP(OVMI_GE, OVM_TYPE_I64, >=, i64, u64)
+ OVM_OP(OVMI_GE, OVM_TYPE_I8 , >=, u8, u8)
+ OVM_OP(OVMI_GE, OVM_TYPE_I16, >=, u16, u16)
+ OVM_OP(OVMI_GE, OVM_TYPE_I32, >=, u32, u32)
+ OVM_OP(OVMI_GE, OVM_TYPE_I64, >=, u64, u64)
OVM_OP(OVMI_GE, OVM_TYPE_F32, >=, f32, f32)
OVM_OP(OVMI_GE, OVM_TYPE_F64, >=, f64, f64)
OVM_OP(OVMI_GE_S, OVM_TYPE_F32, >=, f32, f32)
OVM_OP(OVMI_GE_S, OVM_TYPE_F64, >=, f64, f64)
- OVM_OP(OVMI_GT, OVM_TYPE_I8 , >, i8, u8)
- OVM_OP(OVMI_GT, OVM_TYPE_I16, >, i16, u16)
- OVM_OP(OVMI_GT, OVM_TYPE_I32, >, i32, u32)
- OVM_OP(OVMI_GT, OVM_TYPE_I64, >, i64, u64)
+ OVM_OP(OVMI_GT, OVM_TYPE_I8 , >, u8, u8)
+ OVM_OP(OVMI_GT, OVM_TYPE_I16, >, u16, u16)
+ OVM_OP(OVMI_GT, OVM_TYPE_I32, >, u32, u32)
+ OVM_OP(OVMI_GT, OVM_TYPE_I64, >, u64, u64)
OVM_OP(OVMI_GT, OVM_TYPE_F32, >, f32, f32)
OVM_OP(OVMI_GT, OVM_TYPE_F64, >, f64, f64)
break;
#define OVM_LOAD(type_, stype) \
- case OVM_TYPED_INSTR(OVMI_LOAD, type_): \
+ case OVM_TYPED_INSTR(OVMI_LOAD, type_): {\
assert(VAL(instr.a).type == OVM_TYPE_I32); \
VAL(instr.r).type = type_; \
- VAL(instr.r).stype = * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32]; \
- break;
+ VAL(instr.r).stype = * (stype *) &((u8 *) engine->memory)[VAL(instr.a).u32 + instr.b]; \
+ break; \
+ }
OVM_LOAD(OVM_TYPE_I8, i8)
OVM_LOAD(OVM_TYPE_I16, i16)
#define OVM_STORE(type_, stype) \
case OVM_TYPED_INSTR(OVMI_STORE, type_): \
- assert(VAL(instr.a).type == OVM_TYPE_I32); \
- * (stype *) &((u8 *) engine->memory)[(u32) VAL(instr.a).i32] = VAL(instr.b).stype; \
+ assert(VAL(instr.r).type == OVM_TYPE_I32); \
+ * (stype *) &((u8 *) engine->memory)[VAL(instr.r).u32 + instr.b] = VAL(instr.a).stype; \
break;
OVM_STORE(OVM_TYPE_I8, i8)
i32 count = VAL(instr.b).i32;
u8 *base = engine->memory;
- memcpy(&base[dest], &base[src], count);
+ memmove(&base[dest], &base[src], count);
break;
}
VAL(frame.return_number_value) = val;
}
+ printf("Returning from %s to %s: ", frame.func->name, bh_arr_last(state->stack_frames).func->name);
+ ovm_print_val(val);
+ printf("\n\n");
+
state->pc = frame.return_address;
break;
}
#define CMPXCHG(otype, ctype) \
case OVM_TYPED_INSTR(OVMI_CMPXCHG, otype): {\
ctype *addr = (ctype *) &((u8 *) engine->memory)[VAL(instr.r).i32]; \
+ \
+ VAL(instr.r).i32 = 0; \
+ VAL(instr.r).type = otype; \
+ VAL(instr.r).ctype = *addr; \
+ \
if (*addr == VAL(instr.a).ctype) { \
*addr = VAL(instr.b).ctype ; \
} \
- VAL(instr.r).type = otype; \
- VAL(instr.r).ctype = *addr; \
break; \
}
// Instruction building
//
-static int push_label_target(build_context *ctx, label_kind_t kind) {
- label_target_t target;
- target.kind = kind;
- target.idx = ctx->builder.next_label_idx++;
- target.instr = -1;
-
- if (kind == label_kind_loop) {
- target.instr = bh_arr_length(ctx->program->code);
- }
-
- bh_arr_push(ctx->builder.label_stack, target);
-
- return target.idx;
-}
-
-static void pop_label_target(build_context *ctx) {
- label_target_t target = bh_arr_pop(ctx->builder.label_stack);
- if (target.instr == -1) {
- target.instr = bh_arr_length(ctx->program->code);
- }
-
- fori (i, 0, bh_arr_length(ctx->builder.branch_patches)) {
- branch_patch_t patch = ctx->builder.branch_patches[i];
- if (patch.label_idx != target.idx) continue;
-
- int br_delta = target.instr - patch.branch_instr - 1;
-
- switch (patch.kind) {
- case branch_patch_instr_a:
- ctx->program->code[patch.branch_instr].a = br_delta;
- break;
-
- case branch_patch_static_idx:
- ovm_program_modify_static_int(ctx->program, patch.static_arr, patch.static_idx, br_delta);
- break;
- }
-
- bh_arr_fastdelete(ctx->builder.branch_patches, i);
- i--;
- }
-}
-
static void parse_expression(build_context *ctx);
static void parse_fc_instruction(build_context *ctx) {
case num : { \
int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); \
int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); \
- ovm_code_builder_add_load(&ctx->builder, OVMI_ATOMIC | type, offset); \
+ ovm_code_builder_add_atomic_load(&ctx->builder, type, offset); \
break; \
}
case num : { \
int alignment = uleb128_to_uint(ctx->binary.data, &ctx->offset); \
int offset = uleb128_to_uint(ctx->binary.data, &ctx->offset); \
- ovm_code_builder_add_store(&ctx->builder, OVMI_ATOMIC | type, offset); \
+ ovm_code_builder_add_atomic_store(&ctx->builder, type, offset); \
break; \
}
case 0x02: {
// Currently, only "void" block types are valid.
assert(CONSUME_BYTE(ctx) == 0x40);
- push_label_target(ctx, label_kind_block);
+ ovm_code_builder_push_label_target(&ctx->builder, label_kind_block);
break;
}
case 0x03: {
// Currently, only "void" block types are valid.
assert(CONSUME_BYTE(ctx) == 0x40);
- push_label_target(ctx, label_kind_loop);
+ ovm_code_builder_push_label_target(&ctx->builder, label_kind_loop);
break;
}
case 0x04: {
// Currently, only "void" block types are valid.
assert(CONSUME_BYTE(ctx) == 0x40);
- int if_target = push_label_target(ctx, label_kind_block);
+ int if_target = ovm_code_builder_push_label_target(&ctx->builder, label_kind_if);
//
// This uses the pattern of "branch if zero" to skip a section of
// code if the condition was not true.
- ovm_code_builder_add_cond_branch(&ctx->builder, if_target);
+ ovm_code_builder_add_cond_branch(&ctx->builder, if_target, false);
break;
}
// Therefore, this "peeks" at what the next label index will be, so it can
// know what label to track for where to jump. It feels like there should be
// a better way to do this.
- ovm_code_builder_add_branch(&ctx->builder, bh_arr_last(ctx->builder.label_stack).idx);
- pop_label_target(ctx);
- push_label_target(ctx, label_kind_block);
+ ovm_code_builder_pop_label_target(&ctx->builder);
+ int else_target = ovm_code_builder_push_label_target(&ctx->builder, label_kind_if);
+ ovm_code_builder_add_branch(&ctx->builder, else_target);
break;
}
case 0x0B: {
- pop_label_target(ctx);
+ ovm_code_builder_pop_label_target(&ctx->builder);
break;
}
case 0x0C: {
int label_idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
- label_target_t target = *((&bh_arr_last(ctx->builder.label_stack)) - label_idx);
+ label_target_t target = ovm_code_builder_wasm_target_idx(&ctx->builder, label_idx);
ovm_code_builder_add_branch(&ctx->builder, target.idx);
break;
}
case 0x0D: {
int label_idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
- label_target_t target = *((&bh_arr_last(ctx->builder.label_stack)) - label_idx);
- ovm_code_builder_add_cond_branch(&ctx->builder, target.idx);
+ label_target_t target = ovm_code_builder_wasm_target_idx(&ctx->builder, label_idx);
+ ovm_code_builder_add_cond_branch(&ctx->builder, target.idx, true);
break;
}
int entry_count = uleb128_to_uint(ctx->binary.data, &ctx->offset);
int *entries = bh_alloc_array(bh_heap_allocator(), int, entry_count);
- int label_stack_count = bh_arr_length(ctx->builder.label_stack);
fori (i, 0, entry_count) {
- entries[i] = ctx->builder.label_stack[label_stack_count - 1 - uleb128_to_uint(ctx->binary.data, &ctx->offset)].idx;
+ int label_idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+ label_target_t target = ovm_code_builder_wasm_target_idx(&ctx->builder, label_idx);
+ entries[i] = target.idx;
}
- int default_entry = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+ int default_entry_idx = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+ label_target_t target = ovm_code_builder_wasm_target_idx(&ctx->builder, default_entry_idx);
+ int default_entry = target.idx;
ovm_code_builder_add_branch_table(&ctx->builder, entry_count, entries, default_entry);
break;
}
case 0x41: {
- int value = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+ long long value = leb128_to_int(ctx->binary.data, &ctx->offset);
+
+ // NOTE: This assumes a little-endian CPU as the address is assumes
+ // to be the least significant byte.
ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &value);
break;
}
case 0x42: {
- long long value = uleb128_to_uint(ctx->binary.data, &ctx->offset);
+ unsigned long long value = uleb128_to_uint(ctx->binary.data, &ctx->offset);
ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I64, &value);
break;
}
}
case 0x45: {
- int zero = 0;
+ unsigned int zero = 0;
ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I32, &zero);
ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I32));
break;
}
-
case 0x46: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I32)); break;
case 0x47: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_NE, OVM_TYPE_I32)); break;
case 0x48: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_LT_S, OVM_TYPE_I32)); break;
case 0x4F: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_GE, OVM_TYPE_I32)); break;
case 0x50: {
- long long zero = 0;
+ unsigned long long zero = 0;
ovm_code_builder_add_imm(&ctx->builder, OVM_TYPE_I64, &zero);
ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_EQ, OVM_TYPE_I64));
break;
case 0x6A: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I32)); break;
case 0x6B: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_SUB, OVM_TYPE_I32)); break;
case 0x6C: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_MUL, OVM_TYPE_I32)); break;
- case 0x6D: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV, OVM_TYPE_I32)); break;
- case 0x6E: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I32)); break;
- case 0x6F: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I32)); break;
- case 0x70: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I32)); break;
+ case 0x6D: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I32)); break;
+ case 0x6E: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV, OVM_TYPE_I32)); break;
+ case 0x6F: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I32)); break;
+ case 0x70: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I32)); break;
case 0x71: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_AND, OVM_TYPE_I32)); break;
case 0x72: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_OR, OVM_TYPE_I32)); break;
case 0x73: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_XOR, OVM_TYPE_I32)); break;
case 0x7C: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_ADD, OVM_TYPE_I64)); break;
case 0x7D: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_SUB, OVM_TYPE_I64)); break;
case 0x7E: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_MUL, OVM_TYPE_I64)); break;
- case 0x7F: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV, OVM_TYPE_I64)); break;
- case 0x80: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I64)); break;
- case 0x81: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I64)); break;
- case 0x82: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I64)); break;
+ case 0x7F: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV_S, OVM_TYPE_I64)); break;
+ case 0x80: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_DIV, OVM_TYPE_I64)); break;
+ case 0x81: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM_S, OVM_TYPE_I64)); break;
+ case 0x82: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_REM, OVM_TYPE_I64)); break;
case 0x83: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_AND, OVM_TYPE_I64)); break;
case 0x84: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_OR, OVM_TYPE_I64)); break;
case 0x85: ovm_code_builder_add_binop(&ctx->builder, OVM_TYPED_INSTR(OVMI_XOR, OVM_TYPE_I64)); break;
ctx->builder = ovm_code_builder_new(ctx->program, param_count, total_locals);
ctx->builder.func_table_arr_idx = ctx->func_table_arr_idx;
- push_label_target(ctx, label_kind_func);
+ ovm_code_builder_push_label_target(&ctx->builder, label_kind_func);
parse_expression(ctx);
ovm_code_builder_add_return(&ctx->builder);
+ ovm_code_builder_pop_label_target(&ctx->builder);
char *func_name = bh_aprintf(bh_heap_allocator(), "wasm_loaded_%d", bh_arr_length(ctx->program->funcs));
ovm_program_register_func(ctx->program, func_name, ctx->builder.start_instr, ctx->builder.param_count, ctx->builder.highest_value_number + 1);