protoverse

A metaverse protocol
git clone git://jb55.com/protoverse
Log | Files | Refs | README | LICENSE

commit 37590fca05d463c6b5c42085dd52843aea2fc4b7
parent 37169943d40b4f452b1ed3ce38a0c7c6a936e5f6
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  1 Aug 2021 11:38:38 -0700

op macro, cleanup ops

Diffstat:
Msrc/wasm.c | 477+++++++++++++++++++++++++++++++++++++------------------------------------------
1 file changed, 223 insertions(+), 254 deletions(-)

diff --git a/src/wasm.c b/src/wasm.c @@ -230,6 +230,40 @@ static INLINE struct val *stack_topval(struct wasm_interp *interp) return cursor_topval(&interp->stack); } +static INLINE struct val *stack_top_type(struct wasm_interp *interp, + enum valtype type) +{ + struct val *val; + if (unlikely(!(val = stack_topval(interp)))) { + interp_error(interp, "pop"); + return NULL; + } + if (val->type != type) { + interp_error(interp, + "type mismatch: got %s, expected %s", + valtype_name(val->type), + valtype_name(type) + ); + return NULL; + } + return val; +} + +static INLINE struct val *stack_top_i32(struct wasm_interp *interp) +{ + return stack_top_type(interp, val_i32); +} + +static INLINE struct val *stack_top_f32(struct wasm_interp *interp) +{ + return stack_top_type(interp, val_f32); +} + +static INLINE struct val *stack_top_f64(struct wasm_interp *interp) +{ + return stack_top_type(interp, val_f64); +} + static INLINE int cursor_pop_i32(struct cursor *stack, int *i) { struct val val; @@ -405,6 +439,18 @@ static INLINE void make_i32_val(struct val *val, int v) val->num.i32 = v; } +static INLINE void make_f64_val(struct val *val, double v) +{ + val->type = val_f64; + val->num.f64 = v; +} + +static INLINE void make_f32_val(struct val *val, float v) +{ + val->type = val_f32; + val->num.f32 = v; +} + static INLINE int stack_pushval(struct wasm_interp *interp, struct val *val) { return cursor_pushval(&interp->stack, val); @@ -3041,24 +3087,6 @@ static INLINE int interp_prep_binop(struct wasm_interp *interp, struct val *lhs, return 1; } -static int interp_i32_add(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32)) - return interp_error(interp, "add prep"); - c.num.i32 = lhs.num.i32 + rhs.num.i32; - return stack_pushval(interp, &c); -} - -static int interp_i32_sub(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32)) - return interp_error(interp, "sub prep"); - c.num.i32 = lhs.num.i32 - rhs.num.i32; - return stack_pushval(interp, &c); -} - static INLINE int set_fn_local(struct wasm_interp *interp, int fn, u32 ind, struct val *val) { @@ -3128,72 +3156,6 @@ static INLINE void make_i64_val(struct val *val, s64 v) val->num.i64 = v; } -static INLINE int interp_i32_lt_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) { - return interp_error(interp, "binop prep"); - } - c.num.i32 = lhs.num.i32 < rhs.num.i32; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i32_lt_u(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.u32 = lhs.num.u32 < rhs.num.u32; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i32_le_u(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.u32 = lhs.num.u32 <= rhs.num.u32; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i32_gt_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.i32 = lhs.num.i32 > rhs.num.i32; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_sub(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.num.i64 = lhs.num.i64 - rhs.num.i64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_ge_u(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.u32 = lhs.num.u64 >= rhs.num.u64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_ge_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.i32 = lhs.num.i64 >= rhs.num.i64; - return stack_pushval(interp, &c); -} - static INLINE int interp_i64_xor(struct wasm_interp *interp) { struct val lhs, rhs, c; @@ -3203,15 +3165,6 @@ static INLINE int interp_i64_xor(struct wasm_interp *interp) return stack_pushval(interp, &c); } -static INLINE int interp_i64_mul(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.num.i64 = lhs.num.i64 * rhs.num.i64; - return stack_pushval(interp, &c); -} - static INLINE int interp_i64_div_u(struct wasm_interp *interp) { struct val lhs, rhs, c; @@ -3233,90 +3186,36 @@ static int interp_i64_eqz(struct wasm_interp *interp) return cursor_pushval(&interp->stack, &res); } -static INLINE int interp_i64_and(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.num.i64 = lhs.num.i64 & rhs.num.i64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_add(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.num.i64 = lhs.num.i64 + rhs.num.i64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_gt_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.i32 = lhs.num.i64 > rhs.num.i64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_lt_u(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.i32 = lhs.num.u64 < rhs.num.u64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_lt_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.i32 = lhs.num.i64 < rhs.num.i64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_le_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.i32 = lhs.num.i64 <= rhs.num.i64; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i64_le_u(struct wasm_interp *interp) +static INLINE int interp_f64_abs(struct wasm_interp *interp) { - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) - return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.u32 = lhs.num.u64 <= rhs.num.u64; - return stack_pushval(interp, &c); + struct val *val; + if (unlikely(!(val = stack_top_f64(interp)))) + return interp_error(interp, "pop"); + if (val->num.f64 >= 0) + return 1; + val->num.f64 = -val->num.f64; + return 1; } -static INLINE int interp_i64_gt_u(struct wasm_interp *interp) +static INLINE int interp_f64_div(struct wasm_interp *interp) { struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_f64))) return interp_error(interp, "binop prep"); - c.type = val_i32; - c.num.i32 = lhs.num.u64 > rhs.num.u64; + if (rhs.num.f64 == 0) + return interp_error(interp, "congrats, you divided by zero"); + c.num.f64 = lhs.num.f64 / rhs.num.f64; return stack_pushval(interp, &c); } -static INLINE int interp_i32_gt_u(struct wasm_interp *interp) +static INLINE int interp_f32_div(struct wasm_interp *interp) { struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_f32))) return interp_error(interp, "binop prep"); - c.num.i32 = lhs.num.u32 > rhs.num.u32; + if (rhs.num.f32 == 0) + return interp_error(interp, "congrats, you divided by zero"); + c.num.f32 = lhs.num.f32 / rhs.num.f32; return stack_pushval(interp, &c); } @@ -3372,48 +3271,159 @@ static INLINE int interp_i32_rotl(struct wasm_interp *interp) return stack_pushval(interp, &c); } -static INLINE int interp_i32_ge_u(struct wasm_interp *interp) +static INLINE int interp_i64_const(struct wasm_interp *interp, s64 c) { - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.u32 = lhs.num.u32 >= rhs.num.u32; - return stack_pushval(interp, &c); + struct val val; + make_i64_val(&val, c); + return cursor_pushval(&interp->stack, &val); } -static INLINE int interp_i32_ge_s(struct wasm_interp *interp) +static INLINE int interp_i32_const(struct wasm_interp *interp, u32 c) { - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.i32 = lhs.num.i32 >= rhs.num.i32; - return stack_pushval(interp, &c); + struct val val; + make_i32_val(&val, c); + return cursor_pushval(&interp->stack, &val); } -static INLINE int interp_i32_le_s(struct wasm_interp *interp) +static INLINE int interp_f64_const(struct wasm_interp *interp, double c) { - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.i32 = lhs.num.i32 <= rhs.num.i32; - return stack_pushval(interp, &c); + struct val val; + make_f64_val(&val, c); + return stack_pushval(interp, &val); +} + +#define BINOP(type, name, op) \ +static INLINE int interp_##type##_##name(struct wasm_interp *interp) \ +{ \ + struct val lhs, rhs, c; \ + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_##type))) \ + return interp_error(interp, "binop prep"); \ + c.num.type = lhs.num.type op rhs.num.type; \ + return stack_pushval(interp, &c); \ +} + +#define BINOP2(type, optype, name, op) \ +static INLINE int interp_##type##_##name(struct wasm_interp *interp) \ +{ \ + struct val lhs, rhs, c; \ + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_##type))) \ + return interp_error(interp, "binop prep"); \ + return stack_push_i32(interp, lhs.num.optype op rhs.num.optype); \ +} + +BINOP(f64, mul, *) +BINOP(f32, mul, *) +BINOP(i32, mul, *) +BINOP(i64, mul, *) + +BINOP(f64, sub, -) +BINOP(f32, sub, -) +BINOP(i32, sub, -) +BINOP(i64, sub, -) + +BINOP(f64, add, +) +BINOP(f32, add, +) +BINOP(i32, add, +) +BINOP(i64, add, +) + +BINOP(i32, and, &) +BINOP(i64, and, &) + +BINOP(i32, or, |) +BINOP(i64, or, |) + +BINOP2(i32, i32, lt_s, <) +BINOP2(i64, i64, lt_s, <) +BINOP2(i32, u32, lt_u, <) +BINOP2(i64, u64, lt_u, <) +BINOP2(f32, f32, lt, <) +BINOP2(f64, f64, lt, <) + +BINOP2(i32, i32, gt_s, >) +BINOP2(i64, i64, gt_s, >) +BINOP2(i32, u32, gt_u, >) +BINOP2(i64, u64, gt_u, >) +BINOP2(f32, f32, gt, >) +BINOP2(f64, f64, gt, >) + +BINOP2(i32, i32, le_s, <=) +BINOP2(i64, i64, le_s, <=) +BINOP2(i32, u32, le_u, <=) +BINOP2(i64, u64, le_u, <=) +BINOP2(f32, f32, le, <=) +BINOP2(f64, f64, le, <=) + +BINOP2(i32, i32, ge_s, >=) +BINOP2(i64, i64, ge_s, >=) +BINOP2(i32, u32, ge_u, >=) +BINOP2(i64, u64, ge_u, >=) +BINOP2(f32, f32, ge, >=) +BINOP2(f64, f64, ge, >=) + +static int interp_i32_rem_s(struct wasm_interp *interp) +{ + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) + return interp_error(interp, "binop prep"); + c.num.i32 = lhs.num.i32 % rhs.num.i32; + return stack_pushval(interp, &c); } -static INLINE int interp_i64_const(struct wasm_interp *interp, s64 c) +static int interp_i32_rem_u(struct wasm_interp *interp) { - struct val val; - make_i64_val(&val, c); - return cursor_pushval(&interp->stack, &val); + struct val lhs, rhs, c; + if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) + return interp_error(interp, "binop prep"); + c.num.u32 = lhs.num.u32 % rhs.num.u32; + return stack_pushval(interp, &c); } -static INLINE int interp_i32_const(struct wasm_interp *interp, u32 c) +static INLINE int interp_f32_const(struct wasm_interp *interp, float c) { struct val val; - make_i32_val(&val, c); + make_f32_val(&val, c); return cursor_pushval(&interp->stack, &val); } +static INLINE int interp_f32_neg(struct wasm_interp *interp) +{ + struct val *val; + if (unlikely(!(val = stack_top_f32(interp)))) + return interp_error(interp, "pop"); + val->num.f32 = -val->num.f32; + return 1; +} + +static INLINE int interp_f64_promote_f32(struct wasm_interp *interp) +{ + struct val *val; + if (unlikely(!(val = stack_top_f32(interp)))) + return interp_error(interp, "pop"); + make_f64_val(val, (double)val->num.f32); + return 1; +} + +static INLINE int interp_i32_reinterpret_f32(struct wasm_interp *interp) +{ + struct val *val; + if (unlikely(!(val = stack_top_f32(interp)))) + return interp_error(interp, "pop"); + make_i32_val(val, (int)val->num.f32); + return 1; +} + +static INLINE int interp_f32_convert_i32_s(struct wasm_interp *interp) +{ + float f; + struct val *val; + if (unlikely(!(val = stack_top_i32(interp)))) + return interp_error(interp, "pop"); + f = (float)val->num.i32; + make_f32_val(val, f); + return 1; +} + static INLINE int count_local_resolvers(struct wasm_interp *interp, int *count) { int offset; @@ -4981,6 +4991,10 @@ static int wrap_val(struct val *val, unsigned int size) { return 1; val->num.i64 &= (1ULL << size)-1; break; + case val_f32: + case val_f64: + return 1; + default: return 0; } @@ -5350,71 +5364,6 @@ static INLINE int interp_i32_ne(struct wasm_interp *interp) return stack_push_i32(interp, lhs.num.i32 != rhs.num.i32); } -static INLINE int interp_i32_mul(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) { - return interp_error(interp, "binop prep"); - } - - c.num.i32 = lhs.num.i32 * rhs.num.i32; - - return stack_pushval(interp, &c); -} - -static INLINE int interp_i32_or(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.i32 = lhs.num.i32 | rhs.num.i32; - return stack_pushval(interp, &c); -} - -static int interp_i32_rem_s(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.i32 = lhs.num.i32 % rhs.num.i32; - return stack_pushval(interp, &c); -} - -static int interp_i32_rem_u(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) - return interp_error(interp, "binop prep"); - c.num.u32 = lhs.num.u32 % rhs.num.u32; - return stack_pushval(interp, &c); -} - -static INLINE int interp_i32_and(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i32))) { - return interp_error(interp, "binop prep"); - } - - c.num.i32 = lhs.num.i32 & rhs.num.i32; - - return stack_pushval(interp, &c); -} - -static int interp_i64_or(struct wasm_interp *interp) -{ - struct val lhs, rhs, c; - - if (unlikely(!interp_prep_binop(interp, &lhs, &rhs, &c, val_i64))) { - return interp_error(interp, "binop prep"); - } - - c.num.i64 = lhs.num.i64 | rhs.num.i64; - return stack_pushval(interp, &c); -} - static int interp_i64_shl(struct wasm_interp *interp) { struct val lhs, rhs, c; @@ -5845,6 +5794,26 @@ static int interp_instr(struct wasm_interp *interp, struct instr *instr) case i_global_get: return interp_global_get(interp, instr->i32); case i_global_set: return interp_global_set(interp, instr->i32); + case i_f32_const: return interp_f32_const(interp, instr->f32); + case i_f32_div: return interp_f32_div(interp); + case i_f32_mul: return interp_f32_mul(interp); + case i_f32_neg: return interp_f32_neg(interp); + case i_f32_add: return interp_f32_add(interp); + case i_f32_sub: return interp_f32_sub(interp); + + case i_f32_convert_i32_s: return interp_f32_convert_i32_s(interp); + case i_i32_reinterpret_f32: return interp_i32_reinterpret_f32(interp); + case i_f64_promote_f32: return interp_f64_promote_f32(interp); + + case i_f64_abs: return interp_f64_abs(interp); + case i_f64_const: return interp_f64_const(interp, instr->f64); + case i_f64_div: return interp_f64_div(interp); + case i_f64_ge: return interp_f64_ge(interp); + case i_f64_gt: return interp_f64_gt(interp); + case i_f64_le: return interp_f64_le(interp); + case i_f64_lt: return interp_f64_lt(interp); + case i_f64_mul: return interp_f64_mul(interp); + case i_i32_clz: return interp_i32_clz(interp); case i_i32_ctz: return interp_i32_ctz(interp); case i_i32_popcnt: return interp_i32_popcnt(interp);