From a0d21fd9b85f8389204b38cae470cbbcf4d626fb Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Mon, 24 Oct 2016 12:59:14 +0200 Subject: [PATCH 1/5] Add reserved flags to call_indirect, current/grow_memory --- interpreter/spec/decode.ml | 13 ++++++++++--- interpreter/spec/encode.ml | 6 +++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/interpreter/spec/decode.ml b/interpreter/spec/decode.ml index 134f6b6b4d..cfe3d9b7eb 100644 --- a/interpreter/spec/decode.ml +++ b/interpreter/spec/decode.ml @@ -240,7 +240,10 @@ let rec instr s = | 0x15 -> set_local (at var s) | 0x16 -> call (at var s) - | 0x17 -> call_indirect (at var s) + | 0x17 -> + let x = at var s in + expect 0x00 s "zero flag expected"; + call_indirect x | 0x19 -> tee_local (at var s) @@ -273,9 +276,13 @@ let rec instr s = | 0x37 | 0x38 as b -> illegal s pos b - | 0x39 -> grow_memory + | 0x39 -> + expect 0x00 s "zero flag expected"; + grow_memory | 0x3a as b -> illegal s pos b - | 0x3b -> current_memory + | 0x3b -> + expect 0x00 s "zero flag expected"; + current_memory | 0x3c | 0x3d | 0x3e | 0x3f as b -> illegal s pos b diff --git a/interpreter/spec/encode.ml b/interpreter/spec/encode.ml index 147c169dd6..72aba91331 100644 --- a/interpreter/spec/encode.ml +++ b/interpreter/spec/encode.ml @@ -165,7 +165,7 @@ let encode m = | SetGlobal x -> op 0xbc; var x | Call x -> op 0x16; var x - | CallIndirect x -> op 0x17; var x + | CallIndirect x -> op 0x17; var x; u8 0x00 | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x2a; memop mo | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x2b; memop mo @@ -208,8 +208,8 @@ let encode m = | Store ({ty = I64Type; sz = Some Mem32; _} as mo) -> op 0x32; memop mo | Store {ty = F32Type | F64Type; sz = Some _; _} -> assert false - | GrowMemory -> op 0x39 - | CurrentMemory -> op 0x3b + | GrowMemory -> op 0x39; u8 0x00 + | CurrentMemory -> op 0x3b; u8 0x00 | Unary (I32 I32Op.Clz) -> op 0x57 | Unary (I32 I32Op.Ctz) -> op 0x58 From 8d7c69802c207fa8cd2fd3d552aa5d72d422fe1e Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Mon, 24 Oct 2016 14:10:57 +0200 Subject: [PATCH 2/5] Reorg opcode space --- interpreter/README.md | 14 +- interpreter/spec/ast.ml | 18 +- interpreter/spec/decode.ml | 412 ++++++++++++++++++------------------ interpreter/spec/encode.ml | 390 +++++++++++++++++----------------- interpreter/spec/eval.ml | 70 +++--- interpreter/spec/valid.ml | 58 ++--- interpreter/text/arrange.ml | 68 +++--- interpreter/text/parser.mly | 12 +- 8 files changed, 526 insertions(+), 516 deletions(-) diff --git a/interpreter/README.md b/interpreter/README.md index 1e6f9b3d02..72f263a446 100644 --- a/interpreter/README.md +++ b/interpreter/README.md @@ -164,27 +164,29 @@ instr: op: unreachable nop - drop - select br br_if br_table + return call call_indirect + drop + select get_local set_local tee_local + get_global + set_global + .load((8|16|32)_)? ? ? + .store(8|16|32)? ? ? + current_memory + grow_memory .const . . . . ./ - .load((8|16|32)_)? ? ? - .store(8|16|32)? ? ? - current_memory - grow_memory func: ( func ? * * ) ( func ? ( export ) * * ) ;; = (export (func ) (func ? * *) diff --git a/interpreter/spec/ast.ml b/interpreter/spec/ast.ml index 1bbf9a1dd4..d59ec46f63 100644 --- a/interpreter/spec/ast.ml +++ b/interpreter/spec/ast.ml @@ -27,7 +27,7 @@ struct type binop = Add | Sub | Mul | DivS | DivU | RemS | RemU | And | Or | Xor | Shl | ShrS | ShrU | Rotl | Rotr type testop = Eqz - type relop = Eq | Ne | LtS | LtU | LeS | LeU | GtS | GtU | GeS | GeU + type relop = Eq | Ne | LtS | LtU | GtS | GtU | LeS | LeU | GeS | GeU type cvtop = ExtendSI32 | ExtendUI32 | WrapI64 | TruncSF32 | TruncUF32 | TruncSF64 | TruncUF64 | ReinterpretFloat @@ -38,7 +38,7 @@ struct type unop = Neg | Abs | Ceil | Floor | Trunc | Nearest | Sqrt type binop = Add | Sub | Mul | Div | Min | Max | CopySign type testop - type relop = Eq | Ne | Lt | Le | Gt | Ge + type relop = Eq | Ne | Lt | Gt | Le | Ge type cvtop = ConvertSI32 | ConvertUI32 | ConvertSI64 | ConvertUI64 | PromoteF32 | DemoteF64 | ReinterpretInt @@ -70,17 +70,17 @@ type instr = instr' Source.phrase and instr' = | Unreachable (* trap unconditionally *) | Nop (* do nothing *) - | Drop (* forget a value *) - | Select (* branchless conditional *) | Block of stack_type * instr list (* execute in sequence *) | Loop of stack_type * instr list (* loop header *) + | If of stack_type * instr list * instr list (* conditional *) | Br of var (* break to n-th surrounding label *) | BrIf of var (* conditional break *) | BrTable of var list * var (* indexed break *) | Return (* break from function body *) - | If of stack_type * instr list * instr list (* conditional *) | Call of var (* call function *) | CallIndirect of var (* call function through table *) + | Drop (* forget a value *) + | Select (* branchless conditional *) | GetLocal of var (* read local variable *) | SetLocal of var (* write local variable *) | TeeLocal of var (* write local variable and keep value *) @@ -88,14 +88,14 @@ and instr' = | SetGlobal of var (* write global variable *) | Load of loadop (* read memory at address *) | Store of storeop (* write memory at address *) + | CurrentMemory (* size of linear memory *) + | GrowMemory (* grow linear memory *) | Const of literal (* constant *) - | Unary of unop (* unary numeric operator *) - | Binary of binop (* binary numeric operator *) | Test of testop (* numeric test *) | Compare of relop (* numeric comparison *) + | Unary of unop (* unary numeric operator *) + | Binary of binop (* binary numeric operator *) | Convert of cvtop (* conversion *) - | CurrentMemory (* size of linear memory *) - | GrowMemory (* grow linear memory *) (* Globals & Functions *) diff --git a/interpreter/spec/decode.ml b/interpreter/spec/decode.ml index cfe3d9b7eb..e5de5d67aa 100644 --- a/interpreter/spec/decode.ml +++ b/interpreter/spec/decode.ml @@ -184,6 +184,7 @@ open Operators let var s = vu32 s let op s = u8 s +let end_ s = expect 0x0b s "END opcode expected" let memop s = let align = vu32 s in @@ -195,237 +196,240 @@ let rec instr s = let pos = pos s in match op s with | 0x00 -> unreachable - | 0x01 -> + | 0x01 -> nop + + | 0x02 -> let ts = stack_type s in let es' = instr_block s in - expect 0x0f s "END opcode expected"; + end_ s; block ts es' - | 0x02 -> + | 0x03 -> let ts = stack_type s in let es' = instr_block s in - expect 0x0f s "END opcode expected"; + end_ s; loop ts es' - | 0x03 -> + | 0x04 -> let ts = stack_type s in let es1 = instr_block s in - if peek s = Some 0x04 then begin - expect 0x04 s "`else` or `end` opcode expected"; + if peek s = Some 0x05 then begin + expect 0x05 s "ELSE or END opcode expected"; let es2 = instr_block s in - expect 0x0f s "END opcode expected"; + end_ s; if_ ts es1 es2 end else begin - expect 0x0f s "END opcode expected"; + end_ s; if_ ts es1 [] end - | 0x04 -> error s pos "misplaced ELSE opcode" - | 0x05 -> select - | 0x06 -> br (at var s) - | 0x07 -> br_if (at var s) - | 0x08 -> + + | 0x05 -> error s pos "misplaced ELSE opcode" + | 0x06| 0x07 | 0x08 | 0x09 | 0x0a as b -> illegal s pos b + | 0x0b -> error s pos "misplaced END opcode" + + | 0x0c -> br (at var s) + | 0x0d -> br_if (at var s) + | 0x0e -> let xs = vec (at var) s in let x = at var s in br_table xs x - | 0x09 -> return - | 0x0a -> nop - | 0x0b -> drop - | 0x0c | 0x0d | 0x0e as b -> illegal s pos b - | 0x0f -> error s pos "misplaced END opcode" - - | 0x10 -> i32_const (at vs32 s) - | 0x11 -> i64_const (at vs64 s) - | 0x12 -> f64_const (at f64 s) - | 0x13 -> f32_const (at f32 s) - - | 0x14 -> get_local (at var s) - | 0x15 -> set_local (at var s) - - | 0x16 -> call (at var s) - | 0x17 -> + | 0x0f -> return + + | 0x10 -> call (at var s) + | 0x11 -> let x = at var s in expect 0x00 s "zero flag expected"; call_indirect x - | 0x19 -> tee_local (at var s) - - | 0x1a | 0x1b | 0x1c | 0x1d | 0x1e | 0x1f as b -> illegal s pos b - - | 0x20 -> let a, o = memop s in i32_load8_s a o - | 0x21 -> let a, o = memop s in i32_load8_u a o - | 0x22 -> let a, o = memop s in i32_load16_s a o - | 0x23 -> let a, o = memop s in i32_load16_u a o - | 0x24 -> let a, o = memop s in i64_load8_s a o - | 0x25 -> let a, o = memop s in i64_load8_u a o - | 0x26 -> let a, o = memop s in i64_load16_s a o - | 0x27 -> let a, o = memop s in i64_load16_u a o - | 0x28 -> let a, o = memop s in i64_load32_s a o - | 0x29 -> let a, o = memop s in i64_load32_u a o - | 0x2a -> let a, o = memop s in i32_load a o - | 0x2b -> let a, o = memop s in i64_load a o - | 0x2c -> let a, o = memop s in f32_load a o - | 0x2d -> let a, o = memop s in f64_load a o - - | 0x2e -> let a, o = memop s in i32_store8 a o - | 0x2f -> let a, o = memop s in i32_store16 a o - | 0x30 -> let a, o = memop s in i64_store8 a o - | 0x31 -> let a, o = memop s in i64_store16 a o - | 0x32 -> let a, o = memop s in i64_store32 a o - | 0x33 -> let a, o = memop s in i32_store a o - | 0x34 -> let a, o = memop s in i64_store a o - | 0x35 -> let a, o = memop s in f32_store a o - | 0x36 -> let a, o = memop s in f64_store a o - - | 0x37 | 0x38 as b -> illegal s pos b - - | 0x39 -> + | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 as b -> illegal s pos b + + | 0x1a -> drop + | 0x1b -> select + + | 0x1c | 0x1d | 0x1e | 0x1f as b -> illegal s pos b + + | 0x20 -> get_local (at var s) + | 0x21 -> set_local (at var s) + | 0x22 -> tee_local (at var s) + | 0x23 -> get_global (at var s) + | 0x24 -> set_global (at var s) + + | 0x25 | 0x26 | 0x27 as b -> illegal s pos b + + | 0x28 -> let a, o = memop s in i32_load a o + | 0x29 -> let a, o = memop s in i64_load a o + | 0x2a -> let a, o = memop s in f32_load a o + | 0x2b -> let a, o = memop s in f64_load a o + | 0x2c -> let a, o = memop s in i32_load8_s a o + | 0x2d -> let a, o = memop s in i32_load8_u a o + | 0x2e -> let a, o = memop s in i32_load16_s a o + | 0x2f -> let a, o = memop s in i32_load16_u a o + | 0x30 -> let a, o = memop s in i64_load8_s a o + | 0x31 -> let a, o = memop s in i64_load8_u a o + | 0x32 -> let a, o = memop s in i64_load16_s a o + | 0x33 -> let a, o = memop s in i64_load16_u a o + | 0x34 -> let a, o = memop s in i64_load32_s a o + | 0x35 -> let a, o = memop s in i64_load32_u a o + + | 0x36 -> let a, o = memop s in i32_store a o + | 0x37 -> let a, o = memop s in i64_store a o + | 0x38 -> let a, o = memop s in f32_store a o + | 0x39 -> let a, o = memop s in f64_store a o + | 0x3a -> let a, o = memop s in i32_store8 a o + | 0x3b -> let a, o = memop s in i32_store16 a o + | 0x3c -> let a, o = memop s in i64_store8 a o + | 0x3d -> let a, o = memop s in i64_store16 a o + | 0x3e -> let a, o = memop s in i64_store32 a o + + | 0x3f -> expect 0x00 s "zero flag expected"; grow_memory - | 0x3a as b -> illegal s pos b - | 0x3b -> + | 0x40 -> expect 0x00 s "zero flag expected"; current_memory - | 0x3c | 0x3d | 0x3e | 0x3f as b -> illegal s pos b - - | 0x40 -> i32_add - | 0x41 -> i32_sub - | 0x42 -> i32_mul - | 0x43 -> i32_div_s - | 0x44 -> i32_div_u - | 0x45 -> i32_rem_s - | 0x46 -> i32_rem_u - | 0x47 -> i32_and - | 0x48 -> i32_or - | 0x49 -> i32_xor - | 0x4a -> i32_shl - | 0x4b -> i32_shr_u - | 0x4c -> i32_shr_s - | 0x4d -> i32_eq - | 0x4e -> i32_ne - | 0x4f -> i32_lt_s - | 0x50 -> i32_le_s - | 0x51 -> i32_lt_u - | 0x52 -> i32_le_u - | 0x53 -> i32_gt_s - | 0x54 -> i32_ge_s - | 0x55 -> i32_gt_u - | 0x56 -> i32_ge_u - | 0x57 -> i32_clz - | 0x58 -> i32_ctz - | 0x59 -> i32_popcnt - | 0x5a -> i32_eqz - - | 0x5b -> i64_add - | 0x5c -> i64_sub - | 0x5d -> i64_mul - | 0x5e -> i64_div_s - | 0x5f -> i64_div_u - | 0x60 -> i64_rem_s - | 0x61 -> i64_rem_u - | 0x62 -> i64_and - | 0x63 -> i64_or - | 0x64 -> i64_xor - | 0x65 -> i64_shl - | 0x66 -> i64_shr_u - | 0x67 -> i64_shr_s - | 0x68 -> i64_eq - | 0x69 -> i64_ne - | 0x6a -> i64_lt_s - | 0x6b -> i64_le_s - | 0x6c -> i64_lt_u - | 0x6d -> i64_le_u - | 0x6e -> i64_gt_s - | 0x6f -> i64_ge_s - | 0x70 -> i64_gt_u - | 0x71 -> i64_ge_u - | 0x72 -> i64_clz - | 0x73 -> i64_ctz - | 0x74 -> i64_popcnt - - | 0x75 -> f32_add - | 0x76 -> f32_sub - | 0x77 -> f32_mul - | 0x78 -> f32_div - | 0x79 -> f32_min - | 0x7a -> f32_max - | 0x7b -> f32_abs - | 0x7c -> f32_neg - | 0x7d -> f32_copysign - | 0x7e -> f32_ceil - | 0x7f -> f32_floor - | 0x80 -> f32_trunc - | 0x81 -> f32_nearest - | 0x82 -> f32_sqrt - | 0x83 -> f32_eq - | 0x84 -> f32_ne - | 0x85 -> f32_lt - | 0x86 -> f32_le - | 0x87 -> f32_gt - | 0x88 -> f32_ge - - | 0x89 -> f64_add - | 0x8a -> f64_sub - | 0x8b -> f64_mul - | 0x8c -> f64_div - | 0x8d -> f64_min - | 0x8e -> f64_max - | 0x8f -> f64_abs - | 0x90 -> f64_neg - | 0x91 -> f64_copysign - | 0x92 -> f64_ceil - | 0x93 -> f64_floor - | 0x94 -> f64_trunc - | 0x95 -> f64_nearest - | 0x96 -> f64_sqrt - | 0x97 -> f64_eq - | 0x98 -> f64_ne - | 0x99 -> f64_lt - | 0x9a -> f64_le - | 0x9b -> f64_gt - | 0x9c -> f64_ge - - | 0x9d -> i32_trunc_s_f32 - | 0x9e -> i32_trunc_s_f64 - | 0x9f -> i32_trunc_u_f32 - | 0xa0 -> i32_trunc_u_f64 - | 0xa1 -> i32_wrap_i64 - | 0xa2 -> i64_trunc_s_f32 - | 0xa3 -> i64_trunc_s_f64 - | 0xa4 -> i64_trunc_u_f32 - | 0xa5 -> i64_trunc_u_f64 - | 0xa6 -> i64_extend_s_i32 - | 0xa7 -> i64_extend_u_i32 - | 0xa8 -> f32_convert_s_i32 - | 0xa9 -> f32_convert_u_i32 - | 0xaa -> f32_convert_s_i64 - | 0xab -> f32_convert_u_i64 - | 0xac -> f32_demote_f64 - | 0xad -> f32_reinterpret_i32 - | 0xae -> f64_convert_s_i32 - | 0xaf -> f64_convert_u_i32 - | 0xb0 -> f64_convert_s_i64 - | 0xb1 -> f64_convert_u_i64 - | 0xb2 -> f64_promote_f32 - | 0xb3 -> f64_reinterpret_i64 - | 0xb4 -> i32_reinterpret_f32 - | 0xb5 -> i64_reinterpret_f64 - - | 0xb6 -> i32_rotl - | 0xb7 -> i32_rotr - | 0xb8 -> i64_rotl - | 0xb9 -> i64_rotr - | 0xba -> i64_eqz - - | 0xbb -> get_global (at var s) - | 0xbc -> set_global (at var s) - - | b when b > 0xbc -> illegal s pos b - - | b -> error s pos "too few operands for operator" + | 0x41 -> i32_const (at vs32 s) + | 0x42 -> i64_const (at vs64 s) + | 0x43 -> f32_const (at f32 s) + | 0x44 -> f64_const (at f64 s) + + | 0x45 -> i32_eqz + | 0x46 -> i32_eq + | 0x47 -> i32_ne + | 0x48 -> i32_lt_s + | 0x49 -> i32_lt_u + | 0x4a -> i32_gt_s + | 0x4b -> i32_gt_u + | 0x4c -> i32_le_s + | 0x4d -> i32_le_u + | 0x4e -> i32_ge_s + | 0x4f -> i32_ge_u + + | 0x50 -> i64_eqz + | 0x51 -> i64_eq + | 0x52 -> i64_ne + | 0x53 -> i64_lt_s + | 0x54 -> i64_lt_u + | 0x55 -> i64_gt_s + | 0x56 -> i64_gt_u + | 0x57 -> i64_le_s + | 0x58 -> i64_le_u + | 0x59 -> i64_ge_s + | 0x5a -> i64_ge_u + + | 0x5b -> f32_eq + | 0x5c -> f32_ne + | 0x5d -> f32_lt + | 0x5e -> f32_gt + | 0x5f -> f32_le + | 0x60 -> f32_ge + + | 0x61 -> f64_eq + | 0x62 -> f64_ne + | 0x63 -> f64_lt + | 0x64 -> f64_gt + | 0x65 -> f64_le + | 0x66 -> f64_ge + + | 0x67 -> i32_clz + | 0x68 -> i32_ctz + | 0x69 -> i32_popcnt + | 0x6a -> i32_add + | 0x6b -> i32_sub + | 0x6c -> i32_mul + | 0x6d -> i32_div_s + | 0x6e -> i32_div_u + | 0x6f -> i32_rem_s + | 0x70 -> i32_rem_u + | 0x71 -> i32_and + | 0x72 -> i32_or + | 0x73 -> i32_xor + | 0x74 -> i32_shl + | 0x75 -> i32_shr_s + | 0x76 -> i32_shr_u + | 0x77 -> i32_rotl + | 0x78 -> i32_rotr + + | 0x79 -> i64_clz + | 0x7a -> i64_ctz + | 0x7b -> i64_popcnt + | 0x7c -> i64_add + | 0x7d -> i64_sub + | 0x7e -> i64_mul + | 0x7f -> i64_div_s + | 0x80 -> i64_div_u + | 0x81 -> i64_rem_s + | 0x82 -> i64_rem_u + | 0x83 -> i64_and + | 0x84 -> i64_or + | 0x85 -> i64_xor + | 0x86 -> i64_shl + | 0x87 -> i64_shr_s + | 0x88 -> i64_shr_u + | 0x89 -> i64_rotl + | 0x8a -> i64_rotr + + | 0x8b -> f32_abs + | 0x8c -> f32_neg + | 0x8d -> f32_ceil + | 0x8e -> f32_floor + | 0x8f -> f32_trunc + | 0x90 -> f32_nearest + | 0x91 -> f32_sqrt + | 0x92 -> f32_add + | 0x93 -> f32_sub + | 0x94 -> f32_mul + | 0x95 -> f32_div + | 0x96 -> f32_min + | 0x97 -> f32_max + | 0x98 -> f32_copysign + + | 0x99 -> f64_abs + | 0x9a -> f64_neg + | 0x9b -> f64_ceil + | 0x9c -> f64_floor + | 0x9d -> f64_trunc + | 0x9e -> f64_nearest + | 0x9f -> f64_sqrt + | 0xa0 -> f64_add + | 0xa1 -> f64_sub + | 0xa2 -> f64_mul + | 0xa3 -> f64_div + | 0xa4 -> f64_min + | 0xa5 -> f64_max + | 0xa6 -> f64_copysign + + | 0xa7 -> i32_wrap_i64 + | 0xa8 -> i32_trunc_s_f32 + | 0xa9 -> i32_trunc_u_f32 + | 0xaa -> i32_trunc_s_f64 + | 0xab -> i32_trunc_u_f64 + | 0xac -> i64_extend_s_i32 + | 0xad -> i64_extend_u_i32 + | 0xae -> i64_trunc_s_f32 + | 0xaf -> i64_trunc_u_f32 + | 0xb0 -> i64_trunc_s_f64 + | 0xb1 -> i64_trunc_u_f64 + | 0xb2 -> f32_convert_s_i32 + | 0xb3 -> f32_convert_u_i32 + | 0xb4 -> f32_convert_s_i64 + | 0xb5 -> f32_convert_u_i64 + | 0xb6 -> f32_demote_f64 + | 0xb7 -> f64_convert_s_i32 + | 0xb8 -> f64_convert_u_i32 + | 0xb9 -> f64_convert_s_i64 + | 0xba -> f64_convert_u_i64 + | 0xbb -> f64_promote_f32 + + | 0xbc -> i32_reinterpret_f32 + | 0xbd -> i64_reinterpret_f64 + | 0xbe -> f32_reinterpret_i32 + | 0xbf -> f64_reinterpret_i64 + + | b -> illegal s pos b and instr_block s = List.rev (instr_block' s []) and instr_block' s es = match peek s with - | None | Some (0x04 | 0x0f) -> es + | None | Some (0x05 | 0x0b) -> es | _ -> let pos = pos s in let e' = instr s in @@ -433,7 +437,7 @@ and instr_block' s es = let const s = let c = at instr_block s in - expect 0x0f s "END opcode expected"; + end_ s; c @@ -566,7 +570,7 @@ let local s = let code _ s = let locals = List.flatten (vec local s) in let body = instr_block s in - expect 0x0f s "END opcode expected"; + end_ s; {locals; body; ftype = Source.((-1l) @@ Source.no_region)} let code_section s = diff --git a/interpreter/spec/encode.ml b/interpreter/spec/encode.ml index 72aba91331..2dcefdb7c2 100644 --- a/interpreter/spec/encode.ml +++ b/interpreter/spec/encode.ml @@ -130,6 +130,8 @@ let encode m = open Memory let op n = u8 n + let end_ () = op 0x0b + let memop {align; offset; _} = vu32 (I32.ctz (Int32.of_int align)); vu32 offset @@ -139,227 +141,229 @@ let encode m = let rec instr e = match e.it with | Unreachable -> op 0x00 - | Block (ts, es) -> op 0x01; stack_type ts; list instr es; op 0x0f - | Loop (ts, es) -> op 0x02; stack_type ts; list instr es; op 0x0f + | Nop -> op 0x01 + + | Block (ts, es) -> op 0x02; stack_type ts; list instr es; end_ () + | Loop (ts, es) -> op 0x03; stack_type ts; list instr es; end_ () | If (ts, es1, es2) -> - op 0x03; stack_type ts; list instr es1; - if es2 <> [] then op 0x04; - list instr es2; op 0x0f - | Select -> op 0x05 - | Br x -> op 0x06; var x - | BrIf x -> op 0x07; var x - | BrTable (xs, x) -> op 0x08; vec var xs; var x - | Return -> op 0x09 - | Nop -> op 0x0a - | Drop -> op 0x0b - - | Const {it = I32 c; _} -> op 0x10; vs32 c - | Const {it = I64 c; _} -> op 0x11; vs64 c - | Const {it = F32 c; _} -> op 0x13; f32 c - | Const {it = F64 c; _} -> op 0x12; f64 c - - | GetLocal x -> op 0x14; var x - | SetLocal x -> op 0x15; var x - | TeeLocal x -> op 0x19; var x - | GetGlobal x -> op 0xbb; var x - | SetGlobal x -> op 0xbc; var x - - | Call x -> op 0x16; var x - | CallIndirect x -> op 0x17; var x; u8 0x00 - - | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x2a; memop mo - | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x2b; memop mo - | Load ({ty = F32Type; sz = None; _} as mo) -> op 0x2c; memop mo - | Load ({ty = F64Type; sz = None; _} as mo) -> op 0x2d; memop mo + op 0x04; stack_type ts; list instr es1; + if es2 <> [] then op 0x05; + list instr es2; end_ () + + | Br x -> op 0x0c; var x + | BrIf x -> op 0x0d; var x + | BrTable (xs, x) -> op 0x0e; vec var xs; var x + | Return -> op 0x0f + | Call x -> op 0x10; var x + | CallIndirect x -> op 0x11; var x; u8 0x00 + + | Drop -> op 0x1a + | Select -> op 0x1b + + | GetLocal x -> op 0x20; var x + | SetLocal x -> op 0x21; var x + | TeeLocal x -> op 0x22; var x + | GetGlobal x -> op 0x23; var x + | SetGlobal x -> op 0x24; var x + + | Load ({ty = I32Type; sz = None; _} as mo) -> op 0x28; memop mo + | Load ({ty = I64Type; sz = None; _} as mo) -> op 0x29; memop mo + | Load ({ty = F32Type; sz = None; _} as mo) -> op 0x2a; memop mo + | Load ({ty = F64Type; sz = None; _} as mo) -> op 0x2b; memop mo | Load ({ty = I32Type; sz = Some (Mem8, SX); _} as mo) -> - op 0x20; memop mo + op 0x2c; memop mo | Load ({ty = I32Type; sz = Some (Mem8, ZX); _} as mo) -> - op 0x21; memop mo + op 0x2d; memop mo | Load ({ty = I32Type; sz = Some (Mem16, SX); _} as mo) -> - op 0x22; memop mo + op 0x2e; memop mo | Load ({ty = I32Type; sz = Some (Mem16, ZX); _} as mo) -> - op 0x23; memop mo + op 0x2f; memop mo | Load {ty = I32Type; sz = Some (Mem32, _); _} -> assert false | Load ({ty = I64Type; sz = Some (Mem8, SX); _} as mo) -> - op 0x24; memop mo + op 0x30; memop mo | Load ({ty = I64Type; sz = Some (Mem8, ZX); _} as mo) -> - op 0x25; memop mo + op 0x31; memop mo | Load ({ty = I64Type; sz = Some (Mem16, SX); _} as mo) -> - op 0x26; memop mo + op 0x32; memop mo | Load ({ty = I64Type; sz = Some (Mem16, ZX); _} as mo) -> - op 0x27; memop mo + op 0x33; memop mo | Load ({ty = I64Type; sz = Some (Mem32, SX); _} as mo) -> - op 0x28; memop mo + op 0x34; memop mo | Load ({ty = I64Type; sz = Some (Mem32, ZX); _} as mo) -> - op 0x29; memop mo + op 0x35; memop mo | Load {ty = F32Type | F64Type; sz = Some _; _} -> assert false - | Store ({ty = I32Type; sz = None; _} as mo) -> op 0x33; memop mo - | Store ({ty = I64Type; sz = None; _} as mo) -> op 0x34; memop mo - | Store ({ty = F32Type; sz = None; _} as mo) -> op 0x35; memop mo - | Store ({ty = F64Type; sz = None; _} as mo) -> op 0x36; memop mo - | Store ({ty = I32Type; sz = Some Mem8; _} as mo) -> op 0x2e; memop mo - | Store ({ty = I32Type; sz = Some Mem16; _} as mo) -> op 0x2f; memop mo + | Store ({ty = I32Type; sz = None; _} as mo) -> op 0x36; memop mo + | Store ({ty = I64Type; sz = None; _} as mo) -> op 0x37; memop mo + | Store ({ty = F32Type; sz = None; _} as mo) -> op 0x38; memop mo + | Store ({ty = F64Type; sz = None; _} as mo) -> op 0x39; memop mo + | Store ({ty = I32Type; sz = Some Mem8; _} as mo) -> op 0x3a; memop mo + | Store ({ty = I32Type; sz = Some Mem16; _} as mo) -> op 0x3b; memop mo | Store {ty = I32Type; sz = Some Mem32; _} -> assert false - | Store ({ty = I64Type; sz = Some Mem8; _} as mo) -> op 0x30; memop mo - | Store ({ty = I64Type; sz = Some Mem16; _} as mo) -> op 0x31; memop mo - | Store ({ty = I64Type; sz = Some Mem32; _} as mo) -> op 0x32; memop mo + | Store ({ty = I64Type; sz = Some Mem8; _} as mo) -> op 0x3c; memop mo + | Store ({ty = I64Type; sz = Some Mem16; _} as mo) -> op 0x3d; memop mo + | Store ({ty = I64Type; sz = Some Mem32; _} as mo) -> op 0x3e; memop mo | Store {ty = F32Type | F64Type; sz = Some _; _} -> assert false - | GrowMemory -> op 0x39; u8 0x00 - | CurrentMemory -> op 0x3b; u8 0x00 - - | Unary (I32 I32Op.Clz) -> op 0x57 - | Unary (I32 I32Op.Ctz) -> op 0x58 - | Unary (I32 I32Op.Popcnt) -> op 0x59 - - | Unary (I64 I64Op.Clz) -> op 0x72 - | Unary (I64 I64Op.Ctz) -> op 0x73 - | Unary (I64 I64Op.Popcnt) -> op 0x74 - - | Unary (F32 F32Op.Neg) -> op 0x7c - | Unary (F32 F32Op.Abs) -> op 0x7b - | Unary (F32 F32Op.Ceil) -> op 0x7e - | Unary (F32 F32Op.Floor) -> op 0x7f - | Unary (F32 F32Op.Trunc) -> op 0x80 - | Unary (F32 F32Op.Nearest) -> op 0x81 - | Unary (F32 F32Op.Sqrt) -> op 0x82 - - | Unary (F64 F64Op.Neg) -> op 0x90 - | Unary (F64 F64Op.Abs) -> op 0x8f - | Unary (F64 F64Op.Ceil) -> op 0x92 - | Unary (F64 F64Op.Floor) -> op 0x93 - | Unary (F64 F64Op.Trunc) -> op 0x94 - | Unary (F64 F64Op.Nearest) -> op 0x95 - | Unary (F64 F64Op.Sqrt) -> op 0x96 - - | Binary (I32 I32Op.Add) -> op 0x40 - | Binary (I32 I32Op.Sub) -> op 0x41 - | Binary (I32 I32Op.Mul) -> op 0x42 - | Binary (I32 I32Op.DivS) -> op 0x43 - | Binary (I32 I32Op.DivU) -> op 0x44 - | Binary (I32 I32Op.RemS) -> op 0x45 - | Binary (I32 I32Op.RemU) -> op 0x46 - | Binary (I32 I32Op.And) -> op 0x47 - | Binary (I32 I32Op.Or) -> op 0x48 - | Binary (I32 I32Op.Xor) -> op 0x49 - | Binary (I32 I32Op.Shl) -> op 0x4a - | Binary (I32 I32Op.ShrS) -> op 0x4c - | Binary (I32 I32Op.ShrU) -> op 0x4b - | Binary (I32 I32Op.Rotl) -> op 0xb6 - | Binary (I32 I32Op.Rotr) -> op 0xb7 - - | Binary (I64 I64Op.Add) -> op 0x5b - | Binary (I64 I64Op.Sub) -> op 0x5c - | Binary (I64 I64Op.Mul) -> op 0x5d - | Binary (I64 I64Op.DivS) -> op 0x5e - | Binary (I64 I64Op.DivU) -> op 0x5f - | Binary (I64 I64Op.RemS) -> op 0x60 - | Binary (I64 I64Op.RemU) -> op 0x61 - | Binary (I64 I64Op.And) -> op 0x62 - | Binary (I64 I64Op.Or) -> op 0x63 - | Binary (I64 I64Op.Xor) -> op 0x64 - | Binary (I64 I64Op.Shl) -> op 0x65 - | Binary (I64 I64Op.ShrS) -> op 0x67 - | Binary (I64 I64Op.ShrU) -> op 0x66 - | Binary (I64 I64Op.Rotl) -> op 0xb8 - | Binary (I64 I64Op.Rotr) -> op 0xb9 - - | Binary (F32 F32Op.Add) -> op 0x75 - | Binary (F32 F32Op.Sub) -> op 0x76 - | Binary (F32 F32Op.Mul) -> op 0x77 - | Binary (F32 F32Op.Div) -> op 0x78 - | Binary (F32 F32Op.Min) -> op 0x79 - | Binary (F32 F32Op.Max) -> op 0x7a - | Binary (F32 F32Op.CopySign) -> op 0x7d - - | Binary (F64 F64Op.Add) -> op 0x89 - | Binary (F64 F64Op.Sub) -> op 0x8a - | Binary (F64 F64Op.Mul) -> op 0x8b - | Binary (F64 F64Op.Div) -> op 0x8c - | Binary (F64 F64Op.Min) -> op 0x8d - | Binary (F64 F64Op.Max) -> op 0x8e - | Binary (F64 F64Op.CopySign) -> op 0x91 - - | Test (I32 I32Op.Eqz) -> op 0x5a - | Test (I64 I64Op.Eqz) -> op 0xba + | GrowMemory -> op 0x3f; u8 0x00 + | CurrentMemory -> op 0x40; u8 0x00 + + | Const {it = I32 c; _} -> op 0x41; vs32 c + | Const {it = I64 c; _} -> op 0x42; vs64 c + | Const {it = F32 c; _} -> op 0x43; f32 c + | Const {it = F64 c; _} -> op 0x44; f64 c + + | Test (I32 I32Op.Eqz) -> op 0x45 + | Test (I64 I64Op.Eqz) -> op 0x50 | Test (F32 _) -> assert false | Test (F64 _) -> assert false - | Compare (I32 I32Op.Eq) -> op 0x4d - | Compare (I32 I32Op.Ne) -> op 0x4e - | Compare (I32 I32Op.LtS) -> op 0x4f - | Compare (I32 I32Op.LtU) -> op 0x51 - | Compare (I32 I32Op.LeS) -> op 0x50 - | Compare (I32 I32Op.LeU) -> op 0x52 - | Compare (I32 I32Op.GtS) -> op 0x53 - | Compare (I32 I32Op.GtU) -> op 0x55 - | Compare (I32 I32Op.GeS) -> op 0x54 - | Compare (I32 I32Op.GeU) -> op 0x56 - - | Compare (I64 I64Op.Eq) -> op 0x68 - | Compare (I64 I64Op.Ne) -> op 0x69 - | Compare (I64 I64Op.LtS) -> op 0x6a - | Compare (I64 I64Op.LtU) -> op 0x6c - | Compare (I64 I64Op.LeS) -> op 0x6b - | Compare (I64 I64Op.LeU) -> op 0x6d - | Compare (I64 I64Op.GtS) -> op 0x6e - | Compare (I64 I64Op.GtU) -> op 0x70 - | Compare (I64 I64Op.GeS) -> op 0x6f - | Compare (I64 I64Op.GeU) -> op 0x71 - - | Compare (F32 F32Op.Eq) -> op 0x83 - | Compare (F32 F32Op.Ne) -> op 0x84 - | Compare (F32 F32Op.Lt) -> op 0x85 - | Compare (F32 F32Op.Le) -> op 0x86 - | Compare (F32 F32Op.Gt) -> op 0x87 - | Compare (F32 F32Op.Ge) -> op 0x88 - - | Compare (F64 F64Op.Eq) -> op 0x97 - | Compare (F64 F64Op.Ne) -> op 0x98 - | Compare (F64 F64Op.Lt) -> op 0x99 - | Compare (F64 F64Op.Le) -> op 0x9a - | Compare (F64 F64Op.Gt) -> op 0x9b - | Compare (F64 F64Op.Ge) -> op 0x9c - - | Convert (I32 I32Op.TruncSF32) -> op 0x9d - | Convert (I32 I32Op.TruncSF64) -> op 0x9e - | Convert (I32 I32Op.TruncUF32) -> op 0x9f - | Convert (I32 I32Op.TruncUF64) -> op 0xa0 - | Convert (I32 I32Op.WrapI64) -> op 0xa1 + | Compare (I32 I32Op.Eq) -> op 0x46 + | Compare (I32 I32Op.Ne) -> op 0x47 + | Compare (I32 I32Op.LtS) -> op 0x48 + | Compare (I32 I32Op.LtU) -> op 0x49 + | Compare (I32 I32Op.GtS) -> op 0x4a + | Compare (I32 I32Op.GtU) -> op 0x4b + | Compare (I32 I32Op.LeS) -> op 0x4c + | Compare (I32 I32Op.LeU) -> op 0x4d + | Compare (I32 I32Op.GeS) -> op 0x4e + | Compare (I32 I32Op.GeU) -> op 0x4f + + | Compare (I64 I64Op.Eq) -> op 0x51 + | Compare (I64 I64Op.Ne) -> op 0x52 + | Compare (I64 I64Op.LtS) -> op 0x53 + | Compare (I64 I64Op.LtU) -> op 0x54 + | Compare (I64 I64Op.GtS) -> op 0x55 + | Compare (I64 I64Op.GtU) -> op 0x56 + | Compare (I64 I64Op.LeS) -> op 0x57 + | Compare (I64 I64Op.LeU) -> op 0x58 + | Compare (I64 I64Op.GeS) -> op 0x59 + | Compare (I64 I64Op.GeU) -> op 0x5a + + | Compare (F32 F32Op.Eq) -> op 0x5b + | Compare (F32 F32Op.Ne) -> op 0x5c + | Compare (F32 F32Op.Lt) -> op 0x5d + | Compare (F32 F32Op.Gt) -> op 0x5e + | Compare (F32 F32Op.Le) -> op 0x5f + | Compare (F32 F32Op.Ge) -> op 0x60 + + | Compare (F64 F64Op.Eq) -> op 0x61 + | Compare (F64 F64Op.Ne) -> op 0x62 + | Compare (F64 F64Op.Lt) -> op 0x63 + | Compare (F64 F64Op.Gt) -> op 0x64 + | Compare (F64 F64Op.Le) -> op 0x65 + | Compare (F64 F64Op.Ge) -> op 0x66 + + | Unary (I32 I32Op.Clz) -> op 0x67 + | Unary (I32 I32Op.Ctz) -> op 0x68 + | Unary (I32 I32Op.Popcnt) -> op 0x69 + + | Unary (I64 I64Op.Clz) -> op 0x79 + | Unary (I64 I64Op.Ctz) -> op 0x7a + | Unary (I64 I64Op.Popcnt) -> op 0x7b + + | Unary (F32 F32Op.Abs) -> op 0x8b + | Unary (F32 F32Op.Neg) -> op 0x8c + | Unary (F32 F32Op.Ceil) -> op 0x8d + | Unary (F32 F32Op.Floor) -> op 0x8e + | Unary (F32 F32Op.Trunc) -> op 0x8f + | Unary (F32 F32Op.Nearest) -> op 0x90 + | Unary (F32 F32Op.Sqrt) -> op 0x91 + + | Unary (F64 F64Op.Abs) -> op 0x99 + | Unary (F64 F64Op.Neg) -> op 0x9a + | Unary (F64 F64Op.Ceil) -> op 0x9b + | Unary (F64 F64Op.Floor) -> op 0x9c + | Unary (F64 F64Op.Trunc) -> op 0x9d + | Unary (F64 F64Op.Nearest) -> op 0x9e + | Unary (F64 F64Op.Sqrt) -> op 0x9f + + | Binary (I32 I32Op.Add) -> op 0x6a + | Binary (I32 I32Op.Sub) -> op 0x6b + | Binary (I32 I32Op.Mul) -> op 0x6c + | Binary (I32 I32Op.DivS) -> op 0x6d + | Binary (I32 I32Op.DivU) -> op 0x6e + | Binary (I32 I32Op.RemS) -> op 0x6f + | Binary (I32 I32Op.RemU) -> op 0x70 + | Binary (I32 I32Op.And) -> op 0x71 + | Binary (I32 I32Op.Or) -> op 0x72 + | Binary (I32 I32Op.Xor) -> op 0x73 + | Binary (I32 I32Op.Shl) -> op 0x74 + | Binary (I32 I32Op.ShrS) -> op 0x75 + | Binary (I32 I32Op.ShrU) -> op 0x76 + | Binary (I32 I32Op.Rotl) -> op 0x77 + | Binary (I32 I32Op.Rotr) -> op 0x78 + + | Binary (I64 I64Op.Add) -> op 0x7c + | Binary (I64 I64Op.Sub) -> op 0x7d + | Binary (I64 I64Op.Mul) -> op 0x7e + | Binary (I64 I64Op.DivS) -> op 0x7f + | Binary (I64 I64Op.DivU) -> op 0x80 + | Binary (I64 I64Op.RemS) -> op 0x81 + | Binary (I64 I64Op.RemU) -> op 0x82 + | Binary (I64 I64Op.And) -> op 0x83 + | Binary (I64 I64Op.Or) -> op 0x84 + | Binary (I64 I64Op.Xor) -> op 0x85 + | Binary (I64 I64Op.Shl) -> op 0x86 + | Binary (I64 I64Op.ShrS) -> op 0x87 + | Binary (I64 I64Op.ShrU) -> op 0x88 + | Binary (I64 I64Op.Rotl) -> op 0x89 + | Binary (I64 I64Op.Rotr) -> op 0x8a + + | Binary (F32 F32Op.Add) -> op 0x92 + | Binary (F32 F32Op.Sub) -> op 0x93 + | Binary (F32 F32Op.Mul) -> op 0x94 + | Binary (F32 F32Op.Div) -> op 0x95 + | Binary (F32 F32Op.Min) -> op 0x96 + | Binary (F32 F32Op.Max) -> op 0x97 + | Binary (F32 F32Op.CopySign) -> op 0x98 + + | Binary (F64 F64Op.Add) -> op 0xa0 + | Binary (F64 F64Op.Sub) -> op 0xa1 + | Binary (F64 F64Op.Mul) -> op 0xa2 + | Binary (F64 F64Op.Div) -> op 0xa3 + | Binary (F64 F64Op.Min) -> op 0xa4 + | Binary (F64 F64Op.Max) -> op 0xa5 + | Binary (F64 F64Op.CopySign) -> op 0xa6 + | Convert (I32 I32Op.ExtendSI32) -> assert false | Convert (I32 I32Op.ExtendUI32) -> assert false - | Convert (I32 I32Op.ReinterpretFloat) -> op 0xb4 - - | Convert (I64 I64Op.TruncSF32) -> op 0xa2 - | Convert (I64 I64Op.TruncSF64) -> op 0xa3 - | Convert (I64 I64Op.TruncUF32) -> op 0xa4 - | Convert (I64 I64Op.TruncUF64) -> op 0xa5 + | Convert (I32 I32Op.WrapI64) -> op 0xa7 + | Convert (I32 I32Op.TruncSF32) -> op 0xa8 + | Convert (I32 I32Op.TruncUF32) -> op 0xa9 + | Convert (I32 I32Op.TruncSF64) -> op 0xaa + | Convert (I32 I32Op.TruncUF64) -> op 0xab + | Convert (I32 I32Op.ReinterpretFloat) -> op 0xbc + + | Convert (I64 I64Op.ExtendSI32) -> op 0xac + | Convert (I64 I64Op.ExtendUI32) -> op 0xad | Convert (I64 I64Op.WrapI64) -> assert false - | Convert (I64 I64Op.ExtendSI32) -> op 0xa6 - | Convert (I64 I64Op.ExtendUI32) -> op 0xa7 - | Convert (I64 I64Op.ReinterpretFloat) -> op 0xb5 - - | Convert (F32 F32Op.ConvertSI32) -> op 0xa8 - | Convert (F32 F32Op.ConvertUI32) -> op 0xa9 - | Convert (F32 F32Op.ConvertSI64) -> op 0xaa - | Convert (F32 F32Op.ConvertUI64) -> op 0xab + | Convert (I64 I64Op.TruncSF32) -> op 0xae + | Convert (I64 I64Op.TruncUF32) -> op 0xaf + | Convert (I64 I64Op.TruncSF64) -> op 0xb0 + | Convert (I64 I64Op.TruncUF64) -> op 0xb1 + | Convert (I64 I64Op.ReinterpretFloat) -> op 0xbd + + | Convert (F32 F32Op.ConvertSI32) -> op 0xb2 + | Convert (F32 F32Op.ConvertUI32) -> op 0xb3 + | Convert (F32 F32Op.ConvertSI64) -> op 0xb4 + | Convert (F32 F32Op.ConvertUI64) -> op 0xb5 | Convert (F32 F32Op.PromoteF32) -> assert false - | Convert (F32 F32Op.DemoteF64) -> op 0xac - | Convert (F32 F32Op.ReinterpretInt) -> op 0xad - - | Convert (F64 F64Op.ConvertSI32) -> op 0xae - | Convert (F64 F64Op.ConvertUI32) -> op 0xaf - | Convert (F64 F64Op.ConvertSI64) -> op 0xb0 - | Convert (F64 F64Op.ConvertUI64) -> op 0xb1 - | Convert (F64 F64Op.PromoteF32) -> op 0xb2 + | Convert (F32 F32Op.DemoteF64) -> op 0xb6 + | Convert (F32 F32Op.ReinterpretInt) -> op 0xbe + + | Convert (F64 F64Op.ConvertSI32) -> op 0xb7 + | Convert (F64 F64Op.ConvertUI32) -> op 0xb8 + | Convert (F64 F64Op.ConvertSI64) -> op 0xb9 + | Convert (F64 F64Op.ConvertUI64) -> op 0xba + | Convert (F64 F64Op.PromoteF32) -> op 0xbb | Convert (F64 F64Op.DemoteF64) -> assert false - | Convert (F64 F64Op.ReinterpretInt) -> op 0xb3 + | Convert (F64 F64Op.ReinterpretInt) -> op 0xbf let const c = - list instr c.it; op 0x0f + list instr c.it; end_ () (* Sections *) @@ -455,7 +459,7 @@ let encode m = let p = pos s in vec local (compress locals); list instr body; - u8 0x0f; + end_ (); patch_gap32 g (pos s - p) let code_section fs = diff --git a/interpreter/spec/eval.ml b/interpreter/spec/eval.ml index 7ada639e32..3b7ef3428c 100644 --- a/interpreter/spec/eval.ml +++ b/interpreter/spec/eval.ml @@ -159,15 +159,18 @@ let eval_instr (e : instr) (es, vs, bs, cs : eval_context) : eval_context = | Nop, _, _, _ -> es, vs, bs, cs - | Drop, v :: vs', _, _ -> - es, vs', bs, cs - | Block (ts, es'), vs, bs, _ -> es', [], {target = []; barity = List.length ts; bcontext = es, vs} :: bs, cs | Loop (ts, es'), vs, bs, _ -> es', [], {target = [e]; barity = 0; bcontext = es, vs} :: bs, cs + | If (ts, es1, es2), I32 0l :: vs', _, _ -> + (Block (ts, es2) @@ e.at) :: es, vs', bs, cs + + | If (ts, es1, es2), I32 i :: vs', _, _ -> + (Block (ts, es1) @@ e.at) :: es, vs', bs, cs + | Br x, vs, bs, _ -> let bs' = drop32 x.it bs e.at in let b = List.hd (take 1 bs' e.at) in @@ -191,18 +194,6 @@ let eval_instr (e : instr) (es, vs, bs, cs : eval_context) : eval_context = let es', vs', bs' = c.ccontext in es', take c.carity vs e.at @ vs', bs', cs' - | If (ts, es1, es2), I32 0l :: vs', _, _ -> - (Block (ts, es2) @@ e.at) :: es, vs', bs, cs - - | If (ts, es1, es2), I32 i :: vs', _, _ -> - (Block (ts, es1) @@ e.at) :: es, vs', bs, cs - - | Select, I32 0l :: v2 :: v1 :: vs', _, _ -> - es, v2 :: vs', bs, cs - - | Select, I32 i :: v2 :: v1 :: vs', _, _ -> - es, v1 :: vs', bs, cs - | Call x, _, _, c :: _ -> eval_call (func c.instance x) (es, vs, bs, cs) e.at @@ -212,6 +203,15 @@ let eval_instr (e : instr) (es, vs, bs, cs : eval_context) : eval_context = Trap.error e.at "indirect call signature mismatch"; eval_call clos (es, vs, bs, cs) e.at + | Drop, v :: vs', _, _ -> + es, vs', bs, cs + + | Select, I32 0l :: v2 :: v1 :: vs', _, _ -> + es, v2 :: vs', bs, cs + + | Select, I32 i :: v2 :: v1 :: vs', _, _ -> + es, v1 :: vs', bs, cs + | GetLocal x, vs, _, c :: _ -> es, (local c x) :: vs, bs, cs @@ -249,16 +249,20 @@ let eval_instr (e : instr) (es, vs, bs, cs : eval_context) : eval_context = with exn -> memory_error e.at exn); es, vs', bs, cs - | Const v, vs, _, _ -> - es, v.it :: vs, bs, cs + | CurrentMemory, vs, _, c :: _ -> + let mem = memory c.instance (0l @@ e.at) in + es, I32 (Memory.size mem) :: vs, bs, cs - | Unary unop, v :: vs', _, _ -> - (try es, Eval_numeric.eval_unop unop v :: vs', bs, cs - with exn -> numeric_error e.at exn) + | GrowMemory, I32 delta :: vs', _, c :: _ -> + let mem = memory c.instance (0l @@ e.at) in + let old_size = Memory.size mem in + let result = + try Memory.grow mem delta; old_size + with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l + in es, I32 result :: vs', bs, cs - | Binary binop, v2 :: v1 :: vs', _, _ -> - (try es, Eval_numeric.eval_binop binop v1 v2 :: vs', bs, cs - with exn -> numeric_error e.at exn) + | Const v, vs, _, _ -> + es, v.it :: vs, bs, cs | Test testop, v :: vs', _, _ -> (try es, value_of_bool (Eval_numeric.eval_testop testop v) :: vs', bs, cs @@ -268,21 +272,17 @@ let eval_instr (e : instr) (es, vs, bs, cs : eval_context) : eval_context = (try es, value_of_bool (Eval_numeric.eval_relop relop v1 v2) :: vs', bs, cs with exn -> numeric_error e.at exn) - | Convert cvtop, v :: vs', _, _ -> - (try es, Eval_numeric.eval_cvtop cvtop v :: vs', bs, cs + | Unary unop, v :: vs', _, _ -> + (try es, Eval_numeric.eval_unop unop v :: vs', bs, cs with exn -> numeric_error e.at exn) - | CurrentMemory, vs, _, c :: _ -> - let mem = memory c.instance (0l @@ e.at) in - es, I32 (Memory.size mem) :: vs, bs, cs + | Binary binop, v2 :: v1 :: vs', _, _ -> + (try es, Eval_numeric.eval_binop binop v1 v2 :: vs', bs, cs + with exn -> numeric_error e.at exn) - | GrowMemory, I32 delta :: vs', _, c :: _ -> - let mem = memory c.instance (0l @@ e.at) in - let old_size = Memory.size mem in - let result = - try Memory.grow mem delta; old_size - with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1l - in es, I32 result :: vs', bs, cs + | Convert cvtop, v :: vs', _, _ -> + (try es, Eval_numeric.eval_cvtop cvtop v :: vs', bs, cs + with exn -> numeric_error e.at exn) | _ -> Crash.error e.at "missing or ill-typed operand on stack" diff --git a/interpreter/spec/valid.ml b/interpreter/spec/valid.ml index e0a20eee74..5642678d8b 100644 --- a/interpreter/spec/valid.ml +++ b/interpreter/spec/valid.ml @@ -168,9 +168,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | Nop -> [] --> [] - | Drop -> - [peek 0 s] -~> [] - | Block (ts, es) -> check_arity (List.length ts) e.at; check_block {c with labels = ts :: c.labels} es ts e.at; @@ -181,6 +178,12 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = check_block {c with labels = [] :: c.labels} es ts e.at; [] --> ts + | If (ts, es1, es2) -> + check_arity (List.length ts) e.at; + check_block {c with labels = ts :: c.labels} es1 ts e.at; + check_block {c with labels = ts :: c.labels} es2 ts e.at; + [I32Type] --> ts + | Br x -> label c x -->... [] @@ -195,16 +198,6 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = | Return -> c.results -->... [] - | If (ts, es1, es2) -> - check_arity (List.length ts) e.at; - check_block {c with labels = ts :: c.labels} es1 ts e.at; - check_block {c with labels = ts :: c.labels} es2 ts e.at; - [I32Type] --> ts - - | Select -> - let t = peek 1 s in - [t; t; Some I32Type] -~> [t] - | Call x -> let FuncType (ins, out) = func c x in ins --> out @@ -214,6 +207,13 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let FuncType (ins, out) = type_ c x in (ins @ [I32Type]) --> out + | Drop -> + [peek 0 s] -~> [] + + | Select -> + let t = peek 1 s in + [t; t; Some I32Type] -~> [t] + | GetLocal x -> [] --> [local c x] @@ -240,18 +240,18 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = check_memop c memop (fun sz -> sz) e.at; [I32Type; memop.ty] --> [] + | CurrentMemory -> + ignore (memory c (0l @@ e.at)); + [] --> [I32Type] + + | GrowMemory -> + ignore (memory c (0l @@ e.at)); + [I32Type] --> [I32Type] + | Const v -> let t = type_value v.it in [] --> [t] - | Unary unop -> - let t = type_unop unop in - [t] --> [t] - - | Binary binop -> - let t = type_binop binop in - [t; t] --> [t] - | Test testop -> let t = type_testop testop in [t] --> [I32Type] @@ -260,18 +260,18 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = let t = type_relop relop in [t; t] --> [I32Type] + | Unary unop -> + let t = type_unop unop in + [t] --> [t] + + | Binary binop -> + let t = type_binop binop in + [t; t] --> [t] + | Convert cvtop -> let t1, t2 = type_cvtop e.at cvtop in [t1] --> [t2] - | CurrentMemory -> - ignore (memory c (0l @@ e.at)); - [] --> [I32Type] - - | GrowMemory -> - ignore (memory c (0l @@ e.at)); - [I32Type] --> [I32Type] - and check_seq (c : context) (es : instr list) : infer_stack_type = match es with | [] -> diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index d0ac97cbb1..45cc0085ca 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -73,6 +73,21 @@ module IntOp = struct open Ast.IntOp + let testop xx = function + | Eqz -> "eqz" + + let relop xx = function + | Eq -> "eq" + | Ne -> "ne" + | LtS -> "lt_s" + | LtU -> "lt_u" + | GtS -> "gt_s" + | GtU -> "gt_u" + | LeS -> "le_s" + | LeU -> "le_u" + | GeS -> "ge_s" + | GeU -> "ge_u" + let unop xx = function | Clz -> "clz" | Ctz -> "ctz" @@ -95,21 +110,6 @@ struct | Rotl -> "rotl" | Rotr -> "rotr" - let testop xx = function - | Eqz -> "eqz" - - let relop xx = function - | Eq -> "eq" - | Ne -> "ne" - | LtS -> "lt_s" - | LtU -> "lt_u" - | LeS -> "le_s" - | LeU -> "le_u" - | GtS -> "gt_s" - | GtU -> "gt_u" - | GeS -> "ge_s" - | GeU -> "ge_u" - let cvtop xx = function | ExtendSI32 -> "extend_s/i32" | ExtendUI32 -> "extend_u/i32" @@ -125,6 +125,16 @@ module FloatOp = struct open Ast.FloatOp + let testop xx = fun _ -> assert false + + let relop xx = function + | Eq -> "eq" + | Ne -> "ne" + | Lt -> "lt" + | Gt -> "gt" + | Le -> "le" + | Ge -> "ge" + let unop xx = function | Neg -> "neg" | Abs -> "abs" @@ -143,16 +153,6 @@ struct | Max -> "max" | CopySign -> "copysign" - let testop xx = fun _ -> assert false - - let relop xx = function - | Eq -> "eq" - | Ne -> "ne" - | Lt -> "lt" - | Le -> "le" - | Gt -> "gt" - | Ge -> "ge" - let cvtop xx = function | ConvertSI32 -> "convert_s/i32" | ConvertUI32 -> "convert_u/i32" @@ -214,20 +214,20 @@ let rec instr e = match e.it with | Unreachable -> "unreachable", [] | Nop -> "nop", [] - | Drop -> "drop", [] | Block (ts, es) -> "block", stack_type ts @ list instr es | Loop (ts, es) -> "loop", stack_type ts @ list instr es + | If (ts, es1, es2) -> + "if", stack_type ts @ + [Node ("then", list instr es1); Node ("else", list instr es2)] | Br x -> "br " ^ var x, [] | BrIf x -> "br_if " ^ var x, [] | BrTable (xs, x) -> "br_table " ^ String.concat " " (list var (xs @ [x])), [] | Return -> "return", [] - | If (ts, es1, es2) -> - "if", stack_type ts @ - [Node ("then", list instr es1); Node ("else", list instr es2)] - | Select -> "select", [] | Call x -> "call " ^ var x, [] | CallIndirect x -> "call_indirect " ^ var x, [] + | Drop -> "drop", [] + | Select -> "select", [] | GetLocal x -> "get_local " ^ var x, [] | SetLocal x -> "set_local " ^ var x, [] | TeeLocal x -> "tee_local " ^ var x, [] @@ -235,14 +235,14 @@ let rec instr e = | SetGlobal x -> "set_global " ^ var x, [] | Load op -> loadop op, [] | Store op -> storeop op, [] + | CurrentMemory -> "current_memory", [] + | GrowMemory -> "grow_memory", [] | Const lit -> constop lit ^ " " ^ value lit, [] - | Unary op -> unop op, [] - | Binary op -> binop op, [] | Test op -> testop op, [] | Compare op -> relop op, [] + | Unary op -> unop op, [] + | Binary op -> binop op, [] | Convert op -> cvtop op, [] - | CurrentMemory -> "current_memory", [] - | GrowMemory -> "grow_memory", [] in Node (head, inner) let const c = diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 7612f7baec..dae0bc7945 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -291,8 +291,6 @@ instr : plain_instr : | UNREACHABLE { fun c -> unreachable } | NOP { fun c -> nop } - | DROP { fun c -> drop } - | SELECT { fun c -> select } | BR var { fun c -> br ($2 c label) } | BR_IF var { fun c -> br_if ($2 c label) } | BR_TABLE var var_list @@ -301,6 +299,8 @@ plain_instr : | RETURN { fun c -> return } | CALL var { fun c -> call ($2 c func) } | CALL_INDIRECT var { fun c -> call_indirect ($2 c type_) } + | DROP { fun c -> drop } + | SELECT { fun c -> select } | GET_LOCAL var { fun c -> get_local ($2 c local) } | SET_LOCAL var { fun c -> set_local ($2 c local) } | TEE_LOCAL var { fun c -> tee_local ($2 c local) } @@ -308,14 +308,14 @@ plain_instr : | SET_GLOBAL var { fun c -> set_global ($2 c global) } | LOAD offset_opt align_opt { fun c -> $1 $3 $2 } | STORE offset_opt align_opt { fun c -> $1 $3 $2 } + | CURRENT_MEMORY { fun c -> current_memory } + | GROW_MEMORY { fun c -> grow_memory } | CONST literal { fun c -> fst (literal $1 $2) } - | UNARY { fun c -> $1 } - | BINARY { fun c -> $1 } | TEST { fun c -> $1 } | COMPARE { fun c -> $1 } + | UNARY { fun c -> $1 } + | BINARY { fun c -> $1 } | CONVERT { fun c -> $1 } - | CURRENT_MEMORY { fun c -> current_memory } - | GROW_MEMORY { fun c -> grow_memory } ; block_instr : | BLOCK labeling_opt block END From cb97ad75c0fba4b61fa22e609a9b8c35d0d74fe7 Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Mon, 24 Oct 2016 14:21:22 +0200 Subject: [PATCH 3/5] Negative type opcodes --- interpreter/spec/decode.ml | 27 +++++++++++++++------------ interpreter/spec/encode.ml | 18 ++++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/interpreter/spec/decode.ml b/interpreter/spec/decode.ml index e5de5d67aa..c48df542e2 100644 --- a/interpreter/spec/decode.ml +++ b/interpreter/spec/decode.ml @@ -96,6 +96,7 @@ let rec vsN n s = let vu1 s = Int64.to_int (vuN 1 s) let vu32 s = Int64.to_int32 (vuN 32 s) +let vs7 s = Int64.to_int (vsN 7 s) let vs32 s = Int64.to_int32 (vsN 32 s) let vs64 s = vsN 64 s let f32 s = F32.of_bits (u32 s) @@ -126,28 +127,30 @@ let sized f s = open Types let value_type s = - match u8 s with - | 0x01 -> I32Type - | 0x02 -> I64Type - | 0x03 -> F32Type - | 0x04 -> F64Type + match vs7 s with + | -0x01 -> I32Type + | -0x02 -> I64Type + | -0x03 -> F32Type + | -0x04 -> F64Type | _ -> error s (pos s - 1) "invalid value type" let elem_type s = - match u8 s with - | 0x20 -> AnyFuncType + match vs7 s with + | -0x10 -> AnyFuncType | _ -> error s (pos s - 1) "invalid element type" let stack_type s = match peek s with - | Some 0x00 -> skip 1 s; [] + | Some 0x40 -> skip 1 s; [] | _ -> [value_type s] let func_type s = - expect 0x40 s "invalid function type"; - let ins = vec value_type s in - let out = vec value_type s in - FuncType (ins, out) + match vs7 s with + | -0x20 -> + let ins = vec value_type s in + let out = vec value_type s in + FuncType (ins, out) + | _ -> error s (pos s - 1) "invalid function type" let limits vu s = let has_max = bool s in diff --git a/interpreter/spec/encode.ml b/interpreter/spec/encode.ml index 2dcefdb7c2..5f019a6bae 100644 --- a/interpreter/spec/encode.ml +++ b/interpreter/spec/encode.ml @@ -56,7 +56,9 @@ let encode m = if -64L <= i && i < 64L then u8 b else (u8 (b lor 0x80); vs64 (Int64.shift_right i 7)) + let vu1 i = vu64 (Int64.of_int i) let vu32 i = vu64 (Int64.of_int32 i) + let vs7 i = vs64 (Int64.of_int i) let vs32 i = vs64 (Int64.of_int32 i) let f32 x = u32 (F32.to_bits x) let f64 x = u64 (F64.to_bits x) @@ -67,7 +69,7 @@ let encode m = "cannot encode length with more than 32 bit"; vu32 (Int32.of_int i) - let bool b = u8 (if b then 1 else 0) + let bool b = vu1 (if b then 1 else 0) let string bs = len (String.length bs); put_string s bs let list f xs = List.iter f xs let opt f xo = Lib.Option.app f xo @@ -88,23 +90,23 @@ let encode m = open Types let value_type = function - | I32Type -> u8 0x01 - | I64Type -> u8 0x02 - | F32Type -> u8 0x03 - | F64Type -> u8 0x04 + | I32Type -> vs7 (-0x01) + | I64Type -> vs7 (-0x02) + | F32Type -> vs7 (-0x03) + | F64Type -> vs7 (-0x04) let elem_type = function - | AnyFuncType -> u8 0x20 + | AnyFuncType -> vs7 (-0x10) let stack_type = function - | [] -> u8 0x00 + | [] -> vs7 (-0x40) | [t] -> value_type t | _ -> Code.error Source.no_region "cannot encode stack type with arity > 1 (yet)" let func_type = function - | FuncType (ins, out) -> u8 0x40; vec value_type ins; vec value_type out + | FuncType (ins, out) -> vs7 (-0x20); vec value_type ins; vec value_type out let limits vu {min; max} = bool (max <> None); vu min; opt vu max From 1f00387539cec36fe5d5d2de90963f4a1697f54e Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Mon, 24 Oct 2016 14:39:09 +0200 Subject: [PATCH 4/5] Bump binary vesion --- interpreter/host/main.ml | 4 ++-- interpreter/spec/encode.ml | 2 +- interpreter/test/binary.wast | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interpreter/host/main.ml b/interpreter/host/main.ml index 937727a526..505bb6f23e 100644 --- a/interpreter/host/main.ml +++ b/interpreter/host/main.ml @@ -1,5 +1,5 @@ let name = "wasm" -let version = "0.5" +let version = "0.6" let configure () = Import.register "spectest" Spectest.lookup; @@ -7,7 +7,7 @@ let configure () = let banner () = print_endline - (name ^ "-" ^ Printf.sprintf "0x%02lx" Encode.version ^ + (name ^ "-" ^ Printf.sprintf "0x%lX" Encode.version ^ " " ^ version ^ " reference interpreter") let usage = "Usage: " ^ name ^ " [option] [file ...]" diff --git a/interpreter/spec/encode.ml b/interpreter/spec/encode.ml index 5f019a6bae..e8904c1984 100644 --- a/interpreter/spec/encode.ml +++ b/interpreter/spec/encode.ml @@ -1,6 +1,6 @@ (* Version *) -let version = 0x0cl +let version = 0xdl (* Errors *) diff --git a/interpreter/test/binary.wast b/interpreter/test/binary.wast index 07fc114a9b..177ca4235e 100644 --- a/interpreter/test/binary.wast +++ b/interpreter/test/binary.wast @@ -1,7 +1,7 @@ -(module "\00asm\0c\00\00\00") -(module "\00asm" "\0c\00\00\00") -(module $M1 "\00asm\0c\00\00\00") -(module $M2 "\00asm" "\0c\00\00\00") +(module "\00asm\0d\00\00\00") +(module "\00asm" "\0d\00\00\00") +(module $M1 "\00asm\0d\00\00\00") +(module $M2 "\00asm" "\0d\00\00\00") (assert_malformed (module "") "unexpected end") (assert_malformed (module "\01") "unexpected end") @@ -10,6 +10,6 @@ (assert_malformed (module "asm\00") "magic header not detected") (assert_malformed (module "\00asm") "unexpected end") -(assert_malformed (module "\00asm\0c") "unexpected end") -(assert_malformed (module "\00asm\0c\00\00") "unexpected end") -(assert_malformed (module "\00asm\10\00\00\00") "unknown binary version") +(assert_malformed (module "\00asm\0d") "unexpected end") +(assert_malformed (module "\00asm\0d\00\00") "unexpected end") +(assert_malformed (module "\00asm\0e\00\00\00") "unknown binary version") From de191a99f5a9b6bfa7de5d1488475fa145b5d59a Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Mon, 24 Oct 2016 15:46:17 +0200 Subject: [PATCH 5/5] Fix order of memory ops --- interpreter/spec/decode.ml | 4 ++-- interpreter/spec/encode.ml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interpreter/spec/decode.ml b/interpreter/spec/decode.ml index c48df542e2..b502d10565 100644 --- a/interpreter/spec/decode.ml +++ b/interpreter/spec/decode.ml @@ -284,10 +284,10 @@ let rec instr s = | 0x3f -> expect 0x00 s "zero flag expected"; - grow_memory + current_memory | 0x40 -> expect 0x00 s "zero flag expected"; - current_memory + grow_memory | 0x41 -> i32_const (at vs32 s) | 0x42 -> i64_const (at vs64 s) diff --git a/interpreter/spec/encode.ml b/interpreter/spec/encode.ml index e8904c1984..ed28e3f201 100644 --- a/interpreter/spec/encode.ml +++ b/interpreter/spec/encode.ml @@ -209,8 +209,8 @@ let encode m = | Store ({ty = I64Type; sz = Some Mem32; _} as mo) -> op 0x3e; memop mo | Store {ty = F32Type | F64Type; sz = Some _; _} -> assert false - | GrowMemory -> op 0x3f; u8 0x00 - | CurrentMemory -> op 0x40; u8 0x00 + | CurrentMemory -> op 0x3f; u8 0x00 + | GrowMemory -> op 0x40; u8 0x00 | Const {it = I32 c; _} -> op 0x41; vs32 c | Const {it = I64 c; _} -> op 0x42; vs64 c