From b44323e9d0d00d2a901ee4cb6eb2277ed91c3f34 Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Fri, 22 Jul 2016 14:31:08 +0200 Subject: [PATCH 1/5] Factor out limits type --- ml-proto/host/arrange.ml | 8 ++++++-- ml-proto/host/encode.ml | 7 +++++-- ml-proto/host/parser.mly | 15 +++++++++------ ml-proto/spec/check.ml | 23 ++++++++++++++++------- ml-proto/spec/decode.ml | 12 ++++++++---- ml-proto/spec/eval.ml | 4 ++-- ml-proto/spec/kernel.ml | 13 ++++++++++--- ml-proto/test/memory.wast | 8 ++++---- 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/ml-proto/host/arrange.ml b/ml-proto/host/arrange.ml index 80001e421a..6c82d6ebdd 100644 --- a/ml-proto/host/arrange.ml +++ b/ml-proto/host/arrange.ml @@ -254,14 +254,18 @@ let table xs = tab "table" (atom var) xs (* Memory *) +let limits lim = + let {min; max} = lim.it in + String.concat " " (int64 min :: opt int64 max) + let segment seg = let {Memory.addr; data} = seg.it in let ss = Lib.String.breakup data (!Flags.width / 2) in Node ("segment " ^ int64 addr, list (atom string) ss) let memory mem = - let {min; max; segments} = mem.it in - Node ("memory " ^ int64 min ^ " " ^ int64 max, list segment segments) + let {limits = lim; segments} = mem.it in + Node ("memory " ^ limits lim, list segment segments) (* Modules *) diff --git a/ml-proto/host/encode.ml b/ml-proto/host/encode.ml index 3eff2b8ea6..ec83f9bb8d 100644 --- a/ml-proto/host/encode.ml +++ b/ml-proto/host/encode.ml @@ -327,9 +327,12 @@ let encode m = section "table" (vec var) tab (tab <> []) (* Memory section *) + let limits lim = + let {min; max} = lim.it in + bool (max <> None); vu64 min; opt vu64 max + let memory mem = - let {min; max; _} = mem.it in - vu64 min; vu64 max; bool true (*TODO: pending change*) + limits mem.it.limits let memory_section memo = section "memory" (opt memory) memo (memo <> None) diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index c503474bc6..2d3da88773 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -350,6 +350,13 @@ export_opt : start : | LPAR START var RPAR { fun c -> $3 c func } +; + +limits : + | NAT { {min = Int64.of_string $1; max = None} @@ at () } + | NAT NAT + { {min = Int64.of_string $1; max = Some (Int64.of_string $2)} @@ at () } +; segment : | LPAR SEGMENT NAT text_list RPAR @@ -361,12 +368,8 @@ segment_list : ; memory : - | LPAR MEMORY NAT NAT segment_list RPAR - { {min = Int64.of_string $3; max = Int64.of_string $4; segments = $5} - @@ at () } - | LPAR MEMORY NAT segment_list RPAR - { {min = Int64.of_string $3; max = Int64.of_string $3; segments = $4} - @@ at () } + | LPAR MEMORY limits segment_list RPAR + { {limits = $3; segments = $4} @@ at () } ; type_def : diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index 508317ea42..fcd9383fe2 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -327,6 +327,18 @@ let check_start c start = "start function must not return anything"; ) start +let check_limits lim = + let {min; max} = lim.it in + require (I64.le_u min 65535L) lim.at + "memory pages must be less or equal to 65535 (4GiB)"; + match max with + | None -> () + | Some max -> + require (I64.le_u max 65535L) lim.at + "memory pages must be less or equal to 65535 (4GiB)"; + require (I64.le_u min max) lim.at + "memory pages minimum must not be greater than maximum" + let check_segment pages prev_end seg = let seg_len = Int64.of_int (String.length seg.it.Memory.data) in let seg_end = Int64.add seg.it.Memory.addr seg_len in @@ -336,13 +348,10 @@ let check_segment pages prev_end seg = "data segment does not fit memory"; seg_end -let check_memory memory = - let mem = memory.it in - require (mem.min <= mem.max) memory.at - "minimum memory pages must be less than or equal to the maximum"; - require (mem.max <= 65535L) memory.at - "linear memory pages must be less or equal to 65535 (4GiB)"; - ignore (List.fold_left (check_segment mem.min) 0L mem.segments) +let check_memory mem = + let {limits; segments} = mem.it in + check_limits limits; + ignore (List.fold_left (check_segment limits.it.min) 0L segments) let check_module m = let {memory; types; funcs; start; imports; exports; table} = m.it in diff --git a/ml-proto/spec/decode.ml b/ml-proto/spec/decode.ml index b72ee694a4..995d622e8a 100644 --- a/ml-proto/spec/decode.ml +++ b/ml-proto/spec/decode.ml @@ -493,11 +493,15 @@ let table_section s = (* Memory section *) -let memory s = +let limits s = + let has_max = bool s in let min = vu64 s in - let max = vu64 s in - let _ = bool s in (*TODO: pending change*) - {min; max; segments = []} + let max = opt vu64 has_max s in + {min; max} + +let memory s = + let lim = at limits s in + {limits = lim; segments = []} let memory_section s = section `MemorySection (opt (at memory) true) None s diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index a7260a01f5..2e044b1e61 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -311,8 +311,8 @@ and eval_hostop c hostop vs at = (* Modules *) -let init_memory {it = {min; segments; _}} = - let mem = Memory.create min in +let init_memory {it = {limits; segments}} = + let mem = Memory.create limits.it.min in Memory.init mem (List.map it segments); mem diff --git a/ml-proto/spec/kernel.ml b/ml-proto/spec/kernel.ml index 50137a498b..f5fe909648 100644 --- a/ml-proto/spec/kernel.ml +++ b/ml-proto/spec/kernel.ml @@ -118,14 +118,21 @@ and func' = (* Modules *) +type limits = limits' Source.phrase +and limits' = +{ + min : Memory.size; + max : Memory.size option; +} + +type segment = Memory.segment Source.phrase + type memory = memory' Source.phrase and memory' = { - min : Memory.size; - max : Memory.size; + limits : limits; segments : segment list; } -and segment = Memory.segment Source.phrase type export = export' Source.phrase and export' = diff --git a/ml-proto/test/memory.wast b/ml-proto/test/memory.wast index f98118839d..f05037ebbc 100644 --- a/ml-proto/test/memory.wast +++ b/ml-proto/test/memory.wast @@ -10,7 +10,7 @@ (assert_invalid (module (memory 1 0)) - "minimum memory pages must be less than or equal to the maximum" + "memory pages minimum must not be greater than maximum" ) (assert_invalid (module (memory 0 0 (segment 0 "a"))) @@ -34,15 +34,15 @@ ) (assert_invalid (module (memory 0 65536)) - "linear memory pages must be less or equal to 65535 (4GiB)" + "memory pages must be less or equal to 65535 (4GiB)" ) (assert_invalid (module (memory 0 2147483648)) - "linear memory pages must be less or equal to 65535 (4GiB)" + "memory pages must be less or equal to 65535 (4GiB)" ) (assert_invalid (module (memory 0 4294967296)) - "linear memory pages must be less or equal to 65535 (4GiB)" + "memory pages must be less or equal to 65535 (4GiB)" ) ;; Test alignment annotation rules From 6294e82a87c3469be4ac47e80bf5084fbbb90cbc Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Fri, 22 Jul 2016 15:27:59 +0200 Subject: [PATCH 2/5] Make grow_memory fail when exceeding max --- ml-proto/spec/eval.ml | 8 +++--- ml-proto/spec/memory.ml | 50 +++++++++++++++++++++---------------- ml-proto/spec/memory.mli | 3 ++- ml-proto/test/resizing.wast | 25 +++++++++++++++++++ 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index 2e044b1e61..bcbb6e83b6 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -302,8 +302,10 @@ and eval_hostop c hostop vs at = * Since we currently only support i32, just test that. *) if I64.gt_u new_size (Int64.of_int32 Int32.max_int) then Trap.error at "memory size exceeds implementation limit"; - Memory.grow mem delta; - Some (Int32 (Int64.to_int32 old_size)) + let result = + try Memory.grow mem delta; Int64.to_int32 old_size + with Memory.SizeOverflow | Memory.SizeLimit -> -1l + in Some (Int32 result) | _, _ -> Crash.error at "invalid invocation of host operator" @@ -312,7 +314,7 @@ and eval_hostop c hostop vs at = (* Modules *) let init_memory {it = {limits; segments}} = - let mem = Memory.create limits.it.min in + let mem = Memory.create limits.it.min limits.it.max in Memory.init mem (List.map it segments); mem diff --git a/ml-proto/spec/memory.ml b/ml-proto/spec/memory.ml index 4f6e75f8d5..5bae254601 100644 --- a/ml-proto/spec/memory.ml +++ b/ml-proto/spec/memory.ml @@ -12,12 +12,13 @@ type value_type = Types.value_type type value = Values.value type memory' = (int, int8_unsigned_elt, c_layout) Array1.t -type memory = memory' ref +type memory = {mutable content : memory'; max : size option} type t = memory exception Type exception Bounds exception SizeOverflow +exception SizeLimit let page_size = 0x10000L (* 64 KiB *) @@ -44,6 +45,9 @@ let host_index_of_int64 a n = (* ========================================================================== *) +let within_limits n = function + | None -> true + | Some max -> I64.le_u n max let create' n = let sz = host_size_of_int64 (Int64.mul n page_size) in @@ -51,58 +55,62 @@ let create' n = Array1.fill mem 0; mem -let create n = - ref (create' n) +let create n max = + assert (within_limits n max); + {content = create' n; max} let init_seg mem seg = (* There currently is no way to blit from a string. *) let n = String.length seg.data in let base = host_index_of_int64 seg.addr n in for i = 0 to n - 1 do - !mem.{base + i} <- Char.code seg.data.[i] + mem.content.{base + i} <- Char.code seg.data.[i] done let init mem segs = try List.iter (init_seg mem) segs with Invalid_argument _ -> raise Bounds let size mem = - Int64.div (int64_of_host_size (Array1.dim !mem)) page_size + Int64.div (int64_of_host_size (Array1.dim mem.content)) page_size let grow mem pages = - let host_old_size = Array1.dim !mem in + let host_old_size = Array1.dim mem.content in let old_size = size mem in let new_size = Int64.add old_size pages in if I64.gt_u old_size new_size then raise SizeOverflow else + if not (within_limits new_size mem.max) then raise SizeLimit else let after = create' new_size in - Array1.blit (Array1.sub !mem 0 host_old_size) (Array1.sub after 0 host_old_size); - mem := after + Array1.blit + (Array1.sub mem.content 0 host_old_size) + (Array1.sub after 0 host_old_size); + mem.content <- after let effective_address a o = let ea = Int64.add a o in if I64.lt_u ea a then raise Bounds; ea -let rec loadn mem n ea = - assert (n > 0 && n <= 8); - let i = host_index_of_int64 ea n in - try loadn' mem n i with Invalid_argument _ -> raise Bounds - -and loadn' mem n i = - let byte = Int64.of_int !mem.{i} in +let rec loadn' mem n i = + let byte = Int64.of_int mem.content.{i} in if n = 1 then byte else Int64.logor byte (Int64.shift_left (loadn' mem (n-1) (i+1)) 8) -let rec storen mem n ea v = +let rec storen' mem n i v = + mem.content.{i} <- Int64.to_int v land 255; + if n > 1 then + storen' mem (n - 1) (i + 1) (Int64.shift_right v 8) + +let loadn mem n ea = assert (n > 0 && n <= 8); let i = host_index_of_int64 ea n in - try storen' mem n i v with Invalid_argument _ -> raise Bounds + try loadn' mem n i with Invalid_argument _ -> raise Bounds -and storen' mem n i v = - !mem.{i} <- (Int64.to_int v) land 255; - if (n > 1) then - storen' mem (n-1) (i+1) (Int64.shift_right v 8) +let storen mem n ea v = + assert (n > 0 && n <= 8); + let i = host_index_of_int64 ea n in + try storen' mem n i v with Invalid_argument _ -> raise Bounds let load mem a o t = let ea = effective_address a o in diff --git a/ml-proto/spec/memory.mli b/ml-proto/spec/memory.mli index 2e60e8eb66..f8c6561e29 100644 --- a/ml-proto/spec/memory.mli +++ b/ml-proto/spec/memory.mli @@ -12,10 +12,11 @@ type value = Values.value exception Type exception Bounds exception SizeOverflow +exception SizeLimit val page_size : size -val create : size -> memory +val create : size -> size option -> memory val init : memory -> segment list -> unit val size : memory -> size val grow : memory -> size -> unit diff --git a/ml-proto/test/resizing.wast b/ml-proto/test/resizing.wast index b1792cd02b..1f873c74f9 100644 --- a/ml-proto/test/resizing.wast +++ b/ml-proto/test/resizing.wast @@ -40,3 +40,28 @@ (assert_return (invoke "load_at_page_size") (i32.const 0)) (assert_return (invoke "store_at_page_size")) (assert_return (invoke "load_at_page_size") (i32.const 3)) + + +(module + (memory 0) + (func "grow" (param i32) (result i32) (grow_memory (get_local 0))) +) + +(assert_return (invoke "grow" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 2)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 10000)) (i32.const 3)) + +(module + (memory 0 10) + (func "grow" (param i32) (result i32) (grow_memory (get_local 0))) +) + +(assert_return (invoke "grow" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "grow" (i32.const 2)) (i32.const 2)) +(assert_return (invoke "grow" (i32.const 6)) (i32.const 4)) +(assert_return (invoke "grow" (i32.const 0)) (i32.const 10)) +(assert_return (invoke "grow" (i32.const 1)) (i32.const -1)) From 81953cf8aa82f8bd38f19664c19c3c96cfaf258d Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Fri, 22 Jul 2016 16:18:17 +0200 Subject: [PATCH 3/5] Implement tables & elements --- ml-proto/README.md | 10 ++- ml-proto/given/source.ml | 2 +- ml-proto/host/arrange.ml | 28 ++++--- ml-proto/host/encode.ml | 45 ++++++++--- ml-proto/host/parser.mly | 63 ++++++++++----- ml-proto/host/print.ml | 7 +- ml-proto/spec/ast.ml | 2 +- ml-proto/spec/check.ml | 134 ++++++++++++++++++++----------- ml-proto/spec/decode.ml | 78 +++++++++++++----- ml-proto/spec/eval.ml | 40 ++++++--- ml-proto/spec/kernel.ml | 35 +++++--- ml-proto/spec/memory.ml | 34 ++++---- ml-proto/spec/memory.mli | 10 ++- ml-proto/spec/table.ml | 74 +++++++++++++++++ ml-proto/spec/table.mli | 21 +++++ ml-proto/spec/types.ml | 1 + ml-proto/test/br.wast | 2 +- ml-proto/test/br_table.wast | 2 +- ml-proto/test/call_indirect.wast | 47 ++++++++--- ml-proto/test/func_ptrs.wast | 14 ++-- ml-proto/test/left-to-right.wast | 4 +- ml-proto/test/memory.wast | 13 ++- ml-proto/test/return.wast | 2 +- ml-proto/test/unreachable.wast | 2 +- 24 files changed, 479 insertions(+), 191 deletions(-) create mode 100644 ml-proto/spec/table.ml create mode 100644 ml-proto/spec/table.mli diff --git a/ml-proto/README.md b/ml-proto/README.md index 8afd5acb27..647417b46b 100644 --- a/ml-proto/README.md +++ b/ml-proto/README.md @@ -153,9 +153,12 @@ typedef: ( type ? ( func * ? ) ) import: ( import ? ) export: ( export ) | ( export memory) start: ( start ) -table: ( table * ) -memory: ( memory ? * ) -segment: ( segment + ) +table: ( table ? * ) + ( table ( segment * ) ) ;; = (table (segment 0 *)) +memory: ( memory ? * ) + ( memory ( segment + ) ) ;; = (memory (segment 0 +)) +table-segment: ( segment * ) +memory-segment: ( segment + ) ``` Here, productions marked with respective comments are abbreviation forms for equivalent expansions (see the explanation of the kernel AST below). @@ -165,6 +168,7 @@ Any form of naming via `` and `` (including expression labels) is mer A module of the form `(module +)` is given in binary form and will be decoded from the (concatenation of the) strings. The segment strings in the memory field are used to initialize the consecutive memory at the given offset. +The `` in the expansion of the two short-hand forms for `table` and `memory` is the minimal size that can hold the segment: the number of ``s for tables, and the accumulative length of the strings rounded up to page size for memories. Comments can be written in one of two ways: diff --git a/ml-proto/given/source.ml b/ml-proto/given/source.ml index c00422a674..43a49982d6 100644 --- a/ml-proto/given/source.ml +++ b/ml-proto/given/source.ml @@ -10,7 +10,7 @@ let no_region = {left = no_pos; right = no_pos} let string_of_pos pos = if pos.line = -1 then - string_of_int pos.column + Printf.sprintf "0x%x" pos.column else string_of_int pos.line ^ "." ^ string_of_int (pos.column + 1) diff --git a/ml-proto/host/arrange.ml b/ml-proto/host/arrange.ml index 6c82d6ebdd..f0b85b4a34 100644 --- a/ml-proto/host/arrange.ml +++ b/ml-proto/host/arrange.ml @@ -252,20 +252,30 @@ let start x = Node ("start " ^ var x, []) let table xs = tab "table" (atom var) xs -(* Memory *) +(* Tables & memories *) -let limits lim = +let limits int lim = let {min; max} = lim.it in - String.concat " " (int64 min :: opt int64 max) + String.concat " " (int min :: opt int max) -let segment seg = - let {Memory.addr; data} = seg.it in - let ss = Lib.String.breakup data (!Flags.width / 2) in - Node ("segment " ^ int64 addr, list (atom string) ss) +let segment int dat seg = + let {offset; data} = seg.it in + Node ("segment " ^ int offset, dat data) + +let elems xs = + list (atom var) xs + +let table tab = + let {limits = lim; segments} = tab.it in + Node ("table " ^ limits int32 lim, list (segment int32 elems) segments) + +let data s = + let ss = Lib.String.breakup s (!Flags.width / 2) in + list (atom string) ss let memory mem = let {limits = lim; segments} = mem.it in - Node ("memory " ^ limits lim, list segment segments) + Node ("memory " ^ limits int64 lim, list (segment int64 data) segments) (* Modules *) @@ -293,7 +303,7 @@ let module_ m = listi typedef m.it.types @ listi import m.it.imports @ listi func m.it.funcs @ - table m.it.table @ + opt table m.it.table @ opt memory m.it.memory @ list export m.it.exports @ opt start m.it.start diff --git a/ml-proto/host/encode.ml b/ml-proto/host/encode.ml index ec83f9bb8d..b7fac52ebf 100644 --- a/ml-proto/host/encode.ml +++ b/ml-proto/host/encode.ml @@ -82,6 +82,9 @@ let encode m = | Float32Type -> u8 0x03 | Float64Type -> u8 0x04 + let elem_type = function + | AnyFuncType -> u8 0x20 + let expr_type t = vec1 value_type t let func_type = function @@ -323,16 +326,20 @@ let encode m = section "function" (vec func) fs (fs <> []) (* Table section *) - let table_section tab = - section "table" (vec var) tab (tab <> []) - - (* Memory section *) - let limits lim = + let limits vu lim = let {min; max} = lim.it in - bool (max <> None); vu64 min; opt vu64 max + bool (max <> None); vu min; opt vu max + + let table tab = + elem_type AnyFuncType; + limits vu32 tab.it.limits + + let table_section tabo = + section "table" (opt table) tabo (tabo <> None) + (* Memory section *) let memory mem = - limits mem.it.limits + limits vu64 mem.it.limits let memory_section memo = section "memory" (opt memory) memo (memo <> None) @@ -374,13 +381,24 @@ let encode m = let code_section fs = section "code" (vec code) fs (fs <> []) + (* Element section *) + let segment vu dat seg = + let {offset; data} = seg.it in + vu offset; dat data + + let table_segment seg = + segment vu32 (vec var) seg + + let elem_section segs = + section "element" (opt (vec table_segment)) + segs (segs <> None && segs <> Some []) + (* Data section *) - let segment seg = - let {Memory.addr; data} = seg.it in - vu64 addr; string data + let memory_segment seg = + segment vu64 string seg let data_section segs = - section "data" (opt (vec segment)) + section "data" (opt (vec memory_segment)) segs (segs <> None && segs <> Some []) (* Module *) @@ -396,6 +414,9 @@ let encode m = export_section m.it.exports; start_section m.it.start; code_section m.it.funcs; - data_section (Lib.Option.map (fun mem -> mem.it.segments) m.it.memory) + elem_section + (Lib.Option.map (fun (tab : table) -> tab.it.segments) m.it.table); + data_section + (Lib.Option.map (fun (mem : memory) -> mem.it.segments) m.it.memory) end in E.module_ m; to_string s diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index 2d3da88773..fc86688899 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -352,24 +352,52 @@ start : { fun c -> $3 c func } ; -limits : +table_limits : + | NAT { {min = Int32.of_string $1; max = None} @@ at () } + | NAT NAT + { {min = Int32.of_string $1; max = Some (Int32.of_string $2)} @@ at () } +; + +table_segment : + | LPAR SEGMENT NAT var_list RPAR + { let at = at () in + fun c -> {offset = Int32.of_string $3; data = $4 c func} @@ at } +; +table_segment_list : + | /* empty */ { fun c -> [] } + | table_segment table_segment_list { fun c -> $1 c :: $2 c } +; +table : + | LPAR TABLE table_limits table_segment_list RPAR + { let at = at () in fun c -> {limits = $3; segments = $4 c} @@ at } + | LPAR TABLE LPAR SEGMENT var_list RPAR RPAR /* Sugar */ + { let at = at () in + fun c -> let data = $5 c func in + {limits = {min = Int32.of_int (List.length data); max = None} @@ at; + segments = [{offset = 0l; data} @@ at]} @@ at } +; + +memory_limits : | NAT { {min = Int64.of_string $1; max = None} @@ at () } | NAT NAT { {min = Int64.of_string $1; max = Some (Int64.of_string $2)} @@ at () } ; - -segment : +memory_segment : | LPAR SEGMENT NAT text_list RPAR - { {Memory.addr = Int64.of_string $3; Memory.data = $4} @@ at () } + { {offset = Int64.of_string $3; data = $4} @@ at () } ; -segment_list : +memory_segment_list : | /* empty */ { [] } - | segment segment_list { $1 :: $2 } + | memory_segment memory_segment_list { $1 :: $2 } ; - memory : - | LPAR MEMORY limits segment_list RPAR + | LPAR MEMORY memory_limits memory_segment_list RPAR { {limits = $3; segments = $4} @@ at () } + | LPAR MEMORY LPAR SEGMENT text_list RPAR RPAR /* Sugar */ + { {limits = + {min = Int64.(div (add (of_int (String.length $5)) 65535L) 65536L); + max = None} @@ at (); + segments = [{offset = 0L; data = $5} @@ at ()] } @@ at () } ; type_def : @@ -379,11 +407,6 @@ type_def : { fun c -> bind_type c $3 $6 } ; -table : - | LPAR TABLE var_list RPAR - { fun c -> $3 c func } -; - import : | LPAR IMPORT TEXT TEXT type_use RPAR { let at = at () in @@ -413,8 +436,10 @@ export : module_fields : | /* empty */ { fun c -> - {memory = None; types = c.types.tlist; funcs = []; start = None; imports = []; - exports = []; table = []} } + {table = None; memory = None; types = c.types.tlist; funcs = []; start = None; + imports = []; exports = []} } + | type_def module_fields + { fun c -> $1 c; $2 c } | func module_fields { fun c -> let f = $1 c in let m = $2 c in let func, exs = f () in {m with funcs = func :: m.funcs; exports = exs @ m.exports} } @@ -425,10 +450,10 @@ module_fields : { fun c -> let m = $2 c in {m with exports = $1 c :: m.exports} } | table module_fields - { fun c -> let m = $2 c in - {m with table = ($1 c) @ m.table} } - | type_def module_fields - { fun c -> $1 c; $2 c } + { fun c -> let m = $2 c in let tab = $1 c in + match m.table with + | Some _ -> error tab.at "multiple table sections" + | None -> {m with table = Some tab} } | memory module_fields { fun c -> let m = $2 c in match m.memory with diff --git a/ml-proto/host/print.ml b/ml-proto/host/print.ml index a258e55f70..5450fcba43 100644 --- a/ml-proto/host/print.ml +++ b/ml-proto/host/print.ml @@ -29,9 +29,6 @@ let print_export m i ex = | `Memory -> "memory" in printf "export \"%s\" : %s\n" name ascription -let print_table_elem i x = - printf "table [%d] = func %d\n" i x.it - let print_start start = Lib.Option.app (fun x -> printf "start = func %d\n" x.it) start @@ -42,10 +39,10 @@ let print_func m i f = print_func_sig m "func" i f let print_module m = - let {funcs; start; exports; table} = m.it in + (* TODO: more complete print function *) + let {funcs; start; exports; table; _} = m.it in List.iteri (print_func m) funcs; List.iteri (print_export m) exports; - List.iteri print_table_elem table; print_start start; flush_all () diff --git a/ml-proto/spec/ast.ml b/ml-proto/spec/ast.ml index 6e9fddb957..a1a1e126d8 100644 --- a/ml-proto/spec/ast.ml +++ b/ml-proto/spec/ast.ml @@ -210,11 +210,11 @@ and func' = type module_ = module' Source.phrase and module' = { + table : Kernel.table option; memory : Kernel.memory option; types : Types.func_type list; funcs : func list; start : var option; imports : Kernel.import list; exports : Kernel.export list; - table : var list; } diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index fcd9383fe2..8e3e8c77eb 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -24,7 +24,8 @@ type context = locals : value_type list; return : expr_type; labels : expr_type_future list; - has_memory : bool + has_table : bool; + has_memory : bool; } let lookup category list x = @@ -109,7 +110,7 @@ let type_hostop = function | GrowMemory -> ({ins = [Int32Type]; out = Some Int32Type}, true) -(* Type Analysis *) +(* Expressions *) (* * check_expr : context -> expr_type_future -> expr -> unit @@ -180,6 +181,7 @@ let rec check_expr c et e = | CallIndirect (x, e1, es) -> let {ins; out} = type_ c.types x in + check_has_table c e.at; check_expr c (some Int32Type) e1; check_exprs c ins es e.at; check_type out et e.at @@ -272,8 +274,11 @@ and check_store c et memop e1 e2 at = check_expr c (some memop.ty) e2; check_type None et at +and check_has_table c at = + require c.has_table at "operator requires a table section"; + and check_has_memory c at = - require c.has_memory at "memory operators require a memory section" + require c.has_memory at "operator requires a memory section" and check_memop memop at = require (memop.offset >= 0L) at "negative offset"; @@ -284,6 +289,8 @@ and check_mem_type ty sz at = require (ty = Int64Type || sz <> Memory.Mem32) at "memory size too big" +(* Functions *) + (* * check_func : context -> func -> unit * check_module : context -> module_ -> unit @@ -304,19 +311,60 @@ let check_func c f = let c' = {c with locals = s.ins @ locals; return = s.out} in check_expr c' (known s.out) body -let check_elem c x = - ignore (func c x) -module NameSet = Set.Make(String) +(* Tables & Memories *) + +let check_table_limits lim = + let {min; max} = lim.it in + match max with + | None -> () + | Some max -> + require (I32.le_u min max) lim.at + "table size minimum must not be greater than maximum" + +let check_table_segment c size prev_end seg = + let {offset; data} = seg.it in + let len = Int32.of_int (List.length data) in + let end_ = Int32.add seg.it.offset len in + require (prev_end <= offset) seg.at "table segment not disjoint and ordered"; + require (end_ <= size) seg.at "table segment does not fit memory"; + ignore (List.map (func c) data); + end_ + +let check_table c (tab : table) = + let {limits; segments} = tab.it in + check_table_limits limits; + ignore (List.fold_left (check_table_segment c limits.it.min) 0l segments) -let check_export c set ex = - let {name; kind} = ex.it in - (match kind with - | `Func x -> ignore (func c x) - | `Memory -> require c.has_memory ex.at "no memory to export" - ); - require (not (NameSet.mem name set)) ex.at "duplicate export name"; - NameSet.add name set + +let check_memory_limits lim = + let {min; max} = lim.it in + require (I64.lt_u min 65536L) lim.at + "memory size must be less than 65536 pages (4GiB)"; + match max with + | None -> () + | Some max -> + require (I64.lt_u max 65536L) lim.at + "memory size must be less than 65536 pages (4GiB)"; + require (I64.le_u min max) lim.at + "memory size minimum must not be greater than maximum" + +let check_memory_segment c pages prev_end seg = + let {offset; data} = seg.it in + let len = Int64.of_int (String.length data) in + let end_ = Int64.add offset len in + require (prev_end <= offset) seg.at "data segment not disjoint and ordered"; + require (end_ <= Int64.mul pages Memory.page_size) seg.at + "data segment does not fit memory"; + end_ + +let check_memory c (mem : memory) = + let {limits; segments} = mem.it in + check_memory_limits limits; + ignore (List.fold_left (check_memory_segment c limits.it.min) 0L segments) + + +(* Modules *) let check_start c start = Lib.Option.app (fun x -> @@ -327,43 +375,33 @@ let check_start c start = "start function must not return anything"; ) start -let check_limits lim = - let {min; max} = lim.it in - require (I64.le_u min 65535L) lim.at - "memory pages must be less or equal to 65535 (4GiB)"; - match max with - | None -> () - | Some max -> - require (I64.le_u max 65535L) lim.at - "memory pages must be less or equal to 65535 (4GiB)"; - require (I64.le_u min max) lim.at - "memory pages minimum must not be greater than maximum" - -let check_segment pages prev_end seg = - let seg_len = Int64.of_int (String.length seg.it.Memory.data) in - let seg_end = Int64.add seg.it.Memory.addr seg_len in - require (seg.it.Memory.addr >= prev_end) seg.at - "data segment not disjoint and ordered"; - require (Int64.mul pages Memory.page_size >= seg_end) seg.at - "data segment does not fit memory"; - seg_end +module NameSet = Set.Make(String) -let check_memory mem = - let {limits; segments} = mem.it in - check_limits limits; - ignore (List.fold_left (check_segment limits.it.min) 0L segments) +let check_export c set ex = + let {name; kind} = ex.it in + (match kind with + | `Func x -> ignore (func c x) + | `Memory -> require c.has_memory ex.at "no memory to export" + ); + require (not (NameSet.mem name set)) ex.at "duplicate export name"; + NameSet.add name set let check_module m = - let {memory; types; funcs; start; imports; exports; table} = m.it in - Lib.Option.app check_memory memory; - let c = {types; - funcs = List.map (fun f -> type_ types f.it.ftype) funcs; - imports = List.map (fun i -> type_ types i.it.itype) imports; - locals = []; - return = None; - labels = []; - has_memory = memory <> None} in + let {types; table; memory; funcs; start; imports; exports} = m.it in + let c = + { + types; + funcs = List.map (fun f -> type_ types f.it.ftype) funcs; + imports = List.map (fun i -> type_ types i.it.itype) imports; + locals = []; + return = None; + labels = []; + has_table = table <> None; + has_memory = memory <> None; + } + in + Lib.Option.app (check_table c) table; + Lib.Option.app (check_memory c) memory; List.iter (check_func c) funcs; - List.iter (check_elem c) table; ignore (List.fold_left (check_export c) NameSet.empty exports); check_start c start diff --git a/ml-proto/spec/decode.ml b/ml-proto/spec/decode.ml index 995d622e8a..636aa8cc0e 100644 --- a/ml-proto/spec/decode.ml +++ b/ml-proto/spec/decode.ml @@ -121,6 +121,11 @@ let value_type s = | 0x04 -> Float64Type | _ -> error s (pos s - 1) "invalid value type" +let elem_type s = + match get s with + | 0x20 -> AnyFuncType + | _ -> error s (pos s - 1) "invalid element type" + let expr_type s = vec1 value_type s let func_type s = @@ -446,6 +451,7 @@ let id s = | "export" -> `ExportSection | "start" -> `StartSection | "code" -> `CodeSection + | "element" -> `ElemSection | "data" -> `DataSection | _ -> `UnknownSection @@ -487,20 +493,26 @@ let func_section s = (* Table section *) +let limits vu s = + let has_max = bool s in + let min = vu s in + let max = opt vu has_max s in + {min; max} + +let table s = + let t = elem_type s in + assert (t = AnyFuncType); + let lim = at (limits vu32) s in + {limits = lim; segments = []} + let table_section s = - section `TableSection (vec (at var)) [] s + section `TableSection (opt (at table) true) None s (* Memory section *) -let limits s = - let has_max = bool s in - let min = vu64 s in - let max = opt vu64 has_max s in - {min; max} - let memory s = - let lim = at limits s in + let lim = at (limits vu64) s in {limits = lim; segments = []} let memory_section s = @@ -541,15 +553,27 @@ let code_section s = section `CodeSection (vec (at code)) [] s +(* Element section *) + +let segment vu dat s = + let offset = vu s in + let data = dat s in + {offset; data} + +let table_segment s = + segment vu32 (vec (at var)) s + +let elem_section s = + section `ElemSection (vec (at table_segment)) [] s + + (* Data section *) -let segment s = - let addr = vu64 s in - let data = string s in - {Memory.addr; data} +let memory_segment s = + segment vu64 string s let data_section s = - section `DataSection (vec (at segment)) [] s + section `DataSection (vec (at memory_segment)) [] s (* Unknown section *) @@ -574,7 +598,7 @@ let module_ s = iterate unknown_section s; let func_types = func_section s in iterate unknown_section s; - let table = table_section s in + let table_limits = table_section s in iterate unknown_section s; let memory_limits = memory_section s in iterate unknown_section s; @@ -584,23 +608,37 @@ let module_ s = iterate unknown_section s; let func_bodies = code_section s in iterate unknown_section s; - let segments = data_section s in + let table_segments = elem_section s in + iterate unknown_section s; + let memory_segments = data_section s in iterate unknown_section s; (*TODO: name section*) iterate unknown_section s; require (pos s = len s) s (len s) "junk after last section"; require (List.length func_types = List.length func_bodies) s (len s) "function and code section have inconsistent lengths"; - require (memory_limits <> None || segments = []) - s (len s) "data section without memory section"; let funcs = List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at) func_types func_bodies in + let table = + match table_limits with + | None -> + require (table_segments = []) + s (len s) "element section without memory section"; + None + | Some table -> + Some Source.({table.it with segments = table_segments} @@ table.at) + in let memory = match memory_limits with - | None -> None - | Some memory -> Some Source.({memory.it with segments} @@ memory.at) - in {memory; types; funcs; imports; exports; table; start} + | None -> + require (memory_segments = []) + s (len s) "data section without memory section"; + None + | Some memory -> + Some Source.({memory.it with segments = memory_segments} @@ memory.at) + in + {memory; types; funcs; imports; exports; table; start} let decode name bs = at module_ (stream name bs) diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index bcbb6e83b6..6efa439c4d 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -17,7 +17,8 @@ type instance = module_ : module_; imports : import list; exports : export_map; - memory : Memory.t option + table : Table.t option; + memory : Memory.t option; } @@ -78,13 +79,16 @@ let export m name = try ExportMap.find name.it m.exports with Not_found -> Crash.error name.at ("undefined export \"" ^ name.it ^ "\"") -let table_elem c i at = - try - let j = Int32.to_int i in - if i < 0l || i <> Int32.of_int j then raise (Failure ""); - List.nth c.instance.module_.it.table j - with Failure _ -> - Trap.error at ("undefined table index " ^ Int32.to_string i) +let elem c i t at = + match c.instance.table with + | None -> Crash.error at "no table" + | Some tab -> + match Table.load tab i t with + | Some j -> j + | None -> + Trap.error at ("undefined element " ^ Int32.to_string i) + | exception Table.Bounds -> + Trap.error at ("undefined element " ^ Int32.to_string i) module MakeLabel () = struct @@ -186,7 +190,7 @@ let rec eval_expr (c : config) (e : expr) = | CallIndirect (ftype, e1, es) -> let i = int32 (eval_expr c e1) e1.at in let vs = List.map (fun vo -> some (eval_expr c vo) vo.at) es in - let f = func c (table_elem c i e1.at) in + let f = func c (elem c i AnyFuncType e1.at @@ e1.at) in if ftype.it <> f.it.ftype.it then Trap.error e1.at "indirect call signature mismatch"; eval_func c.instance f vs @@ -313,9 +317,18 @@ and eval_hostop c hostop vs at = (* Modules *) -let init_memory {it = {limits; segments}} = +let init_table m table = + let {limits; segments} = table.it in + let tab = Table.create limits.it.min limits.it.max in + let elems = List.map (fun x -> Some x.it) in + List.iter (fun seg -> Table.blit tab seg.it.offset (elems seg.it.data)) + segments; + tab + +let init_memory m memory = + let {limits; segments} = memory.it in let mem = Memory.create limits.it.min limits.it.max in - Memory.init mem (List.map it segments); + List.iter (fun seg -> Memory.blit mem seg.it.offset seg.it.data) segments; mem let add_export funcs ex = @@ -326,12 +339,13 @@ let add_export funcs ex = let init m imports = assert (List.length imports = List.length m.it.Kernel.imports); - let {memory; funcs; exports; start; _} = m.it in + let {table; memory; funcs; exports; start; _} = m.it in let instance = {module_ = m; imports; exports = List.fold_right (add_export funcs) exports ExportMap.empty; - memory = Lib.Option.map init_memory memory} + table = Lib.Option.map (init_table m) table; + memory = Lib.Option.map (init_memory m) memory} in Lib.Option.app (fun x -> ignore (eval_func instance (lookup "function" funcs x) [])) start; diff --git a/ml-proto/spec/kernel.ml b/ml-proto/spec/kernel.ml index f5fe909648..2ad2135722 100644 --- a/ml-proto/spec/kernel.ml +++ b/ml-proto/spec/kernel.ml @@ -116,24 +116,35 @@ and func' = } -(* Modules *) +(* Tables & Memories *) -type limits = limits' Source.phrase -and limits' = +type 'size limits = 'size limits' Source.phrase +and 'size limits' = { - min : Memory.size; - max : Memory.size option; + min : 'size; + max : 'size option; } -type segment = Memory.segment Source.phrase +type ('off, 'data) segment = ('off, 'data) segment' Source.phrase +and ('off, 'data) segment' = +{ + offset : 'off; + data : 'data; +} -type memory = memory' Source.phrase -and memory' = +type ('size, 'off, 'data) store = ('size, 'off, 'data) store' Source.phrase +and ('size, 'off, 'data) store' = { - limits : limits; - segments : segment list; + limits : 'size limits; + segments : ('off, 'data) segment list; } +type table = (Table.size, Table.index, var list) store +type memory = (Memory.size, Memory.address, string) store + + +(* Modules *) + type export = export' Source.phrase and export' = { @@ -152,11 +163,11 @@ and import' = type module_ = module_' Source.phrase and module_' = { - memory : memory option; types : Types.func_type list; + table : table option; + memory : memory option; funcs : func list; start : var option; imports : import list; exports : export list; - table : var list; } diff --git a/ml-proto/spec/memory.ml b/ml-proto/spec/memory.ml index 5bae254601..a3266e6ba6 100644 --- a/ml-proto/spec/memory.ml +++ b/ml-proto/spec/memory.ml @@ -2,14 +2,15 @@ open Bigarray open Types open Values +type size = int64 type address = int64 -type size = address -type offset = address +type offset = int64 + type mem_size = Mem8 | Mem16 | Mem32 type extension = SX | ZX -type segment = {addr : address; data : string} -type value_type = Types.value_type + type value = Values.value +type value_type = Types.value_type type memory' = (int, int8_unsigned_elt, c_layout) Array1.t type memory = {mutable content : memory'; max : size option} @@ -38,7 +39,7 @@ let int64_of_host_size n = let host_index_of_int64 a n = assert (n >= 0); let n' = Int64.of_int n in - if (a < Int64.zero) || + if (a < 0L) || (Int64.sub Int64.max_int a < n') || (Int64.add a n' > Int64.of_int max_int) then raise Bounds; Int64.to_int a @@ -59,24 +60,13 @@ let create n max = assert (within_limits n max); {content = create' n; max} -let init_seg mem seg = - (* There currently is no way to blit from a string. *) - let n = String.length seg.data in - let base = host_index_of_int64 seg.addr n in - for i = 0 to n - 1 do - mem.content.{base + i} <- Char.code seg.data.[i] - done - -let init mem segs = - try List.iter (init_seg mem) segs with Invalid_argument _ -> raise Bounds - let size mem = Int64.div (int64_of_host_size (Array1.dim mem.content)) page_size -let grow mem pages = +let grow mem delta = let host_old_size = Array1.dim mem.content in let old_size = size mem in - let new_size = Int64.add old_size pages in + let new_size = Int64.add old_size delta in if I64.gt_u old_size new_size then raise SizeOverflow else if not (within_limits new_size mem.max) then raise SizeLimit else let after = create' new_size in @@ -158,3 +148,11 @@ let store_wrap mem a o sz v = | Mem16, Int64 x -> storen mem 2 ea x | Mem32, Int64 x -> storen mem 4 ea x | _ -> raise Type + +let blit mem addr data = + let base = host_index_of_int64 addr 1 in + try + for i = 0 to String.length data - 1 do + mem.content.{base + i} <- Char.code data.[i] + done + with Invalid_argument _ -> raise Bounds diff --git a/ml-proto/spec/memory.mli b/ml-proto/spec/memory.mli index f8c6561e29..e37a47f0a6 100644 --- a/ml-proto/spec/memory.mli +++ b/ml-proto/spec/memory.mli @@ -1,13 +1,15 @@ type memory type t = memory -type address = int64 + type size = int64 +type address = int64 type offset = int64 + type mem_size = Mem8 | Mem16 | Mem32 type extension = SX | ZX -type segment = {addr : address; data : string} -type value_type = Types.value_type + type value = Values.value +type value_type = Types.value_type exception Type exception Bounds @@ -17,7 +19,6 @@ exception SizeLimit val page_size : size val create : size -> size option -> memory -val init : memory -> segment list -> unit val size : memory -> size val grow : memory -> size -> unit @@ -26,4 +27,5 @@ val store : memory -> address -> offset -> value -> unit val load_extend : memory -> address -> offset -> mem_size -> extension -> value_type -> value val store_wrap : memory -> address -> offset -> mem_size -> value -> unit +val blit : memory -> address -> string -> unit diff --git a/ml-proto/spec/table.ml b/ml-proto/spec/table.ml new file mode 100644 index 0000000000..a2b96375a0 --- /dev/null +++ b/ml-proto/spec/table.ml @@ -0,0 +1,74 @@ +open Types +open Values + +type size = int32 +type index = int32 + +type elem = int option +type elem_type = Types.elem_type + +type table' = elem array +type table = {mutable content : table'; max : size option} +type t = table + +exception Bounds +exception SizeOverflow +exception SizeLimit + +(* + * These limitations should be considered part of the host environment and not + * part of the spec defined by this file. + * ========================================================================== + *) + +let host_size_of_int32 n = + if n < 0l || Int64.of_int32 n > Int64.of_int max_int then raise Out_of_memory; + Int32.to_int n + +let int32_of_host_size n = + Int32.of_int n + +let host_index_of_int32 i = + if i < 0l || Int64.of_int32 i > Int64.of_int max_int then raise Bounds; + Int32.to_int i + +(* ========================================================================== *) + +let within_limits size = function + | None -> true + | Some max -> I32.le_u size max + +let create' size = + Array.make (host_size_of_int32 size) None + +let create size max = + assert (within_limits size max); + {content = create' size; max} + +let size tab = + int32_of_host_size (Array.length tab.content) + +let grow tab delta = + let old_size = size tab in + let new_size = Int32.add old_size delta in + if I32.gt_u old_size new_size then raise SizeOverflow else + if not (within_limits new_size tab.max) then raise SizeLimit else + let after = create' new_size in + Array.blit tab.content 0 after 0 (Array.length tab.content); + tab.content <- after + +let load tab i t = + assert (t = AnyFuncType); + let j = host_index_of_int32 i in + try tab.content.(j) with Invalid_argument _ -> raise Bounds + +let store tab i v = + let j = host_index_of_int32 i in + try tab.content.(j) <- v with Invalid_argument _ -> raise Bounds + +let blit tab offset elems = + let data = Array.of_list elems in + let base = host_index_of_int32 offset in + try + Array.blit data 0 tab.content base (Array.length data) + with Invalid_argument _ -> raise Bounds diff --git a/ml-proto/spec/table.mli b/ml-proto/spec/table.mli new file mode 100644 index 0000000000..579c917545 --- /dev/null +++ b/ml-proto/spec/table.mli @@ -0,0 +1,21 @@ +type table +type t = table + +type size = int32 +type index = int32 + +type elem = int option +type elem_type = Types.elem_type + +exception Bounds +exception SizeOverflow +exception SizeLimit + +val create : size -> size option -> table +val size : table -> size +val grow : table -> size -> unit + +val load : table -> index -> elem_type -> elem +val store : table -> index -> elem -> unit +val blit : table -> index -> elem list -> unit + diff --git a/ml-proto/spec/types.ml b/ml-proto/spec/types.ml index 5081be252d..f4e7c9fb76 100644 --- a/ml-proto/spec/types.ml +++ b/ml-proto/spec/types.ml @@ -1,6 +1,7 @@ (* Types *) type value_type = Int32Type | Int64Type | Float32Type | Float64Type +type elem_type = AnyFuncType type expr_type = value_type option type func_type = {ins : value_type list; out : expr_type} diff --git a/ml-proto/test/br.wast b/ml-proto/test/br.wast index ce34922420..340d61150c 100644 --- a/ml-proto/test/br.wast +++ b/ml-proto/test/br.wast @@ -108,7 +108,7 @@ ) (type $sig (func (param i32 i32 i32) (result i32))) - (table $f) + (table (segment $f)) (func "as-call_indirect-func" (result i32) (block (call_indirect $sig diff --git a/ml-proto/test/br_table.wast b/ml-proto/test/br_table.wast index aab0a61c70..84d5f30379 100644 --- a/ml-proto/test/br_table.wast +++ b/ml-proto/test/br_table.wast @@ -929,7 +929,7 @@ ) (type $sig (func (param i32 i32 i32) (result i32))) - (table $f) + (table (segment $f)) (func "as-call_indirect-func" (result i32) (block (call_indirect $sig (br_table 0 (i32.const 20) (i32.const 1)) (i32.const 1) (i32.const 2) (i32.const 3))) ) diff --git a/ml-proto/test/call_indirect.wast b/ml-proto/test/call_indirect.wast index cf71b54e43..4325fdfabc 100644 --- a/ml-proto/test/call_indirect.wast +++ b/ml-proto/test/call_indirect.wast @@ -32,11 +32,13 @@ (func $i64-f64 (type $i64-f64) (get_local 1)) (table - $const-i32 $const-i64 $const-f32 $const-f64 - $id-i32 $id-i64 $id-f32 $id-f64 - $f32-i32 $i32-i64 $f64-f32 $i64-f64 - $fac $fib $even $odd - $runaway $mutual-runaway1 $mutual-runaway2 + (segment + $const-i32 $const-i64 $const-f32 $const-f64 + $id-i32 $id-i64 $id-f32 $id-f64 + $f32-i32 $i32-i64 $f64-f32 $i64-f64 + $fac $fib $even $odd + $runaway $mutual-runaway1 $mutual-runaway2 + ) ) ;; Typing @@ -165,9 +167,9 @@ (assert_return (invoke "dispatch" (i32.const 13) (i64.const 5)) (i64.const 8)) (assert_trap (invoke "dispatch" (i32.const 0) (i64.const 2)) "indirect call signature mismatch") (assert_trap (invoke "dispatch" (i32.const 15) (i64.const 2)) "indirect call signature mismatch") -(assert_trap (invoke "dispatch" (i32.const 20) (i64.const 2)) "undefined table index") -(assert_trap (invoke "dispatch" (i32.const -1) (i64.const 2)) "undefined table index") -(assert_trap (invoke "dispatch" (i32.const 1213432423) (i64.const 2)) "undefined table index") +(assert_trap (invoke "dispatch" (i32.const 20) (i64.const 2)) "undefined element") +(assert_trap (invoke "dispatch" (i32.const -1) (i64.const 2)) "undefined element") +(assert_trap (invoke "dispatch" (i32.const 1213432423) (i64.const 2)) "undefined element") (assert_return (invoke "fac" (i64.const 0)) (i64.const 1)) (assert_return (invoke "fac" (i64.const 1)) (i64.const 1)) @@ -198,6 +200,15 @@ (assert_invalid (module (type (func)) + (func $no-table (call_indirect 0 (i32.const 0))) + ) + "operator requires a table section" +) + +(assert_invalid + (module + (type (func)) + (table 0) (func $type-void-vs-num (i32.eqz (call_indirect 0 (i32.const 0)))) ) "type mismatch" @@ -205,6 +216,7 @@ (assert_invalid (module (type (func (result i64))) + (table 0) (func $type-num-vs-num (i32.eqz (call_indirect 0 (i32.const 0)))) ) "type mismatch" @@ -213,6 +225,7 @@ (assert_invalid (module (type (func (param i32))) + (table 0) (func $arity-0-vs-1 (call_indirect 0 (i32.const 0))) ) "arity mismatch" @@ -220,6 +233,7 @@ (assert_invalid (module (type (func (param f64 i32))) + (table 0) (func $arity-0-vs-2 (call_indirect 0 (i32.const 0))) ) "arity mismatch" @@ -227,6 +241,7 @@ (assert_invalid (module (type (func)) + (table 0) (func $arity-1-vs-0 (call_indirect 0 (i32.const 0) (i32.const 1))) ) "arity mismatch" @@ -234,6 +249,7 @@ (assert_invalid (module (type (func)) + (table 0) (func $arity-2-vs-0 (call_indirect 0 (i32.const 0) (f64.const 2) (i32.const 1)) ) @@ -244,6 +260,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0) (func $arity-nop-first (call_indirect 0 (i32.const 0) (nop) (i32.const 1) (i32.const 2)) ) @@ -253,6 +270,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0) (func $arity-nop-mid (call_indirect 0 (i32.const 0) (i32.const 1) (nop) (i32.const 2)) ) @@ -262,6 +280,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0) (func $arity-nop-last (call_indirect 0 (i32.const 0) (i32.const 1) (i32.const 2) (nop)) ) @@ -272,6 +291,7 @@ (assert_invalid (module (type (func (param i32))) + (table 0) (func $type-func-void-vs-i32 (call_indirect 0 (nop) (i32.const 1))) ) "type mismatch" @@ -279,6 +299,7 @@ (assert_invalid (module (type (func (param i32))) + (table 0) (func $type-func-num-vs-i32 (call_indirect 0 (i64.const 1) (i32.const 0))) ) "type mismatch" @@ -287,6 +308,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0) (func $type-first-void-vs-num (call_indirect 0 (i32.const 0) (nop) (i32.const 1)) ) @@ -296,6 +318,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0) (func $type-second-void-vs-num (call_indirect 0 (i32.const 0) (i32.const 1) (nop)) ) @@ -305,6 +328,7 @@ (assert_invalid (module (type (func (param i32 f64))) + (table 0) (func $type-first-num-vs-num (call_indirect 0 (i32.const 0) (f64.const 1) (i32.const 1)) ) @@ -314,6 +338,7 @@ (assert_invalid (module (type (func (param f64 i32))) + (table 0) (func $type-second-num-vs-num (call_indirect 0 (i32.const 0) (i32.const 1) (f64.const 1)) ) @@ -325,10 +350,12 @@ ;; Unbound type (assert_invalid - (module (func $unbound-type (call_indirect 1 (i32.const 0)))) + (module (table 0) (func $unbound-type (call_indirect 1 (i32.const 0)))) "unknown function type" ) (assert_invalid - (module (func $large-type (call_indirect 10001232130000 (i32.const 0)))) + (module (table 0) + (func $large-type (call_indirect 10001232130000 (i32.const 0))) + ) "unknown function type" ) diff --git a/ml-proto/test/func_ptrs.wast b/ml-proto/test/func_ptrs.wast index 8b89ec7d76..b6fab604b9 100644 --- a/ml-proto/test/func_ptrs.wast +++ b/ml-proto/test/func_ptrs.wast @@ -36,7 +36,7 @@ (module (type $T (func (param) (result i32))) (type $U (func (param) (result i32))) - (table $t1 $t2 $t3 $u1 $u2 $t1 $t3) + (table (segment $t1 $t2 $t3 $u1 $u2 $t1 $t3)) (func $t1 (type $T) (i32.const 1)) (func $t2 (type $T) (i32.const 2)) @@ -62,9 +62,9 @@ (assert_trap (invoke "callt" (i32.const 4)) "indirect call signature mismatch") (assert_return (invoke "callt" (i32.const 5)) (i32.const 1)) (assert_return (invoke "callt" (i32.const 6)) (i32.const 3)) -(assert_trap (invoke "callt" (i32.const 7)) "undefined table index 7") -(assert_trap (invoke "callt" (i32.const 100)) "undefined table index 100") -(assert_trap (invoke "callt" (i32.const -1)) "undefined table index -1") +(assert_trap (invoke "callt" (i32.const 7)) "undefined element 7") +(assert_trap (invoke "callt" (i32.const 100)) "undefined element 100") +(assert_trap (invoke "callt" (i32.const -1)) "undefined element -1") (assert_trap (invoke "callu" (i32.const 0)) "indirect call signature mismatch") (assert_trap (invoke "callu" (i32.const 1)) "indirect call signature mismatch") @@ -73,12 +73,12 @@ (assert_return (invoke "callu" (i32.const 4)) (i32.const 5)) (assert_trap (invoke "callu" (i32.const 5)) "indirect call signature mismatch") (assert_trap (invoke "callu" (i32.const 6)) "indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 7)) "undefined table index 7") -(assert_trap (invoke "callu" (i32.const -1)) "undefined table index -1") +(assert_trap (invoke "callu" (i32.const 7)) "undefined element 7") +(assert_trap (invoke "callu" (i32.const -1)) "undefined element -1") (module (type $T (func (result i32))) - (table 0 1) + (table (segment 0 1)) (import $print_i32 "spectest" "print" (param i32)) diff --git a/ml-proto/test/left-to-right.wast b/ml-proto/test/left-to-right.wast index 8c8ea104be..f3932a3356 100644 --- a/ml-proto/test/left-to-right.wast +++ b/ml-proto/test/left-to-right.wast @@ -5,7 +5,9 @@ (type $i64_T (func (param i64 i64) (result i32))) (type $f32_T (func (param f32 f32) (result i32))) (type $f64_T (func (param f64 f64) (result i32))) - (table $i32_t0 $i32_t1 $i64_t0 $i64_t1 $f32_t0 $f32_t1 $f64_t0 $f64_t1) + (table + (segment $i32_t0 $i32_t1 $i64_t0 $i64_t1 $f32_t0 $f32_t1 $f64_t0 $f64_t1) + ) (func $i32_t0 (type $i32_T) (i32.const -1)) (func $i32_t1 (type $i32_T) (i32.const -2)) diff --git a/ml-proto/test/memory.wast b/ml-proto/test/memory.wast index f05037ebbc..6e6f19c536 100644 --- a/ml-proto/test/memory.wast +++ b/ml-proto/test/memory.wast @@ -8,9 +8,14 @@ (module (memory 1 2 (segment 0 "a") (segment 65535 "b"))) (module (memory 1 2 (segment 0 "a") (segment 1 "b") (segment 2 "c"))) +(module (memory (segment "")) (func "memsize" (result i32) (current_memory))) +(assert_return (invoke "memsize") (i32.const 0)) +(module (memory (segment "x")) (func "memsize" (result i32) (current_memory))) +(assert_return (invoke "memsize") (i32.const 1)) + (assert_invalid (module (memory 1 0)) - "memory pages minimum must not be greater than maximum" + "memory size minimum must not be greater than maximum" ) (assert_invalid (module (memory 0 0 (segment 0 "a"))) @@ -34,15 +39,15 @@ ) (assert_invalid (module (memory 0 65536)) - "memory pages must be less or equal to 65535 (4GiB)" + "memory size must be less than 65536 pages (4GiB)" ) (assert_invalid (module (memory 0 2147483648)) - "memory pages must be less or equal to 65535 (4GiB)" + "memory size must be less than 65536 pages (4GiB)" ) (assert_invalid (module (memory 0 4294967296)) - "memory pages must be less or equal to 65535 (4GiB)" + "memory size must be less than 65536 pages (4GiB)" ) ;; Test alignment annotation rules diff --git a/ml-proto/test/return.wast b/ml-proto/test/return.wast index 2124b831d9..fc2574762b 100644 --- a/ml-proto/test/return.wast +++ b/ml-proto/test/return.wast @@ -119,7 +119,7 @@ ) (type $sig (func (param i32 i32 i32) (result i32))) - (table $f) + (table (segment $f)) (func "as-call_indirect-func" (result i32) (call_indirect $sig (return (i32.const 20)) (i32.const 1) (i32.const 2) (i32.const 3)) ) diff --git a/ml-proto/test/unreachable.wast b/ml-proto/test/unreachable.wast index 3ec8f9d870..d7abf81ecf 100644 --- a/ml-proto/test/unreachable.wast +++ b/ml-proto/test/unreachable.wast @@ -122,7 +122,7 @@ ) (type $sig (func (param i32 i32 i32))) - (table $dummy3) + (table (segment $dummy3)) (func "as-call_indirect-func" (call_indirect $sig (unreachable) (i32.const 1) (i32.const 2) (i32.const 3)) ) From 69c9ad4aef4fe68b4a17d6edc470066db78ad87c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Wed, 3 Aug 2016 21:47:34 +0200 Subject: [PATCH 4/5] Separate elem/data from table/memory --- ml-proto/README.md | 15 ++--- ml-proto/host/arrange.ml | 35 ++++++----- ml-proto/host/encode.ml | 28 ++++----- ml-proto/host/lexer.mll | 6 +- ml-proto/host/parser.mly | 105 +++++++++++++++++-------------- ml-proto/spec/ast.ml | 2 + ml-proto/spec/check.ml | 86 ++++++++++++------------- ml-proto/spec/decode.ml | 39 +++--------- ml-proto/spec/desugar.ml | 4 +- ml-proto/spec/eval.ml | 26 ++++---- ml-proto/spec/kernel.ml | 34 +++++----- ml-proto/spec/types.ml | 3 + ml-proto/test/address.wast | 3 +- ml-proto/test/br.wast | 2 +- ml-proto/test/br_table.wast | 2 +- ml-proto/test/call_indirect.wast | 44 +++++++------ ml-proto/test/exports.wast | 2 +- ml-proto/test/float_exprs.wast | 51 +++++++++++++-- ml-proto/test/float_memory.wast | 14 +++-- ml-proto/test/func_ptrs.wast | 7 ++- ml-proto/test/left-to-right.wast | 4 +- ml-proto/test/memory.wast | 41 ++++++++---- ml-proto/test/return.wast | 2 +- ml-proto/test/start.wast | 4 +- ml-proto/test/typecheck.wast | 4 +- ml-proto/test/unreachable.wast | 2 +- 26 files changed, 322 insertions(+), 243 deletions(-) diff --git a/ml-proto/README.md b/ml-proto/README.md index 647417b46b..47ee0b06b2 100644 --- a/ml-proto/README.md +++ b/ml-proto/README.md @@ -105,6 +105,7 @@ name: ( | | _ | . | + | - | * | / | \ | ^ | ~ | = | < | > | ! | string: "( | \n | \t | \\ | \' | \" | \)*" type: i32 | i64 | f32 | f64 +elem_type: anyfunc unop: ctz | clz | popcnt | ... binop: add | sub | mul | ... @@ -148,17 +149,17 @@ param: ( param * ) | ( param ) result: ( result ) local: ( local * ) | ( local ) -module: ( module * * * * * ? ? ) | (module +) +module: ( module * * * *
? ? * * ? ) | (module +) typedef: ( type ? ( func * ? ) ) import: ( import ? ) export: ( export ) | ( export memory) start: ( start ) -table: ( table ? * ) - ( table ( segment * ) ) ;; = (table (segment 0 *)) -memory: ( memory ? * ) - ( memory ( segment + ) ) ;; = (memory (segment 0 +)) -table-segment: ( segment * ) -memory-segment: ( segment + ) +table: ( table ? ) + ( table ( elem * ) ) ;; = (table ) (elem 0 *) +elem: ( elem * ) +memory: ( memory ? ) + ( memory ( data * ) ) ;; = (memory ) (data 0 *) +data: ( data * ) ``` Here, productions marked with respective comments are abbreviation forms for equivalent expansions (see the explanation of the kernel AST below). diff --git a/ml-proto/host/arrange.ml b/ml-proto/host/arrange.ml index f0b85b4a34..a943e48ecd 100644 --- a/ml-proto/host/arrange.ml +++ b/ml-proto/host/arrange.ml @@ -35,11 +35,17 @@ let opt f xo = list f (list_of_opt xo) let tab head f xs = if xs = [] then [] else [Node (head, list f xs)] let atom f x = Atom (f x) +let break_string s = + let ss = Lib.String.breakup s (!Flags.width / 2) in + list (atom string) ss + (* Types *) let value_type t = string_of_value_type t +let elem_type t = string_of_elem_type t + let decls kind ts = tab kind (atom value_type) ts let func_type {ins; out} = @@ -258,24 +264,23 @@ let limits int lim = let {min; max} = lim.it in String.concat " " (int min :: opt int max) -let segment int dat seg = - let {offset; data} = seg.it in - Node ("segment " ^ int offset, dat data) +let table tab = + let {tlimits = lim; etype} = tab.it in + Node ("table " ^ limits int32 lim, [atom elem_type etype]) -let elems xs = - list (atom var) xs +let memory mem = + let {mlimits = lim} = mem.it in + Node ("memory " ^ limits int64 lim, []) -let table tab = - let {limits = lim; segments} = tab.it in - Node ("table " ^ limits int32 lim, list (segment int32 elems) segments) +let segment head int dat seg = + let {offset; init} = seg.it in + Node (head ^ " " ^ int offset, dat init) -let data s = - let ss = Lib.String.breakup s (!Flags.width / 2) in - list (atom string) ss +let elems seg = + segment "elem" int32 (list (atom var)) seg -let memory mem = - let {limits = lim; segments} = mem.it in - Node ("memory " ^ limits int64 lim, list (segment int64 data) segments) +let data seg = + segment "data" int64 break_string seg (* Modules *) @@ -304,7 +309,9 @@ let module_ m = listi import m.it.imports @ listi func m.it.funcs @ opt table m.it.table @ + list elems m.it.elems @ opt memory m.it.memory @ + list data m.it.data @ list export m.it.exports @ opt start m.it.start ) diff --git a/ml-proto/host/encode.ml b/ml-proto/host/encode.ml index b7fac52ebf..cad400d719 100644 --- a/ml-proto/host/encode.ml +++ b/ml-proto/host/encode.ml @@ -331,15 +331,17 @@ let encode m = bool (max <> None); vu min; opt vu max let table tab = - elem_type AnyFuncType; - limits vu32 tab.it.limits + let {etype; tlimits} = tab.it in + elem_type etype; + limits vu32 tlimits let table_section tabo = section "table" (opt table) tabo (tabo <> None) (* Memory section *) let memory mem = - limits vu64 mem.it.limits + let {mlimits} = mem.it in + limits vu64 mlimits let memory_section memo = section "memory" (opt memory) memo (memo <> None) @@ -383,23 +385,21 @@ let encode m = (* Element section *) let segment vu dat seg = - let {offset; data} = seg.it in - vu offset; dat data + let {offset; init} = seg.it in + vu offset; dat init let table_segment seg = segment vu32 (vec var) seg - let elem_section segs = - section "element" (opt (vec table_segment)) - segs (segs <> None && segs <> Some []) + let elem_section elems = + section "element" (vec table_segment) elems (elems <> []) (* Data section *) let memory_segment seg = segment vu64 string seg - let data_section segs = - section "data" (opt (vec memory_segment)) - segs (segs <> None && segs <> Some []) + let data_section data = + section "data" (vec memory_segment) data (data <> []) (* Module *) @@ -414,9 +414,7 @@ let encode m = export_section m.it.exports; start_section m.it.start; code_section m.it.funcs; - elem_section - (Lib.Option.map (fun (tab : table) -> tab.it.segments) m.it.table); - data_section - (Lib.Option.map (fun (mem : memory) -> mem.it.segments) m.it.memory) + elem_section m.it.elems; + data_section m.it.data end in E.module_ m; to_string s diff --git a/ml-proto/host/lexer.mll b/ml-proto/host/lexer.mll index 9824be3673..1a010cb3dc 100644 --- a/ml-proto/host/lexer.mll +++ b/ml-proto/host/lexer.mll @@ -139,6 +139,7 @@ rule token = parse (fun s -> let n = F64.of_string s.it in F64_const (n @@ s.at), Values.Float64 n)) } + | "anyfunc" { ANYFUNC } | "nop" { NOP } | "unreachable" { UNREACHABLE } @@ -361,11 +362,12 @@ rule token = parse | "result" { RESULT } | "local" { LOCAL } | "module" { MODULE } + | "table" { TABLE } | "memory" { MEMORY } - | "segment" { SEGMENT } + | "elem" { ELEM } + | "data" { DATA } | "import" { IMPORT } | "export" { EXPORT } - | "table" { TABLE } | "assert_invalid" { ASSERT_INVALID } | "assert_return" { ASSERT_RETURN } diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index fc86688899..245c246439 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -124,14 +124,14 @@ let implicit_decl c t at = %} -%token NAT INT FLOAT TEXT VAR VALUE_TYPE LPAR RPAR +%token NAT INT FLOAT TEXT VAR VALUE_TYPE ANYFUNC LPAR RPAR %token NOP DROP BLOCK IF THEN ELSE SELECT LOOP BR BR_IF BR_TABLE %token CALL CALL_IMPORT CALL_INDIRECT RETURN %token GET_LOCAL SET_LOCAL TEE_LOCAL LOAD STORE OFFSET ALIGN %token CONST UNARY BINARY COMPARE CONVERT %token UNREACHABLE CURRENT_MEMORY GROW_MEMORY %token FUNC START TYPE PARAM RESULT LOCAL -%token MODULE MEMORY SEGMENT IMPORT EXPORT TABLE +%token MODULE TABLE ELEM MEMORY DATA IMPORT EXPORT TABLE %token ASSERT_INVALID ASSERT_RETURN ASSERT_RETURN_NAN ASSERT_TRAP INVOKE %token INPUT OUTPUT %token EOF @@ -166,7 +166,7 @@ let implicit_decl c t at = /* Auxiliaries */ text_list : - | TEXT { $1 } + | /* empty */ { "" } | text_list TEXT { $1 ^ $2 } ; @@ -176,6 +176,11 @@ value_type_list : | /* empty */ { [] } | VALUE_TYPE value_type_list { $1 :: $2 } ; + +elem_type : + | ANYFUNC { AnyFuncType } +; + func_type : | /* empty */ { {ins = []; out = None} } @@ -345,11 +350,12 @@ export_opt : ; -/* Modules */ +/* Tables & Memories */ -start : - | LPAR START var RPAR - { fun c -> $3 c func } +elem : + | LPAR ELEM NAT var_list RPAR + { let at = at () in + fun c -> {offset = Int32.of_string $3; init = $4 c func} @@ at } ; table_limits : @@ -357,24 +363,20 @@ table_limits : | NAT NAT { {min = Int32.of_string $1; max = Some (Int32.of_string $2)} @@ at () } ; - -table_segment : - | LPAR SEGMENT NAT var_list RPAR - { let at = at () in - fun c -> {offset = Int32.of_string $3; data = $4 c func} @@ at } -; -table_segment_list : - | /* empty */ { fun c -> [] } - | table_segment table_segment_list { fun c -> $1 c :: $2 c } -; table : - | LPAR TABLE table_limits table_segment_list RPAR - { let at = at () in fun c -> {limits = $3; segments = $4 c} @@ at } - | LPAR TABLE LPAR SEGMENT var_list RPAR RPAR /* Sugar */ + | LPAR TABLE table_limits elem_type RPAR + { let at = at () in fun c -> {tlimits = $3; etype = $4} @@ at, [] } + | LPAR TABLE elem_type LPAR ELEM var_list RPAR RPAR /* Sugar */ { let at = at () in - fun c -> let data = $5 c func in - {limits = {min = Int32.of_int (List.length data); max = None} @@ at; - segments = [{offset = 0l; data} @@ at]} @@ at } + fun c -> let init = $6 c func in + let size = Int32.of_int (List.length init) in + {tlimits = {min = size; max = Some size} @@ at; etype = $3} @@ at, + [{offset = 0l; init} @@ at] } +; + +data : + | LPAR DATA NAT text_list RPAR + { {offset = Int64.of_string $3; init = $4} @@ at () } ; memory_limits : @@ -382,24 +384,18 @@ memory_limits : | NAT NAT { {min = Int64.of_string $1; max = Some (Int64.of_string $2)} @@ at () } ; -memory_segment : - | LPAR SEGMENT NAT text_list RPAR - { {offset = Int64.of_string $3; data = $4} @@ at () } -; -memory_segment_list : - | /* empty */ { [] } - | memory_segment memory_segment_list { $1 :: $2 } -; memory : - | LPAR MEMORY memory_limits memory_segment_list RPAR - { {limits = $3; segments = $4} @@ at () } - | LPAR MEMORY LPAR SEGMENT text_list RPAR RPAR /* Sugar */ - { {limits = - {min = Int64.(div (add (of_int (String.length $5)) 65535L) 65536L); - max = None} @@ at (); - segments = [{offset = 0L; data = $5} @@ at ()] } @@ at () } + | LPAR MEMORY memory_limits RPAR + { {mlimits = $3} @@ at (), [] } + | LPAR MEMORY LPAR DATA text_list RPAR RPAR /* Sugar */ + { let size = Int64.(div (add (of_int (String.length $5)) 65535L) 65536L) in + {mlimits = {min = size; max = Some size} @@ at ()} @@ at (), + [{offset = 0L; init = $5} @@ at ()] } ; + +/* Modules */ + type_def : | LPAR TYPE LPAR FUNC func_type RPAR RPAR { fun c -> anon_type c $5 } @@ -433,11 +429,16 @@ export : { let at = at () in fun c -> {name = $3; kind = `Memory} @@ at } ; +start : + | LPAR START var RPAR + { fun c -> $3 c func } +; + module_fields : | /* empty */ { fun c -> - {table = None; memory = None; types = c.types.tlist; funcs = []; start = None; - imports = []; exports = []} } + {table = None; memory = None; types = c.types.tlist; funcs = []; + elems = []; data = []; start = None; imports = []; exports = []} } | type_def module_fields { fun c -> $1 c; $2 c } | func module_fields @@ -450,23 +451,31 @@ module_fields : { fun c -> let m = $2 c in {m with exports = $1 c :: m.exports} } | table module_fields - { fun c -> let m = $2 c in let tab = $1 c in + { fun c -> let m = $2 c in let tab, elems = $1 c in match m.table with | Some _ -> error tab.at "multiple table sections" - | None -> {m with table = Some tab} } + | None -> {m with table = Some tab; elems = elems @ m.elems} } | memory module_fields - { fun c -> let m = $2 c in + { fun c -> let m = $2 c in let mem, data = $1 in match m.memory with - | Some _ -> error $1.at "multiple memory sections" - | None -> {m with memory = Some $1} } - | start module_fields + | Some _ -> error mem.at "multiple memory sections" + | None -> {m with memory = Some mem; data = data @ m.data} } + | elem module_fields + { fun c -> let m = $2 c in + {m with elems = $1 c :: m.elems} } + | data module_fields { fun c -> let m = $2 c in - {m with start = Some ($1 c)} } + {m with data = $1 :: m.data} } + | start module_fields + { fun c -> let m = $2 c in let x = $1 c in + match m.start with + | Some _ -> error x.at "multiple start sections" + | None -> {m with start = Some x} } ; module_ : | LPAR MODULE module_fields RPAR { Textual ($3 (empty_context ()) @@ at ()) @@ at() } - | LPAR MODULE text_list RPAR { Binary $3 @@ at() } + | LPAR MODULE TEXT text_list RPAR { Binary ($3 ^ $4) @@ at() } ; diff --git a/ml-proto/spec/ast.ml b/ml-proto/spec/ast.ml index a1a1e126d8..f9b671ac17 100644 --- a/ml-proto/spec/ast.ml +++ b/ml-proto/spec/ast.ml @@ -215,6 +215,8 @@ and module' = types : Types.func_type list; funcs : func list; start : var option; + elems : Kernel.table_segment list; + data : Kernel.memory_segment list; imports : Kernel.import list; exports : Kernel.export list; } diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index 8e3e8c77eb..03ee8d2ec5 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -24,8 +24,8 @@ type context = locals : value_type list; return : expr_type; labels : expr_type_future list; - has_table : bool; - has_memory : bool; + table : Table.size option; + memory : Memory.size option; } let lookup category list x = @@ -38,6 +38,14 @@ let import c x = lookup "import" c.imports x let local c x = lookup "local" c.locals x let label c x = lookup "label" c.labels x +let size category opt at = + match opt with + | Some n -> n + | None -> error at ("no " ^ category ^ " defined") + +let table c at = size "table" c.table at +let memory c at = size "memory" c.memory at + (* Type Unification *) @@ -181,7 +189,7 @@ let rec check_expr c et e = | CallIndirect (x, e1, es) -> let {ins; out} = type_ c.types x in - check_has_table c e.at; + ignore (table c e.at); check_expr c (some Int32Type) e1; check_exprs c ins es e.at; check_type out et e.at @@ -243,7 +251,7 @@ let rec check_expr c et e = | Host (hostop, es) -> let {ins; out}, has_mem = type_hostop hostop in - if has_mem then check_has_memory c e.at; + if has_mem then ignore (memory c e.at); check_exprs c ins es e.at; check_type out et e.at @@ -262,24 +270,18 @@ and check_literal c et l = check_type (Some (type_value l.it)) et l.at and check_load c et memop e1 at = - check_has_memory c at; + ignore (memory c at); check_memop memop at; check_expr c (some Int32Type) e1; check_type (Some memop.ty) et at and check_store c et memop e1 e2 at = - check_has_memory c at; + ignore (memory c at); check_memop memop at; check_expr c (some Int32Type) e1; check_expr c (some memop.ty) e2; check_type None et at -and check_has_table c at = - require c.has_table at "operator requires a table section"; - -and check_has_memory c at = - require c.has_memory at "operator requires a memory section" - and check_memop memop at = require (memop.offset >= 0L) at "negative offset"; require (memop.offset <= 0xffffffffL) at "offset too large"; @@ -314,7 +316,7 @@ let check_func c f = (* Tables & Memories *) -let check_table_limits lim = +let check_table_limits (lim : Table.size limits) = let {min; max} = lim.it in match max with | None -> () @@ -322,22 +324,11 @@ let check_table_limits lim = require (I32.le_u min max) lim.at "table size minimum must not be greater than maximum" -let check_table_segment c size prev_end seg = - let {offset; data} = seg.it in - let len = Int32.of_int (List.length data) in - let end_ = Int32.add seg.it.offset len in - require (prev_end <= offset) seg.at "table segment not disjoint and ordered"; - require (end_ <= size) seg.at "table segment does not fit memory"; - ignore (List.map (func c) data); - end_ - -let check_table c (tab : table) = - let {limits; segments} = tab.it in - check_table_limits limits; - ignore (List.fold_left (check_table_segment c limits.it.min) 0l segments) - +let check_table (c : context) (tab : table) = + let {tlimits = lim; etype = t} = tab.it in + check_table_limits lim -let check_memory_limits lim = +let check_memory_limits (lim : Memory.size limits) = let {min; max} = lim.it in require (I64.lt_u min 65536L) lim.at "memory size must be less than 65536 pages (4GiB)"; @@ -349,20 +340,28 @@ let check_memory_limits lim = require (I64.le_u min max) lim.at "memory size minimum must not be greater than maximum" -let check_memory_segment c pages prev_end seg = - let {offset; data} = seg.it in - let len = Int64.of_int (String.length data) in +let check_memory (c : context) (mem : memory) = + let {mlimits = lim} = mem.it in + check_memory_limits lim + +let check_table_segment c prev_end seg = + let {offset; init} = seg.it in + let len = Int32.of_int (List.length init) in + let end_ = Int32.add seg.it.offset len in + require (prev_end <= offset) seg.at "table segment not disjoint and ordered"; + require (end_ <= table c seg.at) seg.at "table segment does not fit memory"; + ignore (List.map (func c) init); + end_ + +let check_memory_segment c prev_end seg = + let {offset; init} = seg.it in + let len = Int64.of_int (String.length init) in let end_ = Int64.add offset len in require (prev_end <= offset) seg.at "data segment not disjoint and ordered"; - require (end_ <= Int64.mul pages Memory.page_size) seg.at + require (end_ <= Int64.mul (memory c seg.at) Memory.page_size) seg.at "data segment does not fit memory"; end_ -let check_memory c (mem : memory) = - let {limits; segments} = mem.it in - check_memory_limits limits; - ignore (List.fold_left (check_memory_segment c limits.it.min) 0L segments) - (* Modules *) @@ -381,13 +380,14 @@ let check_export c set ex = let {name; kind} = ex.it in (match kind with | `Func x -> ignore (func c x) - | `Memory -> require c.has_memory ex.at "no memory to export" + | `Memory -> ignore (memory c ex.at) ); require (not (NameSet.mem name set)) ex.at "duplicate export name"; NameSet.add name set let check_module m = - let {types; table; memory; funcs; start; imports; exports} = m.it in + let {types; table; memory; funcs; start; elems; data; imports; exports} = m.it + in let c = { types; @@ -396,12 +396,14 @@ let check_module m = locals = []; return = None; labels = []; - has_table = table <> None; - has_memory = memory <> None; + table = Lib.Option.map (fun tab -> tab.it.tlimits.it.min) table; + memory = Lib.Option.map (fun mem -> mem.it.mlimits.it.min) memory; } in + List.iter (check_func c) funcs; Lib.Option.app (check_table c) table; Lib.Option.app (check_memory c) memory; - List.iter (check_func c) funcs; ignore (List.fold_left (check_export c) NameSet.empty exports); + ignore (List.fold_left (check_table_segment c) 0l elems); + ignore (List.fold_left (check_memory_segment c) 0L data); check_start c start diff --git a/ml-proto/spec/decode.ml b/ml-proto/spec/decode.ml index 636aa8cc0e..d00c9c3d8a 100644 --- a/ml-proto/spec/decode.ml +++ b/ml-proto/spec/decode.ml @@ -501,9 +501,8 @@ let limits vu s = let table s = let t = elem_type s in - assert (t = AnyFuncType); let lim = at (limits vu32) s in - {limits = lim; segments = []} + {etype = t; tlimits = lim} let table_section s = section `TableSection (opt (at table) true) None s @@ -513,7 +512,7 @@ let table_section s = let memory s = let lim = at (limits vu64) s in - {limits = lim; segments = []} + {mlimits = lim} let memory_section s = section `MemorySection (opt (at memory) true) None s @@ -557,8 +556,8 @@ let code_section s = let segment vu dat s = let offset = vu s in - let data = dat s in - {offset; data} + let init = dat s in + {offset; init} let table_segment s = segment vu32 (vec (at var)) s @@ -598,9 +597,9 @@ let module_ s = iterate unknown_section s; let func_types = func_section s in iterate unknown_section s; - let table_limits = table_section s in + let table = table_section s in iterate unknown_section s; - let memory_limits = memory_section s in + let memory = memory_section s in iterate unknown_section s; let exports = export_section s in iterate unknown_section s; @@ -608,9 +607,9 @@ let module_ s = iterate unknown_section s; let func_bodies = code_section s in iterate unknown_section s; - let table_segments = elem_section s in + let elems = elem_section s in iterate unknown_section s; - let memory_segments = data_section s in + let data = data_section s in iterate unknown_section s; (*TODO: name section*) iterate unknown_section s; @@ -619,26 +618,8 @@ let module_ s = s (len s) "function and code section have inconsistent lengths"; let funcs = List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at) - func_types func_bodies in - let table = - match table_limits with - | None -> - require (table_segments = []) - s (len s) "element section without memory section"; - None - | Some table -> - Some Source.({table.it with segments = table_segments} @@ table.at) - in - let memory = - match memory_limits with - | None -> - require (memory_segments = []) - s (len s) "data section without memory section"; - None - | Some memory -> - Some Source.({memory.it with segments = memory_segments} @@ memory.at) - in - {memory; types; funcs; imports; exports; table; start} + func_types func_bodies + in {types; table; memory; funcs; imports; exports; elems; data; start} let decode name bs = at module_ (stream name bs) diff --git a/ml-proto/spec/desugar.ml b/ml-proto/spec/desugar.ml index b48b09a24c..cd28dadd36 100644 --- a/ml-proto/spec/desugar.ml +++ b/ml-proto/spec/desugar.ml @@ -301,7 +301,7 @@ and func' = function let rec module_ m = module' m.it @@ m.at and module' = function - | {Ast.funcs = fs; start; memory; types; imports; exports; table} -> - {funcs = List.map func fs; start; memory; types; imports; exports; table} + | {Ast.funcs = fs; start; memory; types; imports; exports; table; elems; data} -> + {funcs = List.map func fs; start; memory; types; imports; exports; table; elems; data} let desugar = module_ diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index 6efa439c4d..9fc5638f5b 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -317,18 +317,18 @@ and eval_hostop c hostop vs at = (* Modules *) -let init_table m table = - let {limits; segments} = table.it in - let tab = Table.create limits.it.min limits.it.max in - let elems = List.map (fun x -> Some x.it) in - List.iter (fun seg -> Table.blit tab seg.it.offset (elems seg.it.data)) - segments; +let init_table m elems table = + let {tlimits = lim; _} = table.it in + let tab = Table.create lim.it.min lim.it.max in + let entries xs = List.map (fun x -> Some x.it) xs in + List.iter (fun seg -> Table.blit tab seg.it.offset (entries seg.it.init)) + elems; tab -let init_memory m memory = - let {limits; segments} = memory.it in - let mem = Memory.create limits.it.min limits.it.max in - List.iter (fun seg -> Memory.blit mem seg.it.offset seg.it.data) segments; +let init_memory m data memory = + let {mlimits = lim} = memory.it in + let mem = Memory.create lim.it.min lim.it.max in + List.iter (fun seg -> Memory.blit mem seg.it.offset seg.it.init) data; mem let add_export funcs ex = @@ -339,13 +339,13 @@ let add_export funcs ex = let init m imports = assert (List.length imports = List.length m.it.Kernel.imports); - let {table; memory; funcs; exports; start; _} = m.it in + let {table; memory; funcs; exports; elems; data; start; _} = m.it in let instance = {module_ = m; imports; exports = List.fold_right (add_export funcs) exports ExportMap.empty; - table = Lib.Option.map (init_table m) table; - memory = Lib.Option.map (init_memory m) memory} + table = Lib.Option.map (init_table m elems) table; + memory = Lib.Option.map (init_memory m data) memory} in Lib.Option.app (fun x -> ignore (eval_func instance (lookup "function" funcs x) [])) start; diff --git a/ml-proto/spec/kernel.ml b/ml-proto/spec/kernel.ml index 2ad2135722..517d1b0184 100644 --- a/ml-proto/spec/kernel.ml +++ b/ml-proto/spec/kernel.ml @@ -17,14 +17,10 @@ *) +open Types open Values -(* Types *) - -type value_type = Types.value_type - - (* Operators *) module IntOp = @@ -125,22 +121,28 @@ and 'size limits' = max : 'size option; } -type ('off, 'data) segment = ('off, 'data) segment' Source.phrase -and ('off, 'data) segment' = +type table = table' Source.phrase +and table' = { - offset : 'off; - data : 'data; + tlimits : Table.size limits; + etype : elem_type; } -type ('size, 'off, 'data) store = ('size, 'off, 'data) store' Source.phrase -and ('size, 'off, 'data) store' = +type memory = memory' Source.phrase +and memory' = { - limits : 'size limits; - segments : ('off, 'data) segment list; + mlimits : Memory.size limits; +} + +type ('off, 'data) segment = ('off, 'data) segment' Source.phrase +and ('off, 'data) segment' = +{ + offset : 'off; + init : 'data; } -type table = (Table.size, Table.index, var list) store -type memory = (Memory.size, Memory.address, string) store +type table_segment = (Table.index, var list) segment +type memory_segment = (Memory.address, string) segment (* Modules *) @@ -168,6 +170,8 @@ and module_' = memory : memory option; funcs : func list; start : var option; + elems : table_segment list; + data : memory_segment list; imports : import list; exports : export list; } diff --git a/ml-proto/spec/types.ml b/ml-proto/spec/types.ml index f4e7c9fb76..9d9a046b28 100644 --- a/ml-proto/spec/types.ml +++ b/ml-proto/spec/types.ml @@ -17,6 +17,9 @@ let string_of_value_type_list = function | [t] -> string_of_value_type t | ts -> "(" ^ String.concat " " (List.map string_of_value_type ts) ^ ")" +let string_of_elem_type = function + | AnyFuncType -> "anyfunc" + let string_of_expr_type = function | None -> "()" | Some t -> string_of_value_type t diff --git a/ml-proto/test/address.wast b/ml-proto/test/address.wast index 4eba39a70e..19a5402c41 100644 --- a/ml-proto/test/address.wast +++ b/ml-proto/test/address.wast @@ -1,5 +1,6 @@ (module - (memory 1 (segment 0 "abcdefghijklmnopqrstuvwxyz")) + (memory 1) + (data 0 "abcdefghijklmnopqrstuvwxyz") (import $print "spectest" "print" (param i32)) (func $good (param $i i32) diff --git a/ml-proto/test/br.wast b/ml-proto/test/br.wast index 340d61150c..e2cf2a1b47 100644 --- a/ml-proto/test/br.wast +++ b/ml-proto/test/br.wast @@ -108,7 +108,7 @@ ) (type $sig (func (param i32 i32 i32) (result i32))) - (table (segment $f)) + (table anyfunc (elem $f)) (func "as-call_indirect-func" (result i32) (block (call_indirect $sig diff --git a/ml-proto/test/br_table.wast b/ml-proto/test/br_table.wast index 84d5f30379..8ee433fea4 100644 --- a/ml-proto/test/br_table.wast +++ b/ml-proto/test/br_table.wast @@ -929,7 +929,7 @@ ) (type $sig (func (param i32 i32 i32) (result i32))) - (table (segment $f)) + (table anyfunc (elem $f)) (func "as-call_indirect-func" (result i32) (block (call_indirect $sig (br_table 0 (i32.const 20) (i32.const 1)) (i32.const 1) (i32.const 2) (i32.const 3))) ) diff --git a/ml-proto/test/call_indirect.wast b/ml-proto/test/call_indirect.wast index 4325fdfabc..ac62dfde3c 100644 --- a/ml-proto/test/call_indirect.wast +++ b/ml-proto/test/call_indirect.wast @@ -31,8 +31,8 @@ (func $f64-f32 (type $f64-f32) (get_local 1)) (func $i64-f64 (type $i64-f64) (get_local 1)) - (table - (segment + (table anyfunc + (elem $const-i32 $const-i64 $const-f32 $const-f64 $id-i32 $id-i64 $id-f32 $id-f64 $f32-i32 $i32-i64 $f64-f32 $i64-f64 @@ -202,13 +202,13 @@ (type (func)) (func $no-table (call_indirect 0 (i32.const 0))) ) - "operator requires a table section" + "no table" ) (assert_invalid (module (type (func)) - (table 0) + (table 0 anyfunc) (func $type-void-vs-num (i32.eqz (call_indirect 0 (i32.const 0)))) ) "type mismatch" @@ -216,7 +216,7 @@ (assert_invalid (module (type (func (result i64))) - (table 0) + (table 0 anyfunc) (func $type-num-vs-num (i32.eqz (call_indirect 0 (i32.const 0)))) ) "type mismatch" @@ -225,7 +225,7 @@ (assert_invalid (module (type (func (param i32))) - (table 0) + (table 0 anyfunc) (func $arity-0-vs-1 (call_indirect 0 (i32.const 0))) ) "arity mismatch" @@ -233,7 +233,7 @@ (assert_invalid (module (type (func (param f64 i32))) - (table 0) + (table 0 anyfunc) (func $arity-0-vs-2 (call_indirect 0 (i32.const 0))) ) "arity mismatch" @@ -241,7 +241,7 @@ (assert_invalid (module (type (func)) - (table 0) + (table 0 anyfunc) (func $arity-1-vs-0 (call_indirect 0 (i32.const 0) (i32.const 1))) ) "arity mismatch" @@ -249,7 +249,7 @@ (assert_invalid (module (type (func)) - (table 0) + (table 0 anyfunc) (func $arity-2-vs-0 (call_indirect 0 (i32.const 0) (f64.const 2) (i32.const 1)) ) @@ -260,7 +260,7 @@ (assert_invalid (module (type (func (param i32 i32))) - (table 0) + (table 0 anyfunc) (func $arity-nop-first (call_indirect 0 (i32.const 0) (nop) (i32.const 1) (i32.const 2)) ) @@ -270,7 +270,7 @@ (assert_invalid (module (type (func (param i32 i32))) - (table 0) + (table 0 anyfunc) (func $arity-nop-mid (call_indirect 0 (i32.const 0) (i32.const 1) (nop) (i32.const 2)) ) @@ -280,7 +280,7 @@ (assert_invalid (module (type (func (param i32 i32))) - (table 0) + (table 0 anyfunc) (func $arity-nop-last (call_indirect 0 (i32.const 0) (i32.const 1) (i32.const 2) (nop)) ) @@ -291,7 +291,7 @@ (assert_invalid (module (type (func (param i32))) - (table 0) + (table 0 anyfunc) (func $type-func-void-vs-i32 (call_indirect 0 (nop) (i32.const 1))) ) "type mismatch" @@ -299,7 +299,7 @@ (assert_invalid (module (type (func (param i32))) - (table 0) + (table 0 anyfunc) (func $type-func-num-vs-i32 (call_indirect 0 (i64.const 1) (i32.const 0))) ) "type mismatch" @@ -308,7 +308,7 @@ (assert_invalid (module (type (func (param i32 i32))) - (table 0) + (table 0 anyfunc) (func $type-first-void-vs-num (call_indirect 0 (i32.const 0) (nop) (i32.const 1)) ) @@ -318,7 +318,7 @@ (assert_invalid (module (type (func (param i32 i32))) - (table 0) + (table 0 anyfunc) (func $type-second-void-vs-num (call_indirect 0 (i32.const 0) (i32.const 1) (nop)) ) @@ -328,7 +328,7 @@ (assert_invalid (module (type (func (param i32 f64))) - (table 0) + (table 0 anyfunc) (func $type-first-num-vs-num (call_indirect 0 (i32.const 0) (f64.const 1) (i32.const 1)) ) @@ -338,7 +338,7 @@ (assert_invalid (module (type (func (param f64 i32))) - (table 0) + (table 0 anyfunc) (func $type-second-num-vs-num (call_indirect 0 (i32.const 0) (i32.const 1) (f64.const 1)) ) @@ -350,11 +350,15 @@ ;; Unbound type (assert_invalid - (module (table 0) (func $unbound-type (call_indirect 1 (i32.const 0)))) + (module + (table 0 anyfunc) + (func $unbound-type (call_indirect 1 (i32.const 0))) + ) "unknown function type" ) (assert_invalid - (module (table 0) + (module + (table 0 anyfunc) (func $large-type (call_indirect 10001232130000 (i32.const 0))) ) "unknown function type" diff --git a/ml-proto/test/exports.wast b/ml-proto/test/exports.wast index 08266c4fe9..3cdbb352f7 100644 --- a/ml-proto/test/exports.wast +++ b/ml-proto/test/exports.wast @@ -27,4 +27,4 @@ (module (memory 0 0) (export "a" memory)) (module (memory 0 0) (export "a" memory) (export "b" memory)) -(assert_invalid (module (export "a" memory)) "no memory to export") +(assert_invalid (module (export "a" memory)) "no memory") diff --git a/ml-proto/test/float_exprs.wast b/ml-proto/test/float_exprs.wast index b6c41e450c..a25eba08d3 100644 --- a/ml-proto/test/float_exprs.wast +++ b/ml-proto/test/float_exprs.wast @@ -1423,8 +1423,51 @@ ;; isn't optimized into plain summation. (module - (memory 1 1 - (segment 0 "\c4\c5\57\24\a5\84\c8\0b\6d\b8\4b\2e\f2\76\17\1c\ca\4a\56\1e\1b\6e\71\22\5d\17\1e\6e\bf\cd\14\5c\c7\21\55\51\39\9c\1f\b2\51\f0\a3\93\d7\c1\2c\ae\7e\a8\28\3a\01\21\f4\0a\58\93\f8\42\77\9f\83\39\6a\5f\ba\f7\0a\d8\51\6a\34\ca\ad\c6\34\0e\d8\26\dc\4c\33\1c\ed\29\90\a8\78\0f\d1\ce\76\31\23\83\b8\35\e8\f2\44\b0\d3\a1\fc\bb\32\e1\b0\ba\69\44\09\d6\d9\7d\ff\2e\c0\5a\36\14\33\14\3e\a9\fa\87\6d\8b\bc\ce\9d\a7\fd\c4\e9\85\3f\dd\d7\e1\18\a6\50\26\72\6e\3f\73\0f\f8\12\93\23\34\61\76\12\48\c0\9b\05\93\eb\ac\86\de\94\3e\55\e8\8c\e8\dd\e4\fc\95\47\be\56\03\21\20\4c\e6\bf\7b\f6\7f\d5\ba\73\1c\c1\14\8f\c4\27\96\b3\bd\33\ff\78\41\5f\c0\5a\ce\f6\67\6e\73\9a\17\66\70\03\f8\ce\27\a3\52\b2\9f\3b\bf\fb\ae\ed\d3\5a\f8\37\57\f0\f5\6e\ef\b1\4d\70\3d\54\a7\01\9a\85\08\48\91\f5\9d\0c\60\87\5b\d9\54\1e\51\6d\88\8e\08\8c\a5\71\3a\56\08\67\46\8f\8f\13\2a\2c\ec\2c\1f\b4\62\2b\6f\41\0a\c4\65\42\a2\31\6b\2c\7d\3e\bb\75\ac\86\97\30\d9\48\cd\9a\1f\56\c4\c6\e4\12\c0\9d\fb\ee\02\8c\ce\1c\f2\1e\a1\78\23\db\c4\1e\49\03\d3\71\cc\08\50\c5\d8\5c\ed\d5\b5\65\ac\b5\c9\21\d2\c9\29\76\de\f0\30\1a\5b\3c\f2\3b\db\3a\39\82\3a\16\08\6f\a8\f1\be\69\69\99\71\a6\05\d3\14\93\2a\16\f2\2f\11\c7\7e\20\bb\91\44\ee\f8\e4\01\53\c0\b9\7f\f0\bf\f0\03\9c\6d\b1\df\a2\44\01\6d\6b\71\2b\5c\b3\21\19\46\5e\8f\db\91\d3\7c\78\6b\b7\12\00\8f\eb\bd\8a\f5\d4\2e\c4\c1\1e\df\73\63\59\47\49\03\0a\b7\cf\24\cf\9c\0e\44\7a\9e\14\fb\42\bf\9d\39\30\9e\a0\ab\2f\d1\ae\9e\6a\83\43\e3\55\7d\85\bf\63\8a\f8\96\10\1f\fe\6d\e7\22\1b\e1\69\46\8a\44\c8\c8\f9\0c\2b\19\07\a5\02\3e\f2\30\10\9a\85\8a\5f\ef\81\45\a0\77\b1\03\10\73\4b\ae\98\9d\47\bf\9a\2d\3a\d5\0f\03\66\e3\3d\53\d9\40\ce\1f\6f\32\2f\21\2b\23\21\6c\62\d4\a7\3e\a8\ce\28\31\2d\00\3d\67\5e\af\a0\cf\2e\d2\b9\6b\84\eb\69\08\3c\62\36\be\12\fd\36\7f\88\3e\ad\bc\0b\c0\41\c4\50\b6\e3\50\31\e8\ce\e2\96\65\55\9c\16\46\e6\b0\2d\3a\e8\81\05\b0\bf\34\f7\bc\10\1c\fb\cc\3c\f1\85\97\42\9f\eb\14\8d\3c\bf\d7\17\88\49\9d\8b\2b\b2\3a\83\d1\4f\04\9e\a1\0f\ad\08\9d\54\af\d1\82\c3\ec\32\2f\02\8f\05\21\2d\a2\b7\e4\f4\6f\2e\81\2b\0b\9c\fc\cb\fe\74\02\f9\db\f4\f3\ea\00\a8\ec\d1\99\74\26\dd\d6\34\d5\25\b1\46\dd\9c\aa\71\f5\60\b0\88\c8\e0\0b\59\5a\25\4f\29\66\f9\e3\2e\fe\e9\da\e5\18\4f\27\62\f4\ce\a4\21\95\74\c7\57\64\27\9a\4c\fd\54\7d\61\ce\c3\ac\87\46\9c\fa\ff\09\ca\79\97\67\24\74\ca\d4\21\83\26\25\19\12\37\64\19\e5\65\e0\74\75\8e\dd\c8\ef\74\c7\d8\21\2b\79\04\51\46\65\60\03\5d\fa\d8\f4\65\a4\9e\5d\23\da\d7\8a\92\80\a4\de\78\3c\f1\57\42\6d\cd\c9\2f\d5\a4\9e\ab\40\f4\cb\1b\d7\a3\ca\fc\eb\a7\01\b2\9a\69\4e\46\9b\18\4e\dd\79\a7\aa\a6\52\39\1e\ef\30\cc\9b\bd\5b\ee\4c\21\6d\30\00\72\b0\46\5f\08\cf\c5\b9\e0\3e\c2\b3\0c\dc\8e\64\de\19\42\79\cf\43\ea\43\5d\8e\88\f7\ab\15\dc\3f\c8\67\20\db\b8\64\b1\47\1f\de\f2\cb\3f\59\9f\d8\46\90\dc\ae\2f\22\f9\e2\31\89\d9\9c\1c\4c\d3\a9\4a\57\84\9c\9f\ea\2c\3c\ae\3c\c3\1e\8b\e5\4e\17\01\25\db\34\46\5f\15\ea\05\0c\7c\d9\45\8c\19\d0\73\8a\96\16\dd\44\f9\05\b7\5b\71\b0\e6\21\36\5f\75\89\91\73\75\ab\7d\ae\d3\73\ec\37\c6\ea\55\75\ef\ea\ab\8b\7b\11\dc\6d\1a\b2\6a\c4\25\cf\aa\e3\9f\49\49\89\cb\37\9b\0a\a7\01\60\70\dc\b7\c8\83\e1\42\f5\be\ad\62\94\ad\8d\a1") + (memory 1 1) + (data 0 + "\c4\c5\57\24\a5\84\c8\0b\6d\b8\4b\2e\f2\76\17\1c\ca\4a\56\1e\1b\6e\71\22" + "\5d\17\1e\6e\bf\cd\14\5c\c7\21\55\51\39\9c\1f\b2\51\f0\a3\93\d7\c1\2c\ae" + "\7e\a8\28\3a\01\21\f4\0a\58\93\f8\42\77\9f\83\39\6a\5f\ba\f7\0a\d8\51\6a" + "\34\ca\ad\c6\34\0e\d8\26\dc\4c\33\1c\ed\29\90\a8\78\0f\d1\ce\76\31\23\83" + "\b8\35\e8\f2\44\b0\d3\a1\fc\bb\32\e1\b0\ba\69\44\09\d6\d9\7d\ff\2e\c0\5a" + "\36\14\33\14\3e\a9\fa\87\6d\8b\bc\ce\9d\a7\fd\c4\e9\85\3f\dd\d7\e1\18\a6" + "\50\26\72\6e\3f\73\0f\f8\12\93\23\34\61\76\12\48\c0\9b\05\93\eb\ac\86\de" + "\94\3e\55\e8\8c\e8\dd\e4\fc\95\47\be\56\03\21\20\4c\e6\bf\7b\f6\7f\d5\ba" + "\73\1c\c1\14\8f\c4\27\96\b3\bd\33\ff\78\41\5f\c0\5a\ce\f6\67\6e\73\9a\17" + "\66\70\03\f8\ce\27\a3\52\b2\9f\3b\bf\fb\ae\ed\d3\5a\f8\37\57\f0\f5\6e\ef" + "\b1\4d\70\3d\54\a7\01\9a\85\08\48\91\f5\9d\0c\60\87\5b\d9\54\1e\51\6d\88" + "\8e\08\8c\a5\71\3a\56\08\67\46\8f\8f\13\2a\2c\ec\2c\1f\b4\62\2b\6f\41\0a" + "\c4\65\42\a2\31\6b\2c\7d\3e\bb\75\ac\86\97\30\d9\48\cd\9a\1f\56\c4\c6\e4" + "\12\c0\9d\fb\ee\02\8c\ce\1c\f2\1e\a1\78\23\db\c4\1e\49\03\d3\71\cc\08\50" + "\c5\d8\5c\ed\d5\b5\65\ac\b5\c9\21\d2\c9\29\76\de\f0\30\1a\5b\3c\f2\3b\db" + "\3a\39\82\3a\16\08\6f\a8\f1\be\69\69\99\71\a6\05\d3\14\93\2a\16\f2\2f\11" + "\c7\7e\20\bb\91\44\ee\f8\e4\01\53\c0\b9\7f\f0\bf\f0\03\9c\6d\b1\df\a2\44" + "\01\6d\6b\71\2b\5c\b3\21\19\46\5e\8f\db\91\d3\7c\78\6b\b7\12\00\8f\eb\bd" + "\8a\f5\d4\2e\c4\c1\1e\df\73\63\59\47\49\03\0a\b7\cf\24\cf\9c\0e\44\7a\9e" + "\14\fb\42\bf\9d\39\30\9e\a0\ab\2f\d1\ae\9e\6a\83\43\e3\55\7d\85\bf\63\8a" + "\f8\96\10\1f\fe\6d\e7\22\1b\e1\69\46\8a\44\c8\c8\f9\0c\2b\19\07\a5\02\3e" + "\f2\30\10\9a\85\8a\5f\ef\81\45\a0\77\b1\03\10\73\4b\ae\98\9d\47\bf\9a\2d" + "\3a\d5\0f\03\66\e3\3d\53\d9\40\ce\1f\6f\32\2f\21\2b\23\21\6c\62\d4\a7\3e" + "\a8\ce\28\31\2d\00\3d\67\5e\af\a0\cf\2e\d2\b9\6b\84\eb\69\08\3c\62\36\be" + "\12\fd\36\7f\88\3e\ad\bc\0b\c0\41\c4\50\b6\e3\50\31\e8\ce\e2\96\65\55\9c" + "\16\46\e6\b0\2d\3a\e8\81\05\b0\bf\34\f7\bc\10\1c\fb\cc\3c\f1\85\97\42\9f" + "\eb\14\8d\3c\bf\d7\17\88\49\9d\8b\2b\b2\3a\83\d1\4f\04\9e\a1\0f\ad\08\9d" + "\54\af\d1\82\c3\ec\32\2f\02\8f\05\21\2d\a2\b7\e4\f4\6f\2e\81\2b\0b\9c\fc" + "\cb\fe\74\02\f9\db\f4\f3\ea\00\a8\ec\d1\99\74\26\dd\d6\34\d5\25\b1\46\dd" + "\9c\aa\71\f5\60\b0\88\c8\e0\0b\59\5a\25\4f\29\66\f9\e3\2e\fe\e9\da\e5\18" + "\4f\27\62\f4\ce\a4\21\95\74\c7\57\64\27\9a\4c\fd\54\7d\61\ce\c3\ac\87\46" + "\9c\fa\ff\09\ca\79\97\67\24\74\ca\d4\21\83\26\25\19\12\37\64\19\e5\65\e0" + "\74\75\8e\dd\c8\ef\74\c7\d8\21\2b\79\04\51\46\65\60\03\5d\fa\d8\f4\65\a4" + "\9e\5d\23\da\d7\8a\92\80\a4\de\78\3c\f1\57\42\6d\cd\c9\2f\d5\a4\9e\ab\40" + "\f4\cb\1b\d7\a3\ca\fc\eb\a7\01\b2\9a\69\4e\46\9b\18\4e\dd\79\a7\aa\a6\52" + "\39\1e\ef\30\cc\9b\bd\5b\ee\4c\21\6d\30\00\72\b0\46\5f\08\cf\c5\b9\e0\3e" + "\c2\b3\0c\dc\8e\64\de\19\42\79\cf\43\ea\43\5d\8e\88\f7\ab\15\dc\3f\c8\67" + "\20\db\b8\64\b1\47\1f\de\f2\cb\3f\59\9f\d8\46\90\dc\ae\2f\22\f9\e2\31\89" + "\d9\9c\1c\4c\d3\a9\4a\57\84\9c\9f\ea\2c\3c\ae\3c\c3\1e\8b\e5\4e\17\01\25" + "\db\34\46\5f\15\ea\05\0c\7c\d9\45\8c\19\d0\73\8a\96\16\dd\44\f9\05\b7\5b" + "\71\b0\e6\21\36\5f\75\89\91\73\75\ab\7d\ae\d3\73\ec\37\c6\ea\55\75\ef\ea" + "\ab\8b\7b\11\dc\6d\1a\b2\6a\c4\25\cf\aa\e3\9f\49\49\89\cb\37\9b\0a\a7\01" + "\60\70\dc\b7\c8\83\e1\42\f5\be\ad\62\94\ad\8d\a1" ) (func $f32.kahan_sum (param $p i32) (param $n i32) (result f32) @@ -1458,8 +1501,8 @@ (assert_return (invoke "f32.plain_sum" (i32.const 0) (i32.const 256)) (f32.const -0x1.a0343ap+103)) (module - (memory 1 1 - (segment 0 "\13\05\84\42\5d\a2\2c\c6\43\db\55\a9\cd\da\55\e3\73\fc\58\d6\ba\d5\00\fd\83\35\42\88\8b\13\5d\38\4a\47\0d\72\73\a1\1a\ef\c4\45\17\57\d8\c9\46\e0\8d\6c\e1\37\70\c8\83\5b\55\5e\5a\2d\73\1e\56\c8\e1\6d\69\14\78\0a\8a\5a\64\3a\09\c7\a8\87\c5\f0\d3\5d\e6\03\fc\93\be\26\ca\d6\a9\91\60\bd\b0\ed\ae\f7\30\7e\92\3a\6f\a7\59\8e\aa\7d\bf\67\58\2a\54\f8\4e\fe\ed\35\58\a6\51\bf\42\e5\4b\66\27\24\6d\7f\42\2d\28\92\18\ec\08\ae\e7\55\da\b1\a6\65\a5\72\50\47\1b\b8\a9\54\d7\a6\06\5b\0f\42\58\83\8a\17\82\c6\10\43\a0\c0\2e\6d\bc\5a\85\53\72\7f\ad\44\bc\30\3c\55\b2\24\9a\74\3a\9e\e1\d8\0f\70\fc\a9\3a\cd\93\4b\ec\e3\7e\dd\5d\27\cd\f8\a0\9d\1c\11\c0\57\2e\fd\c8\13\32\cc\3a\1a\7d\a3\41\55\ed\c3\82\49\2a\04\1e\ef\73\b9\2e\2e\e3\5f\f4\df\e6\b2\33\0c\39\3f\6f\44\6a\03\c1\42\b9\fa\b1\c8\ed\a5\58\99\7f\ed\b4\72\9e\79\eb\fb\43\82\45\aa\bb\95\d2\ff\28\9e\f6\a1\ad\95\d6\55\95\0d\6f\60\11\c7\78\3e\49\f2\7e\48\f4\a2\71\d0\13\8e\b3\de\99\52\e3\45\74\ea\76\0e\1b\2a\c8\ee\14\01\c4\50\5b\36\3c\ef\ba\72\a2\a6\08\f8\7b\36\9d\f9\ef\0b\c7\56\2d\5c\f0\9d\5d\de\fc\b8\ad\0f\64\0e\97\15\32\26\c2\31\e6\05\1e\ef\cb\17\1b\6d\15\0b\74\5d\d3\2e\f8\6b\86\b4\ba\73\52\53\99\a9\76\20\45\c9\40\80\6b\14\ed\a1\fa\80\46\e6\26\d2\e6\98\c4\57\bf\c4\1c\a4\90\7a\36\94\14\ba\15\89\6e\e6\9c\37\8c\f4\de\12\22\5d\a1\79\50\67\0d\3d\7a\e9\d4\aa\2e\7f\2a\7a\30\3d\ea\5d\12\48\fe\e1\18\cd\a4\57\a2\87\3e\b6\9a\8b\db\da\9d\78\9c\cf\8d\b1\4f\90\b4\34\e0\9d\f6\ca\fe\4c\3b\78\6d\0a\5c\18\9f\61\b9\dd\b4\e0\0f\76\e0\1b\69\0d\5e\58\73\70\5e\0e\2d\a1\7d\ff\20\eb\91\34\92\ac\38\72\2a\1f\8e\71\2e\6a\f1\af\c7\27\70\d9\c4\57\f7\d2\3c\1d\b8\f0\f0\64\cf\dc\ae\be\a3\cc\3e\22\7d\4e\69\21\63\17\ed\03\02\54\9a\0f\50\4e\13\5a\35\a1\22\a4\df\86\c2\74\79\16\b8\69\69\a0\52\5d\11\64\bd\5b\93\fc\69\a0\f4\13\d0\81\51\dd\fa\0c\15\c3\7a\c9\62\7a\a9\1d\c9\e6\5a\b3\5b\97\02\3c\64\22\12\3c\22\90\64\2d\30\54\4c\b4\a1\22\09\57\22\5e\8e\38\2b\02\a8\ae\f6\be\0d\2b\f2\03\ad\fa\10\01\71\77\2a\30\02\95\f6\00\3e\d0\c4\8d\34\19\50\21\0a\bc\50\da\3c\30\d6\3a\31\94\8d\3a\fe\ef\14\57\9d\4b\93\00\96\24\0c\6f\fd\bc\23\76\02\6c\eb\52\72\80\11\7e\80\3a\13\12\38\1d\38\49\95\40\27\8a\44\7b\e8\dc\6d\8c\8c\8e\3c\b5\b3\18\0e\f6\08\1a\84\41\35\ff\8b\b8\93\40\ea\e1\51\1d\89\a5\8d\42\68\29\ea\2f\c1\7a\52\eb\90\5d\4d\d6\80\e3\d7\75\48\ce\ed\d3\01\1c\8d\5b\a5\94\0d\78\cf\f1\06\13\2f\98\02\a4\6d\2e\6c\f2\d5\74\29\89\4c\f9\03\f5\c7\18\ad\7a\f0\68\f8\5c\d6\59\87\6e\d6\3f\06\be\86\20\e3\41\91\22\f3\6e\8b\f0\68\1c\57\a7\fc\b0\7c\9e\99\0b\96\1a\89\5f\e6\0d\7c\08\51\a0\a2\67\9a\47\00\93\6b\f9\28\f0\68\db\62\f1\e0\65\2c\53\33\e0\a7\ca\11\42\30\f6\af\01\c1\65\3d\32\01\6f\ab\2e\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05\6f\01\09\6b\e3\34\31\0c\1f\66\a6\42\bc\1a\87\49\16\16\8c\b0\90\0d\34\8c\0a\e1\09\5e\10\a4\6b\56\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8d\75\7e\b3\07\88\04\2f\b4\5e\c9\e3\4a\23\73\19\62\6c\9a\03\76\44\86\9c\60\fc\db\72\8f\27\a0\dd\b3\c5\da\ff\f9\ec\6a\b1\7b\d3\cf\50\37\c9\7a\78\0c\e4\3a\b6\f5\e6\f4\98\6e\42\7d\35\73\8b\45\c0\56\97\cd\6d\ce\cf\ad\31\b3\c3\54\fa\ef\d5\c0\f4\6a\5f\54\e7\49\3e\33\0a\30\38\fd\d9\05\ff\a5\3f\57\46\14\b5\91\17\ca\6b\98\23\7a\65\b3\6c\02\b4\cc\79\5d\58\d8\b3\d5\94\ae\f4\6d\75\65\f7\92\bf\7e\47\4c\3c\ee\db\ac\f1\32\5d\fb\6f\41\1c\34\c8\83\4f\c2\58\01\be\05\3e\66\16\a6\04\6d\5d\4f\86\09\27\82\25\12\cd\3a\cd\ce\6b\bc\ca\ac\28\9b\ee\6a\25\86\9e\45\70\c6\d2\bd\3b\7d\42\e5\27\af\c7\1d\f4\81\c8\b3\76\8a\a8\36\a3\ae\2a\e6\18\e1\36\22\ad\f6\25\72\b0\39\8b\01\9a\22\7b\84\c3\2d\5f\72\a4\98\ac\15\70\e7\d4\18\e2\7d\d2\30\7c\33\08\cd\ca\c4\22\85\88\75\81\c6\4a\74\58\8d\e0\e8\ac\c5\ab\75\5a\f4\28\12\f0\18\45\52\f2\97\b2\93\41\6f\8d\7f\db\70\fb\a3\5d\1f\a7\8d\98\20\2b\22\9f\3a\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19\5a\1f\ce\5e\cd\81\79\15\01\ca\de\73\74\8c\56\20\9f\77\2d\25\16\f6\61\51\1d\a4\8e\9b\98\a5\c6\ec\a8\45\57\82\59\78\0d\90\b4\df\51\b0\c3\82\94\cc\b3\53\09\15\6d\96\6c\3a\40\47\b7\4a\7a\05\2f\a1\1e\8c\9d\a0\20\88\fb\52\b7\9f\f3\f3\bb\5f\e7\8a\61\a7\21\b1\ac\fa\09\aa\a4\6c\bc\24\80\ba\2a\e9\65\ff\70\ff\cc\fa\65\87\76\f3\c5\15\ce\cb\e8\42\31\00\0c\91\57\d9\e0\9d\35\54\24\ad\a4\d8\f9\08\67\63\c8\cf\81\dd\90\a2\d7\c4\07\4a\e6\10\6f\67\e7\27\d4\23\59\18\f2\a8\9d\5f\d8\94\30\aa\54\86\4f\87\9d\82\b5\26\ca\a6\96\bf\cf\55\f9\9d\37\01\19\48\43\c5\94\6c\f3\74\97\58\4c\3c\9d\08\e8\04\c2\58\30\76\e1\a0\f8\ea\e9\c5\ae\cf\78\9e\a9\0c\ac\b3\44\42\e0\bc\5d\1b\9c\49\58\4a\1c\19\49\c1\3a\ea\f5\eb\3b\81\a9\4b\70\0c\cc\9e\1a\d3\2f\b7\52\2f\20\3b\eb\64\51\1d\a0\2d\b2\3e\be\13\85\48\92\32\2e\db\5c\a1\e7\8c\45\91\35\01\0a\93\c2\eb\09\ce\f3\d2\22\24\d0\8c\cc\1d\9d\38\c8\4d\e3\82\cc\64\15\06\2d\e7\01\2f\ab\bb\b5\04\4c\92\1c\7a\d6\3f\e8\5f\31\15\0c\dc\e4\31\b4\c4\25\3e\2a\aa\00\9e\c8\e5\21\7a\7f\29\f1\c0\af\1d\5e\e8\63\39\ad\f8\7e\6c\c8\c5\7f\c2\a8\97\27\0a\d9\f4\21\6a\ea\03\09\fb\f7\96\3b\83\79\5f\7c\4b\30\9f\56\35\de\b4\73\d4\95\f0\14\c3\74\2f\0d\a3\1d\4e\8d\31\24\b3\1a\84\85\62\5a\7b\3c\14\39\17\e6\6d\eb\37\c2\00\58\5b\0b\e3\3c\8a\62\e1\f8\35\4b\56\e2\87\60\8b\be\a7\38\91\77\54\a9\5a\24\25\90\9f\a5\42\77\f3\5c\39\df\ff\74\07\76\a1\cd\1f\62\0b\81\81\68\af\05\c1\c0\7f\26\ee\c0\91\a3\6a\7d\29\61\45\27\e5\57\88\dc\0d\97\04\1a\33\a9\44\8a\da\02\10\45\3f\8e\55\a6\76\8c\4d\e3\f1\89\83\c8\d0\f8\9b\50\77\9f\47\df\4c\9c\66\0d\aa\18\b8\5f\4f\c4\01\ce\dc\84\ac\46\9e\69\e1\76\45\6b\61\89\e4\5d\94\bb\11\83\9f\78\d8\0a\d2\f5\7e\5d\43\ea\bc\10\f1\3a\c9\e2\64\fb\53\65\d0\c7\b4\a7\fb\d4\05\53\25\d0\cd\29\88\00\56\25\24\7d\5d\b4\f3\41\9f\e9\b5\f7\ae\64\2c\e3\c9\6d\d5\84\3a\72\12\b8\7a\d9\1b\09\e8\38\da\26\4f\04\ce\03\71\6e\8a\44\7b\5c\81\59\9c\d2\e4\c3\ba\59\a6\e5\28\a7\8f\9a\e4\d5\4e\b9\ca\7f\cb\75\b8\2b\43\3e\b3\15\46\b1\a5\bc\9d\9e\38\15\f1\bd\1b\21\aa\f1\82\00\95\fc\a7\77\47\39\a7\33\43\92\d7\52\40\4b\06\81\8a\a0\bd\f1\6b\99\84\42\5b\e2\3b\c5\5e\12\5c\28\4d\b6\0e\4e\c8\5c\e8\01\8a\c5\e7\e4\9d\42\ee\5d\9c\c4\eb\eb\68\09\27\92\95\9a\11\54\73\c4\12\80\fb\7d\fe\c5\08\60\7f\36\41\e0\10\ba\d6\2b\6c\f1\b4\17\fe\26\34\e3\4b\f8\a8\e3\91\be\4f\2a\fc\da\81\b8\e7\fe\d5\26\50\47\f3\1a\65\32\81\e0\05\b8\4f\32\31\26\00\4a\53\97\c2\c3\0e\2e\a1\26\54\ab\05\8e\56\2f\7d\af\22\84\68\a5\8b\97\f6\a4\fd\a8\cc\75\41\96\86\fd\27\3d\29\86\8d\7f\4c\d4\8e\73\41\f4\1e\e2\dd\58\27\97\ce\9c\94\cf\7a\04\2f\dc\ed") + (memory 1 1) + (data 0 "\13\05\84\42\5d\a2\2c\c6\43\db\55\a9\cd\da\55\e3\73\fc\58\d6\ba\d5\00\fd\83\35\42\88\8b\13\5d\38\4a\47\0d\72\73\a1\1a\ef\c4\45\17\57\d8\c9\46\e0\8d\6c\e1\37\70\c8\83\5b\55\5e\5a\2d\73\1e\56\c8\e1\6d\69\14\78\0a\8a\5a\64\3a\09\c7\a8\87\c5\f0\d3\5d\e6\03\fc\93\be\26\ca\d6\a9\91\60\bd\b0\ed\ae\f7\30\7e\92\3a\6f\a7\59\8e\aa\7d\bf\67\58\2a\54\f8\4e\fe\ed\35\58\a6\51\bf\42\e5\4b\66\27\24\6d\7f\42\2d\28\92\18\ec\08\ae\e7\55\da\b1\a6\65\a5\72\50\47\1b\b8\a9\54\d7\a6\06\5b\0f\42\58\83\8a\17\82\c6\10\43\a0\c0\2e\6d\bc\5a\85\53\72\7f\ad\44\bc\30\3c\55\b2\24\9a\74\3a\9e\e1\d8\0f\70\fc\a9\3a\cd\93\4b\ec\e3\7e\dd\5d\27\cd\f8\a0\9d\1c\11\c0\57\2e\fd\c8\13\32\cc\3a\1a\7d\a3\41\55\ed\c3\82\49\2a\04\1e\ef\73\b9\2e\2e\e3\5f\f4\df\e6\b2\33\0c\39\3f\6f\44\6a\03\c1\42\b9\fa\b1\c8\ed\a5\58\99\7f\ed\b4\72\9e\79\eb\fb\43\82\45\aa\bb\95\d2\ff\28\9e\f6\a1\ad\95\d6\55\95\0d\6f\60\11\c7\78\3e\49\f2\7e\48\f4\a2\71\d0\13\8e\b3\de\99\52\e3\45\74\ea\76\0e\1b\2a\c8\ee\14\01\c4\50\5b\36\3c\ef\ba\72\a2\a6\08\f8\7b\36\9d\f9\ef\0b\c7\56\2d\5c\f0\9d\5d\de\fc\b8\ad\0f\64\0e\97\15\32\26\c2\31\e6\05\1e\ef\cb\17\1b\6d\15\0b\74\5d\d3\2e\f8\6b\86\b4\ba\73\52\53\99\a9\76\20\45\c9\40\80\6b\14\ed\a1\fa\80\46\e6\26\d2\e6\98\c4\57\bf\c4\1c\a4\90\7a\36\94\14\ba\15\89\6e\e6\9c\37\8c\f4\de\12\22\5d\a1\79\50\67\0d\3d\7a\e9\d4\aa\2e\7f\2a\7a\30\3d\ea\5d\12\48\fe\e1\18\cd\a4\57\a2\87\3e\b6\9a\8b\db\da\9d\78\9c\cf\8d\b1\4f\90\b4\34\e0\9d\f6\ca\fe\4c\3b\78\6d\0a\5c\18\9f\61\b9\dd\b4\e0\0f\76\e0\1b\69\0d\5e\58\73\70\5e\0e\2d\a1\7d\ff\20\eb\91\34\92\ac\38\72\2a\1f\8e\71\2e\6a\f1\af\c7\27\70\d9\c4\57\f7\d2\3c\1d\b8\f0\f0\64\cf\dc\ae\be\a3\cc\3e\22\7d\4e\69\21\63\17\ed\03\02\54\9a\0f\50\4e\13\5a\35\a1\22\a4\df\86\c2\74\79\16\b8\69\69\a0\52\5d\11\64\bd\5b\93\fc\69\a0\f4\13\d0\81\51\dd\fa\0c\15\c3\7a\c9\62\7a\a9\1d\c9\e6\5a\b3\5b\97\02\3c\64\22\12\3c\22\90\64\2d\30\54\4c\b4\a1\22\09\57\22\5e\8e\38\2b\02\a8\ae\f6\be\0d\2b\f2\03\ad\fa\10\01\71\77\2a\30\02\95\f6\00\3e\d0\c4\8d\34\19\50\21\0a\bc\50\da\3c\30\d6\3a\31\94\8d\3a\fe\ef\14\57\9d\4b\93\00\96\24\0c\6f\fd\bc\23\76\02\6c\eb\52\72\80\11\7e\80\3a\13\12\38\1d\38\49\95\40\27\8a\44\7b\e8\dc\6d\8c\8c\8e\3c\b5\b3\18\0e\f6\08\1a\84\41\35\ff\8b\b8\93\40\ea\e1\51\1d\89\a5\8d\42\68\29\ea\2f\c1\7a\52\eb\90\5d\4d\d6\80\e3\d7\75\48\ce\ed\d3\01\1c\8d\5b\a5\94\0d\78\cf\f1\06\13\2f\98\02\a4\6d\2e\6c\f2\d5\74\29\89\4c\f9\03\f5\c7\18\ad\7a\f0\68\f8\5c\d6\59\87\6e\d6\3f\06\be\86\20\e3\41\91\22\f3\6e\8b\f0\68\1c\57\a7\fc\b0\7c\9e\99\0b\96\1a\89\5f\e6\0d\7c\08\51\a0\a2\67\9a\47\00\93\6b\f9\28\f0\68\db\62\f1\e0\65\2c\53\33\e0\a7\ca\11\42\30\f6\af\01\c1\65\3d\32\01\6f\ab\2e\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05\6f\01\09\6b\e3\34\31\0c\1f\66\a6\42\bc\1a\87\49\16\16\8c\b0\90\0d\34\8c\0a\e1\09\5e\10\a4\6b\56\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8d\75\7e\b3\07\88\04\2f\b4\5e\c9\e3\4a\23\73\19\62\6c\9a\03\76\44\86\9c\60\fc\db\72\8f\27\a0\dd\b3\c5\da\ff\f9\ec\6a\b1\7b\d3\cf\50\37\c9\7a\78\0c\e4\3a\b6\f5\e6\f4\98\6e\42\7d\35\73\8b\45\c0\56\97\cd\6d\ce\cf\ad\31\b3\c3\54\fa\ef\d5\c0\f4\6a\5f\54\e7\49\3e\33\0a\30\38\fd\d9\05\ff\a5\3f\57\46\14\b5\91\17\ca\6b\98\23\7a\65\b3\6c\02\b4\cc\79\5d\58\d8\b3\d5\94\ae\f4\6d\75\65\f7\92\bf\7e\47\4c\3c\ee\db\ac\f1\32\5d\fb\6f\41\1c\34\c8\83\4f\c2\58\01\be\05\3e\66\16\a6\04\6d\5d\4f\86\09\27\82\25\12\cd\3a\cd\ce\6b\bc\ca\ac\28\9b\ee\6a\25\86\9e\45\70\c6\d2\bd\3b\7d\42\e5\27\af\c7\1d\f4\81\c8\b3\76\8a\a8\36\a3\ae\2a\e6\18\e1\36\22\ad\f6\25\72\b0\39\8b\01\9a\22\7b\84\c3\2d\5f\72\a4\98\ac\15\70\e7\d4\18\e2\7d\d2\30\7c\33\08\cd\ca\c4\22\85\88\75\81\c6\4a\74\58\8d\e0\e8\ac\c5\ab\75\5a\f4\28\12\f0\18\45\52\f2\97\b2\93\41\6f\8d\7f\db\70\fb\a3\5d\1f\a7\8d\98\20\2b\22\9f\3a\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19\5a\1f\ce\5e\cd\81\79\15\01\ca\de\73\74\8c\56\20\9f\77\2d\25\16\f6\61\51\1d\a4\8e\9b\98\a5\c6\ec\a8\45\57\82\59\78\0d\90\b4\df\51\b0\c3\82\94\cc\b3\53\09\15\6d\96\6c\3a\40\47\b7\4a\7a\05\2f\a1\1e\8c\9d\a0\20\88\fb\52\b7\9f\f3\f3\bb\5f\e7\8a\61\a7\21\b1\ac\fa\09\aa\a4\6c\bc\24\80\ba\2a\e9\65\ff\70\ff\cc\fa\65\87\76\f3\c5\15\ce\cb\e8\42\31\00\0c\91\57\d9\e0\9d\35\54\24\ad\a4\d8\f9\08\67\63\c8\cf\81\dd\90\a2\d7\c4\07\4a\e6\10\6f\67\e7\27\d4\23\59\18\f2\a8\9d\5f\d8\94\30\aa\54\86\4f\87\9d\82\b5\26\ca\a6\96\bf\cf\55\f9\9d\37\01\19\48\43\c5\94\6c\f3\74\97\58\4c\3c\9d\08\e8\04\c2\58\30\76\e1\a0\f8\ea\e9\c5\ae\cf\78\9e\a9\0c\ac\b3\44\42\e0\bc\5d\1b\9c\49\58\4a\1c\19\49\c1\3a\ea\f5\eb\3b\81\a9\4b\70\0c\cc\9e\1a\d3\2f\b7\52\2f\20\3b\eb\64\51\1d\a0\2d\b2\3e\be\13\85\48\92\32\2e\db\5c\a1\e7\8c\45\91\35\01\0a\93\c2\eb\09\ce\f3\d2\22\24\d0\8c\cc\1d\9d\38\c8\4d\e3\82\cc\64\15\06\2d\e7\01\2f\ab\bb\b5\04\4c\92\1c\7a\d6\3f\e8\5f\31\15\0c\dc\e4\31\b4\c4\25\3e\2a\aa\00\9e\c8\e5\21\7a\7f\29\f1\c0\af\1d\5e\e8\63\39\ad\f8\7e\6c\c8\c5\7f\c2\a8\97\27\0a\d9\f4\21\6a\ea\03\09\fb\f7\96\3b\83\79\5f\7c\4b\30\9f\56\35\de\b4\73\d4\95\f0\14\c3\74\2f\0d\a3\1d\4e\8d\31\24\b3\1a\84\85\62\5a\7b\3c\14\39\17\e6\6d\eb\37\c2\00\58\5b\0b\e3\3c\8a\62\e1\f8\35\4b\56\e2\87\60\8b\be\a7\38\91\77\54\a9\5a\24\25\90\9f\a5\42\77\f3\5c\39\df\ff\74\07\76\a1\cd\1f\62\0b\81\81\68\af\05\c1\c0\7f\26\ee\c0\91\a3\6a\7d\29\61\45\27\e5\57\88\dc\0d\97\04\1a\33\a9\44\8a\da\02\10\45\3f\8e\55\a6\76\8c\4d\e3\f1\89\83\c8\d0\f8\9b\50\77\9f\47\df\4c\9c\66\0d\aa\18\b8\5f\4f\c4\01\ce\dc\84\ac\46\9e\69\e1\76\45\6b\61\89\e4\5d\94\bb\11\83\9f\78\d8\0a\d2\f5\7e\5d\43\ea\bc\10\f1\3a\c9\e2\64\fb\53\65\d0\c7\b4\a7\fb\d4\05\53\25\d0\cd\29\88\00\56\25\24\7d\5d\b4\f3\41\9f\e9\b5\f7\ae\64\2c\e3\c9\6d\d5\84\3a\72\12\b8\7a\d9\1b\09\e8\38\da\26\4f\04\ce\03\71\6e\8a\44\7b\5c\81\59\9c\d2\e4\c3\ba\59\a6\e5\28\a7\8f\9a\e4\d5\4e\b9\ca\7f\cb\75\b8\2b\43\3e\b3\15\46\b1\a5\bc\9d\9e\38\15\f1\bd\1b\21\aa\f1\82\00\95\fc\a7\77\47\39\a7\33\43\92\d7\52\40\4b\06\81\8a\a0\bd\f1\6b\99\84\42\5b\e2\3b\c5\5e\12\5c\28\4d\b6\0e\4e\c8\5c\e8\01\8a\c5\e7\e4\9d\42\ee\5d\9c\c4\eb\eb\68\09\27\92\95\9a\11\54\73\c4\12\80\fb\7d\fe\c5\08\60\7f\36\41\e0\10\ba\d6\2b\6c\f1\b4\17\fe\26\34\e3\4b\f8\a8\e3\91\be\4f\2a\fc\da\81\b8\e7\fe\d5\26\50\47\f3\1a\65\32\81\e0\05\b8\4f\32\31\26\00\4a\53\97\c2\c3\0e\2e\a1\26\54\ab\05\8e\56\2f\7d\af\22\84\68\a5\8b\97\f6\a4\fd\a8\cc\75\41\96\86\fd\27\3d\29\86\8d\7f\4c\d4\8e\73\41\f4\1e\e2\dd\58\27\97\ce\9c\94\cf\7a\04\2f\dc\ed" ) (func $f64.kahan_sum (param $p i32) (param $n i32) (result f64) diff --git a/ml-proto/test/float_memory.wast b/ml-proto/test/float_memory.wast index b4ea4dcb8e..1b515686dd 100644 --- a/ml-proto/test/float_memory.wast +++ b/ml-proto/test/float_memory.wast @@ -3,7 +3,7 @@ ;; Test that load and store do not canonicalize NaNs as x87 does. (module - (memory 1 1 (segment 0 "\00\00\a0\7f")) + (memory (data "\00\00\a0\7f")) (func $f32.load (result f32) (f32.load (i32.const 0))) (export "f32.load" $f32.load) @@ -37,7 +37,7 @@ (assert_return (invoke "f32.load") (f32.const nan:0x200000)) (module - (memory 1 1 (segment 0 "\00\00\00\00\00\00\f4\7f")) + (memory (data "\00\00\00\00\00\00\f4\7f")) (func $f64.load (result f64) (f64.load (i32.const 0))) (export "f64.load" $f64.load) @@ -73,7 +73,8 @@ ;; Test that unaligned load and store do not canonicalize NaNs. (module - (memory 1 1 (segment 1 "\00\00\a0\7f")) + (memory 1) + (data 1 "\00\00\a0\7f") (func $f32.load (result f32) (f32.load (i32.const 1))) (export "f32.load" $f32.load) @@ -107,7 +108,8 @@ (assert_return (invoke "f32.load") (f32.const nan:0x200000)) (module - (memory 1 1 (segment 1 "\00\00\00\00\00\00\f4\7f")) + (memory 1) + (data 1 "\00\00\00\00\00\00\f4\7f") (func $f64.load (result f64) (f64.load (i32.const 1))) (export "f64.load" $f64.load) @@ -143,7 +145,7 @@ ;; Test that load and store do not canonicalize NaNs as some JS engines do. (module - (memory 1 1 (segment 0 "\01\00\d0\7f")) + (memory (data "\01\00\d0\7f")) (func $f32.load (result f32) (f32.load (i32.const 0))) (export "f32.load" $f32.load) @@ -177,7 +179,7 @@ (assert_return (invoke "f32.load") (f32.const nan:0x500001)) (module - (memory 1 1 (segment 0 "\01\00\00\00\00\00\fc\7f")) + (memory (data "\01\00\00\00\00\00\fc\7f")) (func $f64.load (result f64) (f64.load (i32.const 0))) (export "f64.load" $f64.load) diff --git a/ml-proto/test/func_ptrs.wast b/ml-proto/test/func_ptrs.wast index b6fab604b9..f80e25c2c1 100644 --- a/ml-proto/test/func_ptrs.wast +++ b/ml-proto/test/func_ptrs.wast @@ -30,13 +30,16 @@ (assert_return (invoke "three" (i32.const 13)) (i32.const 11)) (invoke "four" (i32.const 83)) +(assert_invalid (module (elem 0)) "no table defined") +(assert_invalid (module (elem 0 0) (func)) "no table defined") + (assert_invalid (module (func (type 42))) "unknown function type 42") (assert_invalid (module (import "spectest" "print" (type 43))) "unknown function type 43") (module (type $T (func (param) (result i32))) (type $U (func (param) (result i32))) - (table (segment $t1 $t2 $t3 $u1 $u2 $t1 $t3)) + (table anyfunc (elem $t1 $t2 $t3 $u1 $u2 $t1 $t3)) (func $t1 (type $T) (i32.const 1)) (func $t2 (type $T) (i32.const 2)) @@ -78,7 +81,7 @@ (module (type $T (func (result i32))) - (table (segment 0 1)) + (table anyfunc (elem 0 1)) (import $print_i32 "spectest" "print" (param i32)) diff --git a/ml-proto/test/left-to-right.wast b/ml-proto/test/left-to-right.wast index f3932a3356..707f690448 100644 --- a/ml-proto/test/left-to-right.wast +++ b/ml-proto/test/left-to-right.wast @@ -5,8 +5,8 @@ (type $i64_T (func (param i64 i64) (result i32))) (type $f32_T (func (param f32 f32) (result i32))) (type $f64_T (func (param f64 f64) (result i32))) - (table - (segment $i32_t0 $i32_t1 $i64_t0 $i64_t1 $f32_t0 $f32_t1 $f64_t0 $f64_t1) + (table anyfunc + (elem $i32_t0 $i32_t1 $i64_t0 $i64_t1 $f32_t0 $f32_t1 $f64_t0 $f64_t1) ) (func $i32_t0 (type $i32_T) (i32.const -1)) diff --git a/ml-proto/test/memory.wast b/ml-proto/test/memory.wast index 6e6f19c536..0da51375b0 100644 --- a/ml-proto/test/memory.wast +++ b/ml-proto/test/memory.wast @@ -3,38 +3,54 @@ (module (memory 0 1)) (module (memory 1 256)) (module (memory 0 65535)) -(module (memory 0 0 (segment 0 ""))) -(module (memory 1 1 (segment 0 "a"))) -(module (memory 1 2 (segment 0 "a") (segment 65535 "b"))) -(module (memory 1 2 (segment 0 "a") (segment 1 "b") (segment 2 "c"))) +(module (memory 0 0) (data 0)) +(module (memory 0 0) (data 0 "")) +(module (memory 1 1) (data 0 "a")) +(module (memory 1 2) (data 0 "a") (data 65535 "b")) +(module (memory 1 2) (data 0 "a") (data 1 "b") (data 2 "c")) -(module (memory (segment "")) (func "memsize" (result i32) (current_memory))) +(module (memory (data)) (func "memsize" (result i32) (current_memory))) (assert_return (invoke "memsize") (i32.const 0)) -(module (memory (segment "x")) (func "memsize" (result i32) (current_memory))) +(module (memory (data "")) (func "memsize" (result i32) (current_memory))) +(assert_return (invoke "memsize") (i32.const 0)) +(module (memory (data "x")) (func "memsize" (result i32) (current_memory))) (assert_return (invoke "memsize") (i32.const 1)) +(assert_invalid + (module (data 0)) + "no memory defined" +) +(assert_invalid + (module (data 0 "")) + "no memory defined" +) +(assert_invalid + (module (data 0 "x")) + "no memory defined" +) + (assert_invalid (module (memory 1 0)) "memory size minimum must not be greater than maximum" ) (assert_invalid - (module (memory 0 0 (segment 0 "a"))) + (module (memory 0 0) (data 0 "a")) "data segment does not fit memory" ) (assert_invalid - (module (memory 1 2 (segment 0 "a") (segment 98304 "b"))) + (module (memory 1 2) (data 0 "a") (data 98304 "b")) "data segment does not fit memory" ) (assert_invalid - (module (memory 1 2 (segment 0 "abc") (segment 0 "def"))) + (module (memory 1 2) (data 0 "abc") (data 0 "def")) "data segment not disjoint and ordered" ) (assert_invalid - (module (memory 1 2 (segment 3 "ab") (segment 0 "de"))) + (module (memory 1 2) (data 3 "ab") (data 0 "de")) "data segment not disjoint and ordered" ) (assert_invalid - (module (memory 1 2 (segment 0 "a") (segment 2 "b") (segment 1 "c"))) + (module (memory 1 2) (data 0 "a") (data 2 "b") (data 1 "c")) "data segment not disjoint and ordered" ) (assert_invalid @@ -78,7 +94,8 @@ ) (module - (memory 1 (segment 0 "ABC\a7D") (segment 20 "WASM")) + (memory 1) + (data 0 "ABC\a7D") (data 20 "WASM") ;; Data section (func $data (result i32) diff --git a/ml-proto/test/return.wast b/ml-proto/test/return.wast index fc2574762b..1c3a20b630 100644 --- a/ml-proto/test/return.wast +++ b/ml-proto/test/return.wast @@ -119,7 +119,7 @@ ) (type $sig (func (param i32 i32 i32) (result i32))) - (table (segment $f)) + (table anyfunc (elem $f)) (func "as-call_indirect-func" (result i32) (call_indirect $sig (return (i32.const 20)) (i32.const 1) (i32.const 2) (i32.const 3)) ) diff --git a/ml-proto/test/start.wast b/ml-proto/test/start.wast index 6b1e865d7c..00382efca0 100644 --- a/ml-proto/test/start.wast +++ b/ml-proto/test/start.wast @@ -17,7 +17,7 @@ "start function must be nullary" ) (module - (memory 1 (segment 0 "A")) + (memory (data "A")) (func $inc (i32.store8 (i32.const 0) @@ -46,7 +46,7 @@ (assert_return (invoke "get") (i32.const 70)) (module - (memory 1 (segment 0 "A")) + (memory (data "A")) (func $inc (i32.store8 (i32.const 0) diff --git a/ml-proto/test/typecheck.wast b/ml-proto/test/typecheck.wast index 8522f754f1..3b7683036f 100644 --- a/ml-proto/test/typecheck.wast +++ b/ml-proto/test/typecheck.wast @@ -19,7 +19,7 @@ (module (type (func (param i32))) (func (type 0)) - (table 0) + (table 0 anyfunc) (func (call_indirect 0 (i32.const 0) (f32.const 0)))) "type mismatch") @@ -29,7 +29,7 @@ (module (type (func)) (func (type 0)) - (table 0) + (table 0 anyfunc) (func (call_indirect 0 (f32.const 0)))) "type mismatch") diff --git a/ml-proto/test/unreachable.wast b/ml-proto/test/unreachable.wast index d7abf81ecf..6dac5a551a 100644 --- a/ml-proto/test/unreachable.wast +++ b/ml-proto/test/unreachable.wast @@ -122,7 +122,7 @@ ) (type $sig (func (param i32 i32 i32))) - (table (segment $dummy3)) + (table anyfunc (elem $dummy3)) (func "as-call_indirect-func" (call_indirect $sig (unreachable) (i32.const 1) (i32.const 2) (i32.const 3)) ) From 64f17c6c1d80dd7582c70f59b416c468837b8a3a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Thu, 4 Aug 2016 13:35:27 +0200 Subject: [PATCH 5/5] Allow const expressions as offsets --- ml-proto/README.md | 8 +++--- ml-proto/host/arrange.ml | 8 +++--- ml-proto/host/encode.ml | 10 ++++--- ml-proto/host/parser.mly | 24 +++++++++-------- ml-proto/spec/ast.ml | 11 ++++++-- ml-proto/spec/check.ml | 21 ++++++++++++--- ml-proto/spec/decode.ml | 15 ++++++++--- ml-proto/spec/desugar.ml | 6 ++++- ml-proto/spec/eval.ml | 31 +++++++++++++++++----- ml-proto/spec/eval.mli | 1 + ml-proto/spec/kernel.ml | 10 +++---- ml-proto/spec/values.ml | 10 +++++++ ml-proto/test/address.wast | 2 +- ml-proto/test/float_exprs.wast | 10 +++---- ml-proto/test/float_memory.wast | 6 ++--- ml-proto/test/func_ptrs.wast | 8 ++++-- ml-proto/test/memory.wast | 46 +++++++++++++++++++++++---------- 17 files changed, 154 insertions(+), 73 deletions(-) diff --git a/ml-proto/README.md b/ml-proto/README.md index 47ee0b06b2..b7141ff656 100644 --- a/ml-proto/README.md +++ b/ml-proto/README.md @@ -155,11 +155,11 @@ import: ( import ? ) export: ( export ) | ( export memory) start: ( start ) table: ( table ? ) - ( table ( elem * ) ) ;; = (table ) (elem 0 *) -elem: ( elem * ) + ( table ( elem * ) ) ;; = (table ) (elem (i32.const 0) *) +elem: ( elem * ) memory: ( memory ? ) - ( memory ( data * ) ) ;; = (memory ) (data 0 *) -data: ( data * ) + ( memory ( data * ) ) ;; = (memory ) (data (i32.const 0) *) +data: ( data * ) ``` Here, productions marked with respective comments are abbreviation forms for equivalent expansions (see the explanation of the kernel AST below). diff --git a/ml-proto/host/arrange.ml b/ml-proto/host/arrange.ml index a943e48ecd..5446f350b5 100644 --- a/ml-proto/host/arrange.ml +++ b/ml-proto/host/arrange.ml @@ -272,15 +272,15 @@ let memory mem = let {mlimits = lim} = mem.it in Node ("memory " ^ limits int64 lim, []) -let segment head int dat seg = +let segment head dat seg = let {offset; init} = seg.it in - Node (head ^ " " ^ int offset, dat init) + Node (head, expr offset :: dat init) let elems seg = - segment "elem" int32 (list (atom var)) seg + segment "elem" (list (atom var)) seg let data seg = - segment "data" int64 break_string seg + segment "data" break_string seg (* Modules *) diff --git a/ml-proto/host/encode.ml b/ml-proto/host/encode.ml index cad400d719..4a3b862147 100644 --- a/ml-proto/host/encode.ml +++ b/ml-proto/host/encode.ml @@ -296,6 +296,8 @@ let encode m = and nary es o = list expr es; op o; arity es and nary1 eo o = opt expr eo; op o; arity1 eo + let const e = expr e; op 0x0f + (* Sections *) let section id f x needed = @@ -384,19 +386,19 @@ let encode m = section "code" (vec code) fs (fs <> []) (* Element section *) - let segment vu dat seg = + let segment dat seg = let {offset; init} = seg.it in - vu offset; dat init + const offset; dat init let table_segment seg = - segment vu32 (vec var) seg + segment (vec var) seg let elem_section elems = section "element" (vec table_segment) elems (elems <> []) (* Data section *) let memory_segment seg = - segment vu64 string seg + segment string seg let data_section data = section "data" (vec memory_segment) data (data <> []) diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index 245c246439..f112f073bb 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -353,9 +353,9 @@ export_opt : /* Tables & Memories */ elem : - | LPAR ELEM NAT var_list RPAR + | LPAR ELEM expr var_list RPAR { let at = at () in - fun c -> {offset = Int32.of_string $3; init = $4 c func} @@ at } + fun c -> {offset = $3 c; init = $4 c func} @@ at } ; table_limits : @@ -371,12 +371,12 @@ table : fun c -> let init = $6 c func in let size = Int32.of_int (List.length init) in {tlimits = {min = size; max = Some size} @@ at; etype = $3} @@ at, - [{offset = 0l; init} @@ at] } + [{offset = I32_const (0l @@ at) @@ at; init} @@ at] } ; data : - | LPAR DATA NAT text_list RPAR - { {offset = Int64.of_string $3; init = $4} @@ at () } + | LPAR DATA expr text_list RPAR + { fun c -> {offset = $3 c; init = $4} @@ at () } ; memory_limits : @@ -386,11 +386,13 @@ memory_limits : ; memory : | LPAR MEMORY memory_limits RPAR - { {mlimits = $3} @@ at (), [] } + { fun c -> {mlimits = $3} @@ at (), [] } | LPAR MEMORY LPAR DATA text_list RPAR RPAR /* Sugar */ - { let size = Int64.(div (add (of_int (String.length $5)) 65535L) 65536L) in - {mlimits = {min = size; max = Some size} @@ at ()} @@ at (), - [{offset = 0L; init = $5} @@ at ()] } + { let at = at () in + fun c -> + let size = Int64.(div (add (of_int (String.length $5)) 65535L) 65536L) in + {mlimits = {min = size; max = Some size} @@ at} @@ at, + [{offset = I32_const (0l @@ at) @@ at; init = $5} @@ at] } ; @@ -456,7 +458,7 @@ module_fields : | Some _ -> error tab.at "multiple table sections" | None -> {m with table = Some tab; elems = elems @ m.elems} } | memory module_fields - { fun c -> let m = $2 c in let mem, data = $1 in + { fun c -> let m = $2 c in let mem, data = $1 c in match m.memory with | Some _ -> error mem.at "multiple memory sections" | None -> {m with memory = Some mem; data = data @ m.data} } @@ -465,7 +467,7 @@ module_fields : {m with elems = $1 c :: m.elems} } | data module_fields { fun c -> let m = $2 c in - {m with data = $1 :: m.data} } + {m with data = $1 c :: m.data} } | start module_fields { fun c -> let m = $2 c in let x = $1 c in match m.start with diff --git a/ml-proto/spec/ast.ml b/ml-proto/spec/ast.ml index f9b671ac17..d0f14d6dc5 100644 --- a/ml-proto/spec/ast.ml +++ b/ml-proto/spec/ast.ml @@ -207,6 +207,13 @@ and func' = (* Modules *) +type 'data segment = 'data segment' Source.phrase +and 'data segment' = +{ + offset : expr; + init : 'data; +} + type module_ = module' Source.phrase and module' = { @@ -215,8 +222,8 @@ and module' = types : Types.func_type list; funcs : func list; start : var option; - elems : Kernel.table_segment list; - data : Kernel.memory_segment list; + elems : var list segment list; + data : string segment list; imports : Kernel.import list; exports : Kernel.export list; } diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index 03ee8d2ec5..87fa5f41ef 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -18,6 +18,7 @@ type expr_type_future = [`Known of expr_type | `SomeUnknown] ref type context = { + module_ : module_; types : func_type list; funcs : func_type list; imports : func_type list; @@ -290,6 +291,12 @@ and check_memop memop at = and check_mem_type ty sz at = require (ty = Int64Type || sz <> Memory.Mem32) at "memory size too big" +let check_const c et e = + check_expr c (some et) e; + match e.it with + | Const _ -> () + | _ -> error e.at "constant expression required" + (* Functions *) @@ -346,18 +353,23 @@ let check_memory (c : context) (mem : memory) = let check_table_segment c prev_end seg = let {offset; init} = seg.it in + check_const c Int32Type offset; + let start = Values.int32_of_value (Eval.const c.module_ offset) in let len = Int32.of_int (List.length init) in - let end_ = Int32.add seg.it.offset len in - require (prev_end <= offset) seg.at "table segment not disjoint and ordered"; + let end_ = Int32.add start len in + require (prev_end <= start) seg.at "table segment not disjoint and ordered"; require (end_ <= table c seg.at) seg.at "table segment does not fit memory"; ignore (List.map (func c) init); end_ let check_memory_segment c prev_end seg = let {offset; init} = seg.it in + check_const c Int32Type offset; + let start = + Int64.of_int32 (Values.int32_of_value (Eval.const c.module_ offset)) in let len = Int64.of_int (String.length init) in - let end_ = Int64.add offset len in - require (prev_end <= offset) seg.at "data segment not disjoint and ordered"; + let end_ = Int64.add start len in + require (prev_end <= start) seg.at "data segment not disjoint and ordered"; require (end_ <= Int64.mul (memory c seg.at) Memory.page_size) seg.at "data segment does not fit memory"; end_ @@ -390,6 +402,7 @@ let check_module m = in let c = { + module_ = m; types; funcs = List.map (fun f -> type_ types f.it.ftype) funcs; imports = List.map (fun i -> type_ types i.it.itype) imports; diff --git a/ml-proto/spec/decode.ml b/ml-proto/spec/decode.ml index d00c9c3d8a..a84fe755c4 100644 --- a/ml-proto/spec/decode.ml +++ b/ml-proto/spec/decode.ml @@ -434,6 +434,13 @@ and expr_block' stack s = let e', stack' = expr stack s in expr_block' (Source.(e' @@ region s pos pos) :: stack') s +let const s = + match expr_block s with + | [e] -> + expect 0x0f s "`end` opcode expected"; + e + | _ -> error s (pos s) "too many expressions" + (* Sections *) @@ -554,13 +561,13 @@ let code_section s = (* Element section *) -let segment vu dat s = - let offset = vu s in +let segment dat s = + let offset = const s in let init = dat s in {offset; init} let table_segment s = - segment vu32 (vec (at var)) s + segment (vec (at var)) s let elem_section s = section `ElemSection (vec (at table_segment)) [] s @@ -569,7 +576,7 @@ let elem_section s = (* Data section *) let memory_segment s = - segment vu64 string s + segment string s let data_section s = section `DataSection (vec (at memory_segment)) [] s diff --git a/ml-proto/spec/desugar.ml b/ml-proto/spec/desugar.ml index cd28dadd36..cb66de0d56 100644 --- a/ml-proto/spec/desugar.ml +++ b/ml-proto/spec/desugar.ml @@ -299,9 +299,13 @@ let rec func f = func' f.it @@ f.at and func' = function | {Ast.body = es; ftype; locals} -> {body = return (seq es); ftype; locals} +let rec segment seg = segment' seg.it @@ seg.at +and segment' = function + | {Ast.offset = e; init} -> {offset = expr e; init} + let rec module_ m = module' m.it @@ m.at and module' = function | {Ast.funcs = fs; start; memory; types; imports; exports; table; elems; data} -> - {funcs = List.map func fs; start; memory; types; imports; exports; table; elems; data} + {funcs = List.map func fs; start; memory; types; imports; exports; table; elems = List.map segment elems; data = List.map segment data} let desugar = module_ diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index 9fc5638f5b..1db0d6362e 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -109,6 +109,11 @@ let int32 v at = | Int32 i -> i | v -> type_error at v Int32Type +let int64 v at = + match some v at with + | Int64 i -> i + | v -> type_error at v Int64Type + let address32 v at = Int64.logand (Int64.of_int32 (int32 v at)) 0xffffffffL @@ -317,18 +322,30 @@ and eval_hostop c hostop vs at = (* Modules *) +let const m e = + let inst = + {module_ = m; imports = []; exports = ExportMap.empty; + table = None; memory = None} + in some (eval_expr {instance = inst; locals = []; labels = []} e) e.at + +let offset m seg = + int32 (Some (const m seg.it.offset)) seg.it.offset.at + let init_table m elems table = let {tlimits = lim; _} = table.it in let tab = Table.create lim.it.min lim.it.max in let entries xs = List.map (fun x -> Some x.it) xs in - List.iter (fun seg -> Table.blit tab seg.it.offset (entries seg.it.init)) + List.iter + (fun seg -> Table.blit tab (offset m seg) (entries seg.it.init)) elems; tab let init_memory m data memory = let {mlimits = lim} = memory.it in let mem = Memory.create lim.it.min lim.it.max in - List.iter (fun seg -> Memory.blit mem seg.it.offset seg.it.init) data; + List.iter + (fun seg -> Memory.blit mem (Int64.of_int32 (offset m seg)) seg.it.init) + data; mem let add_export funcs ex = @@ -340,7 +357,7 @@ let add_export funcs ex = let init m imports = assert (List.length imports = List.length m.it.Kernel.imports); let {table; memory; funcs; exports; elems; data; start; _} = m.it in - let instance = + let inst = {module_ = m; imports; exports = List.fold_right (add_export funcs) exports ExportMap.empty; @@ -348,10 +365,10 @@ let init m imports = memory = Lib.Option.map (init_memory m data) memory} in Lib.Option.app - (fun x -> ignore (eval_func instance (lookup "function" funcs x) [])) start; - instance + (fun x -> ignore (eval_func inst (lookup "function" funcs x) [])) start; + inst -let invoke instance name vs = +let invoke inst name vs = try - eval_func instance (export instance (name @@ no_region)) vs + eval_func inst (export inst (name @@ no_region)) vs with Stack_overflow -> Trap.error Source.no_region "call stack exhausted" diff --git a/ml-proto/spec/eval.mli b/ml-proto/spec/eval.mli index c8c4390bd7..703a242170 100644 --- a/ml-proto/spec/eval.mli +++ b/ml-proto/spec/eval.mli @@ -8,3 +8,4 @@ exception Crash of Source.region * string val init : Kernel.module_ -> import list -> instance val invoke : instance -> string -> value list -> value option (* raises Trap, Crash *) +val const : Kernel.module_ -> Kernel.expr -> value diff --git a/ml-proto/spec/kernel.ml b/ml-proto/spec/kernel.ml index 517d1b0184..2c8b27d053 100644 --- a/ml-proto/spec/kernel.ml +++ b/ml-proto/spec/kernel.ml @@ -134,15 +134,15 @@ and memory' = mlimits : Memory.size limits; } -type ('off, 'data) segment = ('off, 'data) segment' Source.phrase -and ('off, 'data) segment' = +type 'data segment = 'data segment' Source.phrase +and 'data segment' = { - offset : 'off; + offset : expr; init : 'data; } -type table_segment = (Table.index, var list) segment -type memory_segment = (Memory.address, string) segment +type table_segment = var list segment +type memory_segment = string segment (* Modules *) diff --git a/ml-proto/spec/values.ml b/ml-proto/spec/values.ml index 353b943fb2..28f6870633 100644 --- a/ml-proto/spec/values.ml +++ b/ml-proto/spec/values.ml @@ -36,3 +36,13 @@ let string_of_value = function let string_of_values = function | [v] -> string_of_value v | vs -> "(" ^ String.concat " " (List.map string_of_value vs) ^ ")" + +(* TODO(stack): merge this with stack branch's additions *) + +let int32_of_value = function + | Int32 n -> n + | _ -> raise (Invalid_argument "int32_of_value") + +let int64_of_value = function + | Int64 n -> n + | _ -> raise (Invalid_argument "int64_of_value") diff --git a/ml-proto/test/address.wast b/ml-proto/test/address.wast index 19a5402c41..9007af064e 100644 --- a/ml-proto/test/address.wast +++ b/ml-proto/test/address.wast @@ -1,6 +1,6 @@ (module (memory 1) - (data 0 "abcdefghijklmnopqrstuvwxyz") + (data (i32.const 0) "abcdefghijklmnopqrstuvwxyz") (import $print "spectest" "print" (param i32)) (func $good (param $i i32) diff --git a/ml-proto/test/float_exprs.wast b/ml-proto/test/float_exprs.wast index a25eba08d3..154dd71e15 100644 --- a/ml-proto/test/float_exprs.wast +++ b/ml-proto/test/float_exprs.wast @@ -1423,8 +1423,7 @@ ;; isn't optimized into plain summation. (module - (memory 1 1) - (data 0 + (memory (data "\c4\c5\57\24\a5\84\c8\0b\6d\b8\4b\2e\f2\76\17\1c\ca\4a\56\1e\1b\6e\71\22" "\5d\17\1e\6e\bf\cd\14\5c\c7\21\55\51\39\9c\1f\b2\51\f0\a3\93\d7\c1\2c\ae" "\7e\a8\28\3a\01\21\f4\0a\58\93\f8\42\77\9f\83\39\6a\5f\ba\f7\0a\d8\51\6a" @@ -1468,7 +1467,7 @@ "\71\b0\e6\21\36\5f\75\89\91\73\75\ab\7d\ae\d3\73\ec\37\c6\ea\55\75\ef\ea" "\ab\8b\7b\11\dc\6d\1a\b2\6a\c4\25\cf\aa\e3\9f\49\49\89\cb\37\9b\0a\a7\01" "\60\70\dc\b7\c8\83\e1\42\f5\be\ad\62\94\ad\8d\a1" - ) + )) (func $f32.kahan_sum (param $p i32) (param $n i32) (result f32) (local $sum f32) @@ -1501,9 +1500,8 @@ (assert_return (invoke "f32.plain_sum" (i32.const 0) (i32.const 256)) (f32.const -0x1.a0343ap+103)) (module - (memory 1 1) - (data 0 "\13\05\84\42\5d\a2\2c\c6\43\db\55\a9\cd\da\55\e3\73\fc\58\d6\ba\d5\00\fd\83\35\42\88\8b\13\5d\38\4a\47\0d\72\73\a1\1a\ef\c4\45\17\57\d8\c9\46\e0\8d\6c\e1\37\70\c8\83\5b\55\5e\5a\2d\73\1e\56\c8\e1\6d\69\14\78\0a\8a\5a\64\3a\09\c7\a8\87\c5\f0\d3\5d\e6\03\fc\93\be\26\ca\d6\a9\91\60\bd\b0\ed\ae\f7\30\7e\92\3a\6f\a7\59\8e\aa\7d\bf\67\58\2a\54\f8\4e\fe\ed\35\58\a6\51\bf\42\e5\4b\66\27\24\6d\7f\42\2d\28\92\18\ec\08\ae\e7\55\da\b1\a6\65\a5\72\50\47\1b\b8\a9\54\d7\a6\06\5b\0f\42\58\83\8a\17\82\c6\10\43\a0\c0\2e\6d\bc\5a\85\53\72\7f\ad\44\bc\30\3c\55\b2\24\9a\74\3a\9e\e1\d8\0f\70\fc\a9\3a\cd\93\4b\ec\e3\7e\dd\5d\27\cd\f8\a0\9d\1c\11\c0\57\2e\fd\c8\13\32\cc\3a\1a\7d\a3\41\55\ed\c3\82\49\2a\04\1e\ef\73\b9\2e\2e\e3\5f\f4\df\e6\b2\33\0c\39\3f\6f\44\6a\03\c1\42\b9\fa\b1\c8\ed\a5\58\99\7f\ed\b4\72\9e\79\eb\fb\43\82\45\aa\bb\95\d2\ff\28\9e\f6\a1\ad\95\d6\55\95\0d\6f\60\11\c7\78\3e\49\f2\7e\48\f4\a2\71\d0\13\8e\b3\de\99\52\e3\45\74\ea\76\0e\1b\2a\c8\ee\14\01\c4\50\5b\36\3c\ef\ba\72\a2\a6\08\f8\7b\36\9d\f9\ef\0b\c7\56\2d\5c\f0\9d\5d\de\fc\b8\ad\0f\64\0e\97\15\32\26\c2\31\e6\05\1e\ef\cb\17\1b\6d\15\0b\74\5d\d3\2e\f8\6b\86\b4\ba\73\52\53\99\a9\76\20\45\c9\40\80\6b\14\ed\a1\fa\80\46\e6\26\d2\e6\98\c4\57\bf\c4\1c\a4\90\7a\36\94\14\ba\15\89\6e\e6\9c\37\8c\f4\de\12\22\5d\a1\79\50\67\0d\3d\7a\e9\d4\aa\2e\7f\2a\7a\30\3d\ea\5d\12\48\fe\e1\18\cd\a4\57\a2\87\3e\b6\9a\8b\db\da\9d\78\9c\cf\8d\b1\4f\90\b4\34\e0\9d\f6\ca\fe\4c\3b\78\6d\0a\5c\18\9f\61\b9\dd\b4\e0\0f\76\e0\1b\69\0d\5e\58\73\70\5e\0e\2d\a1\7d\ff\20\eb\91\34\92\ac\38\72\2a\1f\8e\71\2e\6a\f1\af\c7\27\70\d9\c4\57\f7\d2\3c\1d\b8\f0\f0\64\cf\dc\ae\be\a3\cc\3e\22\7d\4e\69\21\63\17\ed\03\02\54\9a\0f\50\4e\13\5a\35\a1\22\a4\df\86\c2\74\79\16\b8\69\69\a0\52\5d\11\64\bd\5b\93\fc\69\a0\f4\13\d0\81\51\dd\fa\0c\15\c3\7a\c9\62\7a\a9\1d\c9\e6\5a\b3\5b\97\02\3c\64\22\12\3c\22\90\64\2d\30\54\4c\b4\a1\22\09\57\22\5e\8e\38\2b\02\a8\ae\f6\be\0d\2b\f2\03\ad\fa\10\01\71\77\2a\30\02\95\f6\00\3e\d0\c4\8d\34\19\50\21\0a\bc\50\da\3c\30\d6\3a\31\94\8d\3a\fe\ef\14\57\9d\4b\93\00\96\24\0c\6f\fd\bc\23\76\02\6c\eb\52\72\80\11\7e\80\3a\13\12\38\1d\38\49\95\40\27\8a\44\7b\e8\dc\6d\8c\8c\8e\3c\b5\b3\18\0e\f6\08\1a\84\41\35\ff\8b\b8\93\40\ea\e1\51\1d\89\a5\8d\42\68\29\ea\2f\c1\7a\52\eb\90\5d\4d\d6\80\e3\d7\75\48\ce\ed\d3\01\1c\8d\5b\a5\94\0d\78\cf\f1\06\13\2f\98\02\a4\6d\2e\6c\f2\d5\74\29\89\4c\f9\03\f5\c7\18\ad\7a\f0\68\f8\5c\d6\59\87\6e\d6\3f\06\be\86\20\e3\41\91\22\f3\6e\8b\f0\68\1c\57\a7\fc\b0\7c\9e\99\0b\96\1a\89\5f\e6\0d\7c\08\51\a0\a2\67\9a\47\00\93\6b\f9\28\f0\68\db\62\f1\e0\65\2c\53\33\e0\a7\ca\11\42\30\f6\af\01\c1\65\3d\32\01\6f\ab\2e\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05\6f\01\09\6b\e3\34\31\0c\1f\66\a6\42\bc\1a\87\49\16\16\8c\b0\90\0d\34\8c\0a\e1\09\5e\10\a4\6b\56\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8d\75\7e\b3\07\88\04\2f\b4\5e\c9\e3\4a\23\73\19\62\6c\9a\03\76\44\86\9c\60\fc\db\72\8f\27\a0\dd\b3\c5\da\ff\f9\ec\6a\b1\7b\d3\cf\50\37\c9\7a\78\0c\e4\3a\b6\f5\e6\f4\98\6e\42\7d\35\73\8b\45\c0\56\97\cd\6d\ce\cf\ad\31\b3\c3\54\fa\ef\d5\c0\f4\6a\5f\54\e7\49\3e\33\0a\30\38\fd\d9\05\ff\a5\3f\57\46\14\b5\91\17\ca\6b\98\23\7a\65\b3\6c\02\b4\cc\79\5d\58\d8\b3\d5\94\ae\f4\6d\75\65\f7\92\bf\7e\47\4c\3c\ee\db\ac\f1\32\5d\fb\6f\41\1c\34\c8\83\4f\c2\58\01\be\05\3e\66\16\a6\04\6d\5d\4f\86\09\27\82\25\12\cd\3a\cd\ce\6b\bc\ca\ac\28\9b\ee\6a\25\86\9e\45\70\c6\d2\bd\3b\7d\42\e5\27\af\c7\1d\f4\81\c8\b3\76\8a\a8\36\a3\ae\2a\e6\18\e1\36\22\ad\f6\25\72\b0\39\8b\01\9a\22\7b\84\c3\2d\5f\72\a4\98\ac\15\70\e7\d4\18\e2\7d\d2\30\7c\33\08\cd\ca\c4\22\85\88\75\81\c6\4a\74\58\8d\e0\e8\ac\c5\ab\75\5a\f4\28\12\f0\18\45\52\f2\97\b2\93\41\6f\8d\7f\db\70\fb\a3\5d\1f\a7\8d\98\20\2b\22\9f\3a\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19\5a\1f\ce\5e\cd\81\79\15\01\ca\de\73\74\8c\56\20\9f\77\2d\25\16\f6\61\51\1d\a4\8e\9b\98\a5\c6\ec\a8\45\57\82\59\78\0d\90\b4\df\51\b0\c3\82\94\cc\b3\53\09\15\6d\96\6c\3a\40\47\b7\4a\7a\05\2f\a1\1e\8c\9d\a0\20\88\fb\52\b7\9f\f3\f3\bb\5f\e7\8a\61\a7\21\b1\ac\fa\09\aa\a4\6c\bc\24\80\ba\2a\e9\65\ff\70\ff\cc\fa\65\87\76\f3\c5\15\ce\cb\e8\42\31\00\0c\91\57\d9\e0\9d\35\54\24\ad\a4\d8\f9\08\67\63\c8\cf\81\dd\90\a2\d7\c4\07\4a\e6\10\6f\67\e7\27\d4\23\59\18\f2\a8\9d\5f\d8\94\30\aa\54\86\4f\87\9d\82\b5\26\ca\a6\96\bf\cf\55\f9\9d\37\01\19\48\43\c5\94\6c\f3\74\97\58\4c\3c\9d\08\e8\04\c2\58\30\76\e1\a0\f8\ea\e9\c5\ae\cf\78\9e\a9\0c\ac\b3\44\42\e0\bc\5d\1b\9c\49\58\4a\1c\19\49\c1\3a\ea\f5\eb\3b\81\a9\4b\70\0c\cc\9e\1a\d3\2f\b7\52\2f\20\3b\eb\64\51\1d\a0\2d\b2\3e\be\13\85\48\92\32\2e\db\5c\a1\e7\8c\45\91\35\01\0a\93\c2\eb\09\ce\f3\d2\22\24\d0\8c\cc\1d\9d\38\c8\4d\e3\82\cc\64\15\06\2d\e7\01\2f\ab\bb\b5\04\4c\92\1c\7a\d6\3f\e8\5f\31\15\0c\dc\e4\31\b4\c4\25\3e\2a\aa\00\9e\c8\e5\21\7a\7f\29\f1\c0\af\1d\5e\e8\63\39\ad\f8\7e\6c\c8\c5\7f\c2\a8\97\27\0a\d9\f4\21\6a\ea\03\09\fb\f7\96\3b\83\79\5f\7c\4b\30\9f\56\35\de\b4\73\d4\95\f0\14\c3\74\2f\0d\a3\1d\4e\8d\31\24\b3\1a\84\85\62\5a\7b\3c\14\39\17\e6\6d\eb\37\c2\00\58\5b\0b\e3\3c\8a\62\e1\f8\35\4b\56\e2\87\60\8b\be\a7\38\91\77\54\a9\5a\24\25\90\9f\a5\42\77\f3\5c\39\df\ff\74\07\76\a1\cd\1f\62\0b\81\81\68\af\05\c1\c0\7f\26\ee\c0\91\a3\6a\7d\29\61\45\27\e5\57\88\dc\0d\97\04\1a\33\a9\44\8a\da\02\10\45\3f\8e\55\a6\76\8c\4d\e3\f1\89\83\c8\d0\f8\9b\50\77\9f\47\df\4c\9c\66\0d\aa\18\b8\5f\4f\c4\01\ce\dc\84\ac\46\9e\69\e1\76\45\6b\61\89\e4\5d\94\bb\11\83\9f\78\d8\0a\d2\f5\7e\5d\43\ea\bc\10\f1\3a\c9\e2\64\fb\53\65\d0\c7\b4\a7\fb\d4\05\53\25\d0\cd\29\88\00\56\25\24\7d\5d\b4\f3\41\9f\e9\b5\f7\ae\64\2c\e3\c9\6d\d5\84\3a\72\12\b8\7a\d9\1b\09\e8\38\da\26\4f\04\ce\03\71\6e\8a\44\7b\5c\81\59\9c\d2\e4\c3\ba\59\a6\e5\28\a7\8f\9a\e4\d5\4e\b9\ca\7f\cb\75\b8\2b\43\3e\b3\15\46\b1\a5\bc\9d\9e\38\15\f1\bd\1b\21\aa\f1\82\00\95\fc\a7\77\47\39\a7\33\43\92\d7\52\40\4b\06\81\8a\a0\bd\f1\6b\99\84\42\5b\e2\3b\c5\5e\12\5c\28\4d\b6\0e\4e\c8\5c\e8\01\8a\c5\e7\e4\9d\42\ee\5d\9c\c4\eb\eb\68\09\27\92\95\9a\11\54\73\c4\12\80\fb\7d\fe\c5\08\60\7f\36\41\e0\10\ba\d6\2b\6c\f1\b4\17\fe\26\34\e3\4b\f8\a8\e3\91\be\4f\2a\fc\da\81\b8\e7\fe\d5\26\50\47\f3\1a\65\32\81\e0\05\b8\4f\32\31\26\00\4a\53\97\c2\c3\0e\2e\a1\26\54\ab\05\8e\56\2f\7d\af\22\84\68\a5\8b\97\f6\a4\fd\a8\cc\75\41\96\86\fd\27\3d\29\86\8d\7f\4c\d4\8e\73\41\f4\1e\e2\dd\58\27\97\ce\9c\94\cf\7a\04\2f\dc\ed" - ) + (memory (data "\13\05\84\42\5d\a2\2c\c6\43\db\55\a9\cd\da\55\e3\73\fc\58\d6\ba\d5\00\fd\83\35\42\88\8b\13\5d\38\4a\47\0d\72\73\a1\1a\ef\c4\45\17\57\d8\c9\46\e0\8d\6c\e1\37\70\c8\83\5b\55\5e\5a\2d\73\1e\56\c8\e1\6d\69\14\78\0a\8a\5a\64\3a\09\c7\a8\87\c5\f0\d3\5d\e6\03\fc\93\be\26\ca\d6\a9\91\60\bd\b0\ed\ae\f7\30\7e\92\3a\6f\a7\59\8e\aa\7d\bf\67\58\2a\54\f8\4e\fe\ed\35\58\a6\51\bf\42\e5\4b\66\27\24\6d\7f\42\2d\28\92\18\ec\08\ae\e7\55\da\b1\a6\65\a5\72\50\47\1b\b8\a9\54\d7\a6\06\5b\0f\42\58\83\8a\17\82\c6\10\43\a0\c0\2e\6d\bc\5a\85\53\72\7f\ad\44\bc\30\3c\55\b2\24\9a\74\3a\9e\e1\d8\0f\70\fc\a9\3a\cd\93\4b\ec\e3\7e\dd\5d\27\cd\f8\a0\9d\1c\11\c0\57\2e\fd\c8\13\32\cc\3a\1a\7d\a3\41\55\ed\c3\82\49\2a\04\1e\ef\73\b9\2e\2e\e3\5f\f4\df\e6\b2\33\0c\39\3f\6f\44\6a\03\c1\42\b9\fa\b1\c8\ed\a5\58\99\7f\ed\b4\72\9e\79\eb\fb\43\82\45\aa\bb\95\d2\ff\28\9e\f6\a1\ad\95\d6\55\95\0d\6f\60\11\c7\78\3e\49\f2\7e\48\f4\a2\71\d0\13\8e\b3\de\99\52\e3\45\74\ea\76\0e\1b\2a\c8\ee\14\01\c4\50\5b\36\3c\ef\ba\72\a2\a6\08\f8\7b\36\9d\f9\ef\0b\c7\56\2d\5c\f0\9d\5d\de\fc\b8\ad\0f\64\0e\97\15\32\26\c2\31\e6\05\1e\ef\cb\17\1b\6d\15\0b\74\5d\d3\2e\f8\6b\86\b4\ba\73\52\53\99\a9\76\20\45\c9\40\80\6b\14\ed\a1\fa\80\46\e6\26\d2\e6\98\c4\57\bf\c4\1c\a4\90\7a\36\94\14\ba\15\89\6e\e6\9c\37\8c\f4\de\12\22\5d\a1\79\50\67\0d\3d\7a\e9\d4\aa\2e\7f\2a\7a\30\3d\ea\5d\12\48\fe\e1\18\cd\a4\57\a2\87\3e\b6\9a\8b\db\da\9d\78\9c\cf\8d\b1\4f\90\b4\34\e0\9d\f6\ca\fe\4c\3b\78\6d\0a\5c\18\9f\61\b9\dd\b4\e0\0f\76\e0\1b\69\0d\5e\58\73\70\5e\0e\2d\a1\7d\ff\20\eb\91\34\92\ac\38\72\2a\1f\8e\71\2e\6a\f1\af\c7\27\70\d9\c4\57\f7\d2\3c\1d\b8\f0\f0\64\cf\dc\ae\be\a3\cc\3e\22\7d\4e\69\21\63\17\ed\03\02\54\9a\0f\50\4e\13\5a\35\a1\22\a4\df\86\c2\74\79\16\b8\69\69\a0\52\5d\11\64\bd\5b\93\fc\69\a0\f4\13\d0\81\51\dd\fa\0c\15\c3\7a\c9\62\7a\a9\1d\c9\e6\5a\b3\5b\97\02\3c\64\22\12\3c\22\90\64\2d\30\54\4c\b4\a1\22\09\57\22\5e\8e\38\2b\02\a8\ae\f6\be\0d\2b\f2\03\ad\fa\10\01\71\77\2a\30\02\95\f6\00\3e\d0\c4\8d\34\19\50\21\0a\bc\50\da\3c\30\d6\3a\31\94\8d\3a\fe\ef\14\57\9d\4b\93\00\96\24\0c\6f\fd\bc\23\76\02\6c\eb\52\72\80\11\7e\80\3a\13\12\38\1d\38\49\95\40\27\8a\44\7b\e8\dc\6d\8c\8c\8e\3c\b5\b3\18\0e\f6\08\1a\84\41\35\ff\8b\b8\93\40\ea\e1\51\1d\89\a5\8d\42\68\29\ea\2f\c1\7a\52\eb\90\5d\4d\d6\80\e3\d7\75\48\ce\ed\d3\01\1c\8d\5b\a5\94\0d\78\cf\f1\06\13\2f\98\02\a4\6d\2e\6c\f2\d5\74\29\89\4c\f9\03\f5\c7\18\ad\7a\f0\68\f8\5c\d6\59\87\6e\d6\3f\06\be\86\20\e3\41\91\22\f3\6e\8b\f0\68\1c\57\a7\fc\b0\7c\9e\99\0b\96\1a\89\5f\e6\0d\7c\08\51\a0\a2\67\9a\47\00\93\6b\f9\28\f0\68\db\62\f1\e0\65\2c\53\33\e0\a7\ca\11\42\30\f6\af\01\c1\65\3d\32\01\6f\ab\2e\be\d3\8b\be\14\c3\ff\ec\fb\f0\f9\c5\0c\05\6f\01\09\6b\e3\34\31\0c\1f\66\a6\42\bc\1a\87\49\16\16\8c\b0\90\0d\34\8c\0a\e1\09\5e\10\a4\6b\56\cc\f0\c9\bb\dc\b8\5c\ce\f6\cc\8d\75\7e\b3\07\88\04\2f\b4\5e\c9\e3\4a\23\73\19\62\6c\9a\03\76\44\86\9c\60\fc\db\72\8f\27\a0\dd\b3\c5\da\ff\f9\ec\6a\b1\7b\d3\cf\50\37\c9\7a\78\0c\e4\3a\b6\f5\e6\f4\98\6e\42\7d\35\73\8b\45\c0\56\97\cd\6d\ce\cf\ad\31\b3\c3\54\fa\ef\d5\c0\f4\6a\5f\54\e7\49\3e\33\0a\30\38\fd\d9\05\ff\a5\3f\57\46\14\b5\91\17\ca\6b\98\23\7a\65\b3\6c\02\b4\cc\79\5d\58\d8\b3\d5\94\ae\f4\6d\75\65\f7\92\bf\7e\47\4c\3c\ee\db\ac\f1\32\5d\fb\6f\41\1c\34\c8\83\4f\c2\58\01\be\05\3e\66\16\a6\04\6d\5d\4f\86\09\27\82\25\12\cd\3a\cd\ce\6b\bc\ca\ac\28\9b\ee\6a\25\86\9e\45\70\c6\d2\bd\3b\7d\42\e5\27\af\c7\1d\f4\81\c8\b3\76\8a\a8\36\a3\ae\2a\e6\18\e1\36\22\ad\f6\25\72\b0\39\8b\01\9a\22\7b\84\c3\2d\5f\72\a4\98\ac\15\70\e7\d4\18\e2\7d\d2\30\7c\33\08\cd\ca\c4\22\85\88\75\81\c6\4a\74\58\8d\e0\e8\ac\c5\ab\75\5a\f4\28\12\f0\18\45\52\f2\97\b2\93\41\6f\8d\7f\db\70\fb\a3\5d\1f\a7\8d\98\20\2b\22\9f\3a\01\b5\8b\1b\d2\cb\14\03\0e\14\14\d2\19\5a\1f\ce\5e\cd\81\79\15\01\ca\de\73\74\8c\56\20\9f\77\2d\25\16\f6\61\51\1d\a4\8e\9b\98\a5\c6\ec\a8\45\57\82\59\78\0d\90\b4\df\51\b0\c3\82\94\cc\b3\53\09\15\6d\96\6c\3a\40\47\b7\4a\7a\05\2f\a1\1e\8c\9d\a0\20\88\fb\52\b7\9f\f3\f3\bb\5f\e7\8a\61\a7\21\b1\ac\fa\09\aa\a4\6c\bc\24\80\ba\2a\e9\65\ff\70\ff\cc\fa\65\87\76\f3\c5\15\ce\cb\e8\42\31\00\0c\91\57\d9\e0\9d\35\54\24\ad\a4\d8\f9\08\67\63\c8\cf\81\dd\90\a2\d7\c4\07\4a\e6\10\6f\67\e7\27\d4\23\59\18\f2\a8\9d\5f\d8\94\30\aa\54\86\4f\87\9d\82\b5\26\ca\a6\96\bf\cf\55\f9\9d\37\01\19\48\43\c5\94\6c\f3\74\97\58\4c\3c\9d\08\e8\04\c2\58\30\76\e1\a0\f8\ea\e9\c5\ae\cf\78\9e\a9\0c\ac\b3\44\42\e0\bc\5d\1b\9c\49\58\4a\1c\19\49\c1\3a\ea\f5\eb\3b\81\a9\4b\70\0c\cc\9e\1a\d3\2f\b7\52\2f\20\3b\eb\64\51\1d\a0\2d\b2\3e\be\13\85\48\92\32\2e\db\5c\a1\e7\8c\45\91\35\01\0a\93\c2\eb\09\ce\f3\d2\22\24\d0\8c\cc\1d\9d\38\c8\4d\e3\82\cc\64\15\06\2d\e7\01\2f\ab\bb\b5\04\4c\92\1c\7a\d6\3f\e8\5f\31\15\0c\dc\e4\31\b4\c4\25\3e\2a\aa\00\9e\c8\e5\21\7a\7f\29\f1\c0\af\1d\5e\e8\63\39\ad\f8\7e\6c\c8\c5\7f\c2\a8\97\27\0a\d9\f4\21\6a\ea\03\09\fb\f7\96\3b\83\79\5f\7c\4b\30\9f\56\35\de\b4\73\d4\95\f0\14\c3\74\2f\0d\a3\1d\4e\8d\31\24\b3\1a\84\85\62\5a\7b\3c\14\39\17\e6\6d\eb\37\c2\00\58\5b\0b\e3\3c\8a\62\e1\f8\35\4b\56\e2\87\60\8b\be\a7\38\91\77\54\a9\5a\24\25\90\9f\a5\42\77\f3\5c\39\df\ff\74\07\76\a1\cd\1f\62\0b\81\81\68\af\05\c1\c0\7f\26\ee\c0\91\a3\6a\7d\29\61\45\27\e5\57\88\dc\0d\97\04\1a\33\a9\44\8a\da\02\10\45\3f\8e\55\a6\76\8c\4d\e3\f1\89\83\c8\d0\f8\9b\50\77\9f\47\df\4c\9c\66\0d\aa\18\b8\5f\4f\c4\01\ce\dc\84\ac\46\9e\69\e1\76\45\6b\61\89\e4\5d\94\bb\11\83\9f\78\d8\0a\d2\f5\7e\5d\43\ea\bc\10\f1\3a\c9\e2\64\fb\53\65\d0\c7\b4\a7\fb\d4\05\53\25\d0\cd\29\88\00\56\25\24\7d\5d\b4\f3\41\9f\e9\b5\f7\ae\64\2c\e3\c9\6d\d5\84\3a\72\12\b8\7a\d9\1b\09\e8\38\da\26\4f\04\ce\03\71\6e\8a\44\7b\5c\81\59\9c\d2\e4\c3\ba\59\a6\e5\28\a7\8f\9a\e4\d5\4e\b9\ca\7f\cb\75\b8\2b\43\3e\b3\15\46\b1\a5\bc\9d\9e\38\15\f1\bd\1b\21\aa\f1\82\00\95\fc\a7\77\47\39\a7\33\43\92\d7\52\40\4b\06\81\8a\a0\bd\f1\6b\99\84\42\5b\e2\3b\c5\5e\12\5c\28\4d\b6\0e\4e\c8\5c\e8\01\8a\c5\e7\e4\9d\42\ee\5d\9c\c4\eb\eb\68\09\27\92\95\9a\11\54\73\c4\12\80\fb\7d\fe\c5\08\60\7f\36\41\e0\10\ba\d6\2b\6c\f1\b4\17\fe\26\34\e3\4b\f8\a8\e3\91\be\4f\2a\fc\da\81\b8\e7\fe\d5\26\50\47\f3\1a\65\32\81\e0\05\b8\4f\32\31\26\00\4a\53\97\c2\c3\0e\2e\a1\26\54\ab\05\8e\56\2f\7d\af\22\84\68\a5\8b\97\f6\a4\fd\a8\cc\75\41\96\86\fd\27\3d\29\86\8d\7f\4c\d4\8e\73\41\f4\1e\e2\dd\58\27\97\ce\9c\94\cf\7a\04\2f\dc\ed" + )) (func $f64.kahan_sum (param $p i32) (param $n i32) (result f64) (local $sum f64) diff --git a/ml-proto/test/float_memory.wast b/ml-proto/test/float_memory.wast index 1b515686dd..6a4f014152 100644 --- a/ml-proto/test/float_memory.wast +++ b/ml-proto/test/float_memory.wast @@ -73,8 +73,7 @@ ;; Test that unaligned load and store do not canonicalize NaNs. (module - (memory 1) - (data 1 "\00\00\a0\7f") + (memory (data "\00\00\00\a0\7f")) (func $f32.load (result f32) (f32.load (i32.const 1))) (export "f32.load" $f32.load) @@ -108,8 +107,7 @@ (assert_return (invoke "f32.load") (f32.const nan:0x200000)) (module - (memory 1) - (data 1 "\00\00\00\00\00\00\f4\7f") + (memory (data "\00\00\00\00\00\00\00\f4\7f")) (func $f64.load (result f64) (f64.load (i32.const 1))) (export "f64.load" $f64.load) diff --git a/ml-proto/test/func_ptrs.wast b/ml-proto/test/func_ptrs.wast index f80e25c2c1..08a2134e7d 100644 --- a/ml-proto/test/func_ptrs.wast +++ b/ml-proto/test/func_ptrs.wast @@ -30,8 +30,12 @@ (assert_return (invoke "three" (i32.const 13)) (i32.const 11)) (invoke "four" (i32.const 83)) -(assert_invalid (module (elem 0)) "no table defined") -(assert_invalid (module (elem 0 0) (func)) "no table defined") +(assert_invalid (module (elem (i32.const 0))) "no table defined") +(assert_invalid (module (elem (i32.const 0) 0) (func)) "no table defined") + +(assert_invalid (module (table 1 anyfunc) (elem (nop))) "type mismatch") +(assert_invalid (module (table 1 anyfunc) (elem (i64.const 0))) "type mismatch") +(assert_invalid (module (table 1 anyfunc) (elem (i32.ctz (i32.const 0)))) "constant expression required") (assert_invalid (module (func (type 42))) "unknown function type 42") (assert_invalid (module (import "spectest" "print" (type 43))) "unknown function type 43") diff --git a/ml-proto/test/memory.wast b/ml-proto/test/memory.wast index 0da51375b0..1acd50994d 100644 --- a/ml-proto/test/memory.wast +++ b/ml-proto/test/memory.wast @@ -3,11 +3,13 @@ (module (memory 0 1)) (module (memory 1 256)) (module (memory 0 65535)) -(module (memory 0 0) (data 0)) -(module (memory 0 0) (data 0 "")) -(module (memory 1 1) (data 0 "a")) -(module (memory 1 2) (data 0 "a") (data 65535 "b")) -(module (memory 1 2) (data 0 "a") (data 1 "b") (data 2 "c")) +(module (memory 0 0) (data (i32.const 0))) +(module (memory 0 0) (data (i32.const 0) "")) +(module (memory 1 1) (data (i32.const 0) "a")) +(module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 65535) "b")) +(module (memory 1 2) + (data (i32.const 0) "a") (data (i32.const 1) "b") (data (i32.const 2) "c") +) (module (memory (data)) (func "memsize" (result i32) (current_memory))) (assert_return (invoke "memsize") (i32.const 0)) @@ -17,40 +19,56 @@ (assert_return (invoke "memsize") (i32.const 1)) (assert_invalid - (module (data 0)) + (module (data (i32.const 0))) "no memory defined" ) (assert_invalid - (module (data 0 "")) + (module (data (i32.const 0) "")) "no memory defined" ) (assert_invalid - (module (data 0 "x")) + (module (data (i32.const 0) "x")) "no memory defined" ) +(assert_invalid + (module (memory 1) (data (nop))) + "type mismatch" +) +(assert_invalid + (module (memory 1) (data (i64.const 0))) + "type mismatch" +) +(assert_invalid + (module (memory 1) (data (i32.ctz (i32.const 0)))) + "constant expression required" +) + (assert_invalid (module (memory 1 0)) "memory size minimum must not be greater than maximum" ) (assert_invalid - (module (memory 0 0) (data 0 "a")) + (module (memory 0 0) (data (i32.const 0) "a")) "data segment does not fit memory" ) (assert_invalid - (module (memory 1 2) (data 0 "a") (data 98304 "b")) + (module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 98304) "b")) "data segment does not fit memory" ) (assert_invalid - (module (memory 1 2) (data 0 "abc") (data 0 "def")) + (module (memory 1 2) (data (i32.const 0) "abc") (data (i32.const 0) "def")) "data segment not disjoint and ordered" ) (assert_invalid - (module (memory 1 2) (data 3 "ab") (data 0 "de")) + (module (memory 1 2) (data (i32.const 3) "ab") (data (i32.const 0) "de")) "data segment not disjoint and ordered" ) (assert_invalid - (module (memory 1 2) (data 0 "a") (data 2 "b") (data 1 "c")) + (module + (memory 1 2) + (data (i32.const 0) "a") (data (i32.const 2) "b") (data (i32.const 1) "c") + ) "data segment not disjoint and ordered" ) (assert_invalid @@ -95,7 +113,7 @@ (module (memory 1) - (data 0 "ABC\a7D") (data 20 "WASM") + (data (i32.const 0) "ABC\a7D") (data (i32.const 20) "WASM") ;; Data section (func $data (result i32)