diff --git a/ml-proto/README.md b/ml-proto/README.md index 8afd5acb27..b7141ff656 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,14 +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 * ) -memory: ( memory ? * ) -segment: ( segment + ) +table: ( table ? ) + ( table ( elem * ) ) ;; = (table ) (elem (i32.const 0) *) +elem: ( elem * ) +memory: ( memory ? ) + ( 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). @@ -165,6 +169,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 3201614025..b358c8870d 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} = @@ -254,16 +260,29 @@ let start x = Node ("start " ^ var x, []) let table xs = tab "table" (atom var) xs -(* Memory *) +(* Tables & memories *) -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 limits int lim = + let {min; max} = lim.it in + String.concat " " (int min :: opt int max) + +let table tab = + let {tlimits = lim; etype} = tab.it in + Node ("table " ^ limits int32 lim, [atom elem_type etype]) let memory mem = - let {min; max; segments} = mem.it in - Node ("memory " ^ int64 min ^ " " ^ int64 max, list segment segments) + let {mlimits = lim} = mem.it in + Node ("memory " ^ limits int64 lim, []) + +let segment head dat seg = + let {offset; init} = seg.it in + Node (head, expr offset :: dat init) + +let elems seg = + segment "elem" (list (atom var)) seg + +let data seg = + segment "data" break_string seg (* Modules *) @@ -279,8 +298,8 @@ let import i im = ) let global g = - let {gtype; init} = g.it in - Node ("global", [atom value_type gtype; expr init]) + let {gtype; value} = g.it in + Node ("global", [atom value_type gtype; expr value]) let export ex = let {name; kind} = ex.it in @@ -294,11 +313,13 @@ let module_ m = Node ("module", 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 global m.it.globals @ + listi func m.it.funcs @ list export m.it.exports @ - opt start m.it.start + opt start m.it.start @ + list elems m.it.elems @ + list data m.it.data ) diff --git a/ml-proto/host/encode.ml b/ml-proto/host/encode.ml index 754243d9e2..a4412abc80 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 @@ -295,6 +298,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 = @@ -325,20 +330,29 @@ let encode m = section "function" (vec func) fs (fs <> []) (* Table section *) - let table_section tab = - section "table" (vec var) tab (tab <> []) + let limits vu lim = + let {min; max} = lim.it in + bool (max <> None); vu min; opt vu max + + let table tab = + 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 = - let {min; max; _} = mem.it in - vu64 min; vu64 max; bool true (*TODO: pending change*) + let {mlimits} = mem.it in + limits vu64 mlimits let memory_section memo = section "memory" (opt memory) memo (memo <> None) (* Global section *) let global g = - let {gtype = t; init = e} = g.it in + let {gtype = t; value = e} = g.it in value_type t; expr e; op 0x0f let global_section gs = @@ -381,14 +395,23 @@ let encode m = let code_section fs = section "code" (vec code) fs (fs <> []) + (* Element section *) + let segment dat seg = + let {offset; init} = seg.it in + const offset; dat init + + let table_segment seg = + segment (vec var) seg + + let elem_section elems = + section "element" (vec table_segment) elems (elems <> []) + (* Data section *) - let segment seg = - let {Memory.addr; data} = seg.it in - vu64 addr; string data + let memory_segment seg = + segment string seg - let data_section segs = - section "data" (opt (vec segment)) - segs (segs <> None && segs <> Some []) + let data_section data = + section "data" (vec memory_segment) data (data <> []) (* Module *) @@ -404,6 +427,7 @@ 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 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 b10cc54d53..131a2bceb2 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 } @@ -364,11 +365,12 @@ rule token = parse | "local" { LOCAL } | "global" { GLOBAL } | "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 f423c59cc0..1730a67716 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -127,7 +127,7 @@ 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 GET_GLOBAL SET_GLOBAL @@ -135,7 +135,7 @@ let implicit_decl c t at = %token CONST UNARY BINARY COMPARE CONVERT %token UNREACHABLE CURRENT_MEMORY GROW_MEMORY %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%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 @@ -170,7 +170,7 @@ let implicit_decl c t at = /* Auxiliaries */ text_list : - | TEXT { $1 } + | /* empty */ { "" } | text_list TEXT { $1 ^ $2 } ; @@ -180,6 +180,11 @@ value_type_list : | /* empty */ { [] } | VALUE_TYPE value_type_list { $1 :: $2 } ; + +elem_type : + | ANYFUNC { AnyFuncType } +; + func_type : | /* empty */ { {ins = []; out = None} } @@ -351,40 +356,54 @@ export_opt : ; -/* Modules */ +/* Tables & Memories */ -start : - | LPAR START var RPAR - { fun c -> $3 c func } +elem : + | LPAR ELEM expr var_list RPAR + { let at = at () in + fun c -> {offset = $3 c; init = $4 c func} @@ at } ; -global : - | LPAR GLOBAL VALUE_TYPE expr RPAR - { let at = at () in - fun c -> anon_global c; fun () -> {gtype = $3; init = $4 c} @@ at } - | LPAR GLOBAL bind_var VALUE_TYPE expr RPAR /* Sugar */ +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 : + | 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 -> bind_global c $3; fun () -> {gtype = $4; init = $5 c} @@ 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 = I32_const (0l @@ at) @@ at; init} @@ at] } ; -segment : - | LPAR SEGMENT NAT text_list RPAR - { {Memory.addr = Int64.of_string $3; Memory.data = $4} @@ at () } -; -segment_list : - | /* empty */ { [] } - | segment segment_list { $1 :: $2 } +data : + | LPAR DATA expr text_list RPAR + { fun c -> {offset = $3 c; init = $4} @@ 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 () } +; 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 memory_limits RPAR + { fun c -> {mlimits = $3} @@ at (), [] } + | LPAR MEMORY LPAR DATA text_list RPAR RPAR /* Sugar */ + { 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] } ; + +/* Modules */ + type_def : | LPAR TYPE LPAR FUNC func_type RPAR RPAR { fun c -> anon_type c $5 } @@ -392,11 +411,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 @@ -423,41 +437,75 @@ export : { let at = at () in fun c -> {name = $3; kind = `Memory} @@ at } ; +global : + | LPAR GLOBAL VALUE_TYPE expr RPAR + { let at = at () in + fun c -> anon_global c; fun () -> {gtype = $3; value = $4 c} @@ at } + | LPAR GLOBAL bind_var VALUE_TYPE expr RPAR /* Sugar */ + { let at = at () in + fun c -> bind_global c $3; fun () -> {gtype = $4; value = $5 c} @@ at } +; + +start : + | LPAR START var RPAR + { fun c -> $3 c func } +; + module_fields : | /* empty */ { fun c -> - {memory = None; types = c.types.tlist; globals = []; funcs = []; - start = None; imports = []; exports = []; table = []} } - | 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} } + { + types = c.types.tlist; + globals = []; + table = None; + memory = None; + funcs = []; + elems = []; + data = []; + start = None; + imports = []; + exports = [] + } } + | type_def module_fields + { fun c -> $1 c; $2 c } | global module_fields { fun c -> let g = $1 c in let m = $2 c in {m with globals = g () :: m.globals} } + | table module_fields + { 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; elems = elems @ m.elems} } + | memory module_fields + { 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} } + | 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} } + | 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 data = $1 c :: 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} } | import module_fields { fun c -> let i = $1 c in let m = $2 c in {m with imports = i :: m.imports} } | export 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 } - | memory module_fields - { fun c -> let m = $2 c in - match m.memory with - | Some _ -> error $1.at "multiple memory sections" - | None -> {m with memory = Some $1} } - | start module_fields - { fun c -> let m = $2 c in - {m with start = Some ($1 c)} } ; 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/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 8207c9d3b2..a66bd65230 100644 --- a/ml-proto/spec/ast.ml +++ b/ml-proto/spec/ast.ml @@ -202,7 +202,7 @@ type global = global' Source.phrase and global' = { gtype : Types.value_type; - init : expr; + value : expr; } type func = func' Source.phrase @@ -216,15 +216,24 @@ and func' = (* Modules *) +type 'data segment = 'data segment' Source.phrase +and 'data segment' = +{ + offset : expr; + init : 'data; +} + type module_ = module' Source.phrase and module' = { - memory : Kernel.memory option; types : Types.func_type list; globals : global list; + table : Kernel.table option; + memory : Kernel.memory option; funcs : func list; start : var option; + elems : var list segment list; + data : string segment list; 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 855a9bc52d..187888c086 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; @@ -25,7 +26,8 @@ type context = globals : value_type list; return : expr_type; labels : expr_type_future list; - has_memory : bool + table : Table.size option; + memory : Memory.size option; } let lookup category list x = @@ -39,6 +41,14 @@ let local c x = lookup "local" c.locals x let global c x = lookup "global" c.globals 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 *) @@ -111,7 +121,7 @@ let type_hostop = function | GrowMemory -> ({ins = [Int32Type]; out = Some Int32Type}, true) -(* Type Analysis *) +(* Expressions *) (* * check_expr : context -> expr_type_future -> expr -> unit @@ -182,6 +192,7 @@ let rec check_expr c et e = | CallIndirect (x, e1, es) -> let {ins; out} = type_ c.types x in + ignore (table c e.at); check_expr c (some Int32Type) e1; check_exprs c ins es e.at; check_type out et e.at @@ -250,7 +261,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 @@ -269,21 +280,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_memory c at = - require c.has_memory at "memory operators require a memory section" - and check_memop memop at = require (memop.offset >= 0L) at "negative offset"; require (memop.offset <= 0xffffffffL) at "offset too large"; @@ -292,11 +300,13 @@ 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_init_expr e = +let check_const c et e = match e.it with - | Const _ | GetGlobal _ -> () - | _ -> error e.at "not an initialization expression" + | Const _ | GetGlobal _ -> check_expr c (some et) e + | _ -> error e.at "constant expression required" + +(* Functions *) (* * check_func : context -> func -> unit @@ -318,24 +328,66 @@ 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) -let check_global c g = - let {gtype; init} = g.it in - check_init_expr init; - check_expr c (some gtype) init +(* Tables & Memories *) + +let check_table_limits (lim : Table.size limits) = + 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 (c : context) (tab : table) = + let {tlimits = lim; etype = t} = tab.it in + check_table_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)"; + 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 (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 + 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 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 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_ -module NameSet = Set.Make(String) -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 +(* Modules *) + +let check_global c g = + let {gtype; value} = g.it in + check_const c gtype value let check_start c start = Lib.Option.app (fun x -> @@ -346,37 +398,42 @@ let check_start c start = "start function must not return anything"; ) start -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 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_export c set ex = + let {name; kind} = ex.it in + (match kind with + | `Func x -> ignore (func c x) + | `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 {memory; types; globals; 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; - globals = []; - locals = []; - return = None; - labels = []; - has_memory = memory <> None} in + let + {types; table; memory; globals; funcs; start; elems; data; + imports; exports} = m.it 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; + globals = []; + locals = []; + return = None; + labels = []; + 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_global c) globals; let c' = {c with globals = List.map (fun g -> g.it.gtype) globals} in List.iter (check_func c') funcs; - List.iter (check_elem c') table; + Lib.Option.app (check_table c') table; + Lib.Option.app (check_memory c') memory; 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 8a9c408090..59645468d6 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 = @@ -436,6 +441,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 *) @@ -454,6 +466,7 @@ let id s = | "export" -> `ExportSection | "start" -> `StartSection | "code" -> `CodeSection + | "element" -> `ElemSection | "data" -> `DataSection | _ -> `UnknownSection @@ -495,17 +508,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 + let lim = at (limits vu32) s in + {etype = t; tlimits = lim} + let table_section s = - section `TableSection (vec (at var)) [] s + section `TableSection (opt (at table) true) None s (* Memory section *) let memory s = - let min = vu64 s in - let max = vu64 s in - let _ = bool s in (*TODO: pending change*) - {min; max; segments = []} + let lim = at (limits vu64) s in + {mlimits = lim} let memory_section s = section `MemorySection (opt (at memory) true) None s @@ -519,7 +541,7 @@ let global s = let es = expr_block s in require (List.length es = 1) s pos "single expression expected"; expect 0x0f s "`end` opcode expected"; - {gtype = t; init = List.hd es} + {gtype = t; value = List.hd es} let global_section s = section `GlobalSection (vec (at global)) [] s @@ -559,15 +581,27 @@ let code_section s = section `CodeSection (vec (at code)) [] s +(* Element section *) + +let segment dat s = + let offset = const s in + let init = dat s in + {offset; init} + +let table_segment s = + segment (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 string s let data_section s = - section `DataSection (vec (at segment)) [] s + section `DataSection (vec (at memory_segment)) [] s (* Unknown section *) @@ -594,7 +628,7 @@ let module_ s = iterate unknown_section s; 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 globals = global_section s in iterate unknown_section s; @@ -604,23 +638,19 @@ 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 elems = elem_section s in + iterate unknown_section s; + let data = 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 memory = - match memory_limits with - | None -> None - | Some memory -> Some Source.({memory.it with segments} @@ memory.at) - in {memory; types; globals; funcs; imports; exports; table; start} + func_types func_bodies + in {types; table; memory; globals; 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 46df8ee65a..6f5e514be3 100644 --- a/ml-proto/spec/desugar.ml +++ b/ml-proto/spec/desugar.ml @@ -301,17 +301,23 @@ and block = function let rec global g = global' g.it @@ g.at and global' = function - | {Ast.gtype = t; init = e} -> {gtype = t; init = expr e} + | {Ast.gtype = t; value = e} -> {gtype = t; value = expr e} 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; globals = gs; memory; types; imports; exports; table} -> + | {Ast.funcs = fs; start; globals = gs; memory; types; imports; exports; table; elems; data} -> let globals = List.map global gs in + let elems = List.map segment elems in let funcs = List.map func fs in - {funcs; start; globals; memory; types; imports; exports; table} + let data = List.map segment data in + {funcs; start; globals; 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 e3a3e53c8d..244aab8ba1 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -17,8 +17,9 @@ type instance = module_ : module_; imports : import list; exports : export_map; + table : Table.t option; + memory : Memory.t option; globals : value ref list; - memory : Memory.t option } @@ -80,13 +81,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 @@ -107,6 +111,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 @@ -188,7 +197,7 @@ let rec eval_expr (c : config) (e : expr) : value option = | CallIndirect (x, 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 type_ c x <> type_ c f.it.ftype then Trap.error e1.at "indirect call signature mismatch"; eval_func c.instance f vs @@ -312,8 +321,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" @@ -321,15 +332,38 @@ and eval_hostop c hostop vs at = (* Modules *) -let init_global inst r g = - let c = {instance = inst; locals = []; labels = []} in - r := some (eval_expr c g.it.init) g.it.init.at - -let init_memory m = - let mem = Memory.create m.it.min in - Memory.init mem (List.map it m.it.segments); +let const m e = + (* TODO: allow referring to earlier glboals *) + let inst = + { module_ = m; imports = []; exports = ExportMap.empty; + table = None; memory = None; globals = [] } + 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 (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 (Int64.of_int32 (offset m seg)) seg.it.init) + data; mem +let init_global inst ref global = + let {value = e; _} = global.it in + let c = {instance = inst; locals = []; labels = []} in + ref := some (eval_expr c e) e.at + let add_export funcs ex = let {name; kind} = ex.it in match kind with @@ -338,20 +372,22 @@ let add_export funcs ex = let init m imports = assert (List.length imports = List.length m.it.Kernel.imports); - let {memory; funcs; globals; exports; start; _} = m.it in + let {table; memory; globals; funcs; exports; elems; data; start; _} = m.it in let inst = - {module_ = m; - imports; - exports = List.fold_right (add_export funcs) exports ExportMap.empty; - globals = List.map (fun g -> ref (default_value g.it.gtype)) globals; - memory = Lib.Option.map init_memory memory} + { module_ = m; + imports; + exports = List.fold_right (add_export funcs) exports ExportMap.empty; + table = Lib.Option.map (init_table m elems) table; + memory = Lib.Option.map (init_memory m data) memory; + globals = List.map (fun g -> ref (default_value g.it.gtype)) globals; + } in List.iter2 (init_global inst) inst.globals globals; Lib.Option.app (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 76a3fa6aa9..d89b12debf 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 = @@ -107,7 +103,14 @@ and expr' = | Host of hostop * expr list (* host interaction *) -(* Functions *) +(* Globals and Functions *) + +type global = global' Source.phrase +and global' = +{ + gtype : Types.value_type; + value : expr; +} type func = func' Source.phrase and func' = @@ -118,23 +121,40 @@ and func' = } -(* Modules *) +(* Tables & Memories *) -type global = global' Source.phrase -and global' = +type 'size limits = 'size limits' Source.phrase +and 'size limits' = { - gtype : Types.value_type; - init : expr; + min : 'size; + max : 'size option; +} + +type table = table' Source.phrase +and table' = +{ + tlimits : Table.size limits; + etype : elem_type; } type memory = memory' Source.phrase and memory' = { - min : Memory.size; - max : Memory.size; - segments : segment list; + mlimits : Memory.size limits; +} + +type 'data segment = 'data segment' Source.phrase +and 'data segment' = +{ + offset : expr; + init : 'data; } -and segment = Memory.segment Source.phrase + +type table_segment = var list segment +type memory_segment = string segment + + +(* Modules *) type export = export' Source.phrase and export' = @@ -154,12 +174,14 @@ and import' = type module_ = module_' Source.phrase and module_' = { - memory : memory option; types : Types.func_type list; globals : global list; + table : table option; + memory : memory option; funcs : func list; start : var option; + elems : table_segment list; + data : memory_segment list; imports : import list; exports : export list; - table : var list; } diff --git a/ml-proto/spec/memory.ml b/ml-proto/spec/memory.ml index 4f6e75f8d5..a3266e6ba6 100644 --- a/ml-proto/spec/memory.ml +++ b/ml-proto/spec/memory.ml @@ -2,22 +2,24 @@ 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 = 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 *) @@ -37,13 +39,16 @@ 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 (* ========================================================================== *) +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 +56,51 @@ let create' n = Array1.fill mem 0; mem -let create n = - ref (create' n) - -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] - done - -let init mem segs = - try List.iter (init_seg mem) segs with Invalid_argument _ -> raise Bounds +let create n max = + assert (within_limits n max); + {content = create' n; max} 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 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 - 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 @@ -150,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 2e60e8eb66..e37a47f0a6 100644 --- a/ml-proto/spec/memory.mli +++ b/ml-proto/spec/memory.mli @@ -1,22 +1,24 @@ 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 exception SizeOverflow +exception SizeLimit val page_size : size -val create : size -> memory -val init : memory -> segment list -> unit +val create : size -> size option -> memory val size : memory -> size val grow : memory -> size -> unit @@ -25,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..9d9a046b28 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} @@ -16,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/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 4eba39a70e..9007af064e 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 (i32.const 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 ce34922420..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 $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 aab0a61c70..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 $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 7c25ee8af0..70b160402b 100644 --- a/ml-proto/test/call_indirect.wast +++ b/ml-proto/test/call_indirect.wast @@ -40,14 +40,16 @@ (func $over-f32-duplicate (type $over-f32-duplicate) (get_local 0)) (func $over-f64-duplicate (type $over-f64-duplicate) (get_local 0)) - (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 - $over-i32-duplicate $over-i64-duplicate - $over-f32-duplicate $over-f64-duplicate + (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 + $fac $fib $even $odd + $runaway $mutual-runaway1 $mutual-runaway2 + $over-i32-duplicate $over-i64-duplicate + $over-f32-duplicate $over-f64-duplicate + ) ) ;; Typing @@ -181,9 +183,9 @@ (assert_return (invoke "dispatch" (i32.const 20) (i64.const 2)) (i64.const 2)) (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 23) (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 23) (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 "dispatch-structural" (i32.const 5)) (i64.const 9)) (assert_return (invoke "dispatch-structural" (i32.const 5)) (i64.const 9)) @@ -221,6 +223,15 @@ (assert_invalid (module (type (func)) + (func $no-table (call_indirect 0 (i32.const 0))) + ) + "no table" +) + +(assert_invalid + (module + (type (func)) + (table 0 anyfunc) (func $type-void-vs-num (i32.eqz (call_indirect 0 (i32.const 0)))) ) "type mismatch" @@ -228,6 +239,7 @@ (assert_invalid (module (type (func (result i64))) + (table 0 anyfunc) (func $type-num-vs-num (i32.eqz (call_indirect 0 (i32.const 0)))) ) "type mismatch" @@ -236,6 +248,7 @@ (assert_invalid (module (type (func (param i32))) + (table 0 anyfunc) (func $arity-0-vs-1 (call_indirect 0 (i32.const 0))) ) "arity mismatch" @@ -243,6 +256,7 @@ (assert_invalid (module (type (func (param f64 i32))) + (table 0 anyfunc) (func $arity-0-vs-2 (call_indirect 0 (i32.const 0))) ) "arity mismatch" @@ -250,6 +264,7 @@ (assert_invalid (module (type (func)) + (table 0 anyfunc) (func $arity-1-vs-0 (call_indirect 0 (i32.const 0) (i32.const 1))) ) "arity mismatch" @@ -257,6 +272,7 @@ (assert_invalid (module (type (func)) + (table 0 anyfunc) (func $arity-2-vs-0 (call_indirect 0 (i32.const 0) (f64.const 2) (i32.const 1)) ) @@ -267,6 +283,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0 anyfunc) (func $arity-nop-first (call_indirect 0 (i32.const 0) (nop) (i32.const 1) (i32.const 2)) ) @@ -276,6 +293,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0 anyfunc) (func $arity-nop-mid (call_indirect 0 (i32.const 0) (i32.const 1) (nop) (i32.const 2)) ) @@ -285,6 +303,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0 anyfunc) (func $arity-nop-last (call_indirect 0 (i32.const 0) (i32.const 1) (i32.const 2) (nop)) ) @@ -295,6 +314,7 @@ (assert_invalid (module (type (func (param i32))) + (table 0 anyfunc) (func $type-func-void-vs-i32 (call_indirect 0 (nop) (i32.const 1))) ) "type mismatch" @@ -302,6 +322,7 @@ (assert_invalid (module (type (func (param i32))) + (table 0 anyfunc) (func $type-func-num-vs-i32 (call_indirect 0 (i64.const 1) (i32.const 0))) ) "type mismatch" @@ -310,6 +331,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0 anyfunc) (func $type-first-void-vs-num (call_indirect 0 (i32.const 0) (nop) (i32.const 1)) ) @@ -319,6 +341,7 @@ (assert_invalid (module (type (func (param i32 i32))) + (table 0 anyfunc) (func $type-second-void-vs-num (call_indirect 0 (i32.const 0) (i32.const 1) (nop)) ) @@ -328,6 +351,7 @@ (assert_invalid (module (type (func (param i32 f64))) + (table 0 anyfunc) (func $type-first-num-vs-num (call_indirect 0 (i32.const 0) (f64.const 1) (i32.const 1)) ) @@ -337,6 +361,7 @@ (assert_invalid (module (type (func (param f64 i32))) + (table 0 anyfunc) (func $type-second-num-vs-num (call_indirect 0 (i32.const 0) (i32.const 1) (f64.const 1)) ) @@ -348,10 +373,16 @@ ;; Unbound type (assert_invalid - (module (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 (func $large-type (call_indirect 10001232130000 (i32.const 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..154dd71e15 100644 --- a/ml-proto/test/float_exprs.wast +++ b/ml-proto/test/float_exprs.wast @@ -1423,9 +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 (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" + "\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) (local $sum f32) @@ -1458,9 +1500,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 (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 b4ea4dcb8e..6a4f014152 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,7 @@ ;; Test that unaligned load and store do not canonicalize NaNs. (module - (memory 1 1 (segment 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) @@ -107,7 +107,7 @@ (assert_return (invoke "f32.load") (f32.const nan:0x200000)) (module - (memory 1 1 (segment 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) @@ -143,7 +143,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 +177,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 c63d78e24b..841c74ecbf 100644 --- a/ml-proto/test/func_ptrs.wast +++ b/ml-proto/test/func_ptrs.wast @@ -1,58 +1,69 @@ (module - (type (func)) ;; 0: void -> void - (type $S (func)) ;; 1: void -> void - (type (func (param))) ;; 2: void -> void - (type (func (result i32))) ;; 3: void -> i32 - (type (func (param) (result i32))) ;; 4: void -> i32 - (type $T (func (param i32) (result i32))) ;; 5: i32 -> i32 - (type $U (func (param i32))) ;; 6: i32 -> void - - (func (type 0)) - (func (type $S)) - - (func $one (type 4) (i32.const 13)) - (export "one" $one) - - (func $two (type $T) (i32.add (get_local 0) (i32.const 1))) - (export "two" $two) - - ;; Both signature and parameters are allowed (and required to match) - ;; since this allows the naming of parameters. - (func $three (type $T) (param $a i32) (result i32) (i32.sub (get_local 0) (i32.const 2))) - (export "three" $three) - - (import $print "spectest" "print" (type 6)) - (func $four (type $U) (call_import $print (get_local 0))) - (export "four" $four) + (type (func)) ;; 0: void -> void + (type $S (func)) ;; 1: void -> void + (type (func (param))) ;; 2: void -> void + (type (func (result i32))) ;; 3: void -> i32 + (type (func (param) (result i32))) ;; 4: void -> i32 + (type $T (func (param i32) (result i32))) ;; 5: i32 -> i32 + (type $U (func (param i32))) ;; 6: i32 -> void + + (func (type 0)) + (func (type $S)) + + (func "one" (type 4) (i32.const 13)) + (func "two" (type $T) (i32.add (get_local 0) (i32.const 1))) + + ;; Both signature and parameters are allowed (and required to match) + ;; since this allows the naming of parameters. + (func "three" (type $T) (param $a i32) (result i32) + (i32.sub (get_local 0) (i32.const 2)) + ) + + (import $print "spectest" "print" (type 6)) + (func "four" (type $U) (call_import $print (get_local 0))) ) (assert_return (invoke "one") (i32.const 13)) (assert_return (invoke "two" (i32.const 13)) (i32.const 14)) (assert_return (invoke "three" (i32.const 13)) (i32.const 11)) (invoke "four" (i32.const 83)) +(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 (i64.const 0))) + "type mismatch" +) +(assert_invalid + (module (table 1 anyfunc) (elem (i32.ctz (i32.const 0)))) + "constant expression required" +) +(assert_invalid + (module (table 1 anyfunc) (elem (nop))) + "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") (module - (type $T (func (param) (result i32))) - (type $U (func (param) (result i32))) - (table $t1 $t2 $t3 $u1 $u2 $t1 $t3) - - (func $t1 (type $T) (i32.const 1)) - (func $t2 (type $T) (i32.const 2)) - (func $t3 (type $T) (i32.const 3)) - (func $u1 (type $U) (i32.const 4)) - (func $u2 (type $U) (i32.const 5)) - - (func $callt (param $i i32) (result i32) - (call_indirect $T (get_local $i)) - ) - (export "callt" $callt) - - (func $callu (param $i i32) (result i32) - (call_indirect $U (get_local $i)) - ) - (export "callu" $callu) + (type $T (func (param) (result i32))) + (type $U (func (param) (result i32))) + (table anyfunc (elem $t1 $t2 $t3 $u1 $u2 $t1 $t3)) + + (func $t1 (type $T) (i32.const 1)) + (func $t2 (type $T) (i32.const 2)) + (func $t3 (type $T) (i32.const 3)) + (func $u1 (type $U) (i32.const 4)) + (func $u2 (type $U) (i32.const 5)) + + (func "callt" (param $i i32) (result i32) + (call_indirect $T (get_local $i)) + ) + + (func "callu" (param $i i32) (result i32) + (call_indirect $U (get_local $i)) + ) ) (assert_return (invoke "callt" (i32.const 0)) (i32.const 1)) @@ -62,9 +73,9 @@ (assert_return (invoke "callt" (i32.const 4)) (i32.const 5)) (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") +(assert_trap (invoke "callt" (i32.const 100)) "undefined element") +(assert_trap (invoke "callt" (i32.const -1)) "undefined element") (assert_return (invoke "callu" (i32.const 0)) (i32.const 1)) (assert_return (invoke "callu" (i32.const 1)) (i32.const 2)) @@ -73,21 +84,22 @@ (assert_return (invoke "callu" (i32.const 4)) (i32.const 5)) (assert_return (invoke "callu" (i32.const 5)) (i32.const 1)) (assert_return (invoke "callu" (i32.const 6)) (i32.const 3)) -(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") +(assert_trap (invoke "callu" (i32.const 100)) "undefined element") +(assert_trap (invoke "callu" (i32.const -1)) "undefined element") (module - (type $T (func (result i32))) - (table 0 1) + (type $T (func (result i32))) + (table anyfunc (elem 0 1)) - (import $print_i32 "spectest" "print" (param i32)) + (import $print_i32 "spectest" "print" (param i32)) - (func $t1 (type $T) (i32.const 1)) - (func $t2 (type $T) (i32.const 2)) + (func $t1 (type $T) (i32.const 1)) + (func $t2 (type $T) (i32.const 2)) - (func $callt (param $i i32) (result i32) - (call_indirect $T (get_local $i))) - (export "callt" $callt) + (func "callt" (param $i i32) (result i32) + (call_indirect $T (get_local $i)) + ) ) (assert_return (invoke "callt" (i32.const 0)) (i32.const 1)) diff --git a/ml-proto/test/globals.wast b/ml-proto/test/globals.wast index 4fc36a647e..1459233b37 100644 --- a/ml-proto/test/globals.wast +++ b/ml-proto/test/globals.wast @@ -34,12 +34,12 @@ (assert_invalid (module (global f32 (f32.neg (f32.const 0)))) - "not an initialization expression" + "constant expression required" ) (assert_invalid (module (global f32 (get_local 0))) - "not an initialization expression" + "constant expression required" ) (assert_invalid @@ -50,4 +50,4 @@ (assert_invalid (module (global i32 (get_global 0))) "unknown global" -) \ No newline at end of file +) diff --git a/ml-proto/test/left-to-right.wast b/ml-proto/test/left-to-right.wast index 8c8ea104be..707f690448 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 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)) (func $i32_t1 (type $i32_T) (i32.const -2)) diff --git a/ml-proto/test/memory.wast b/ml-proto/test/memory.wast index f98118839d..621740208b 100644 --- a/ml-proto/test/memory.wast +++ b/ml-proto/test/memory.wast @@ -3,46 +3,85 @@ (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 (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)) +(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 (i32.const 0))) + "no memory defined" +) +(assert_invalid + (module (data (i32.const 0) "")) + "no memory defined" +) +(assert_invalid + (module (data (i32.const 0) "x")) + "no memory defined" +) + +(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) (data (nop))) + "constant expression required" +) (assert_invalid (module (memory 1 0)) - "minimum memory pages must be less than or equal to the maximum" + "memory size minimum must not be greater than maximum" ) (assert_invalid - (module (memory 0 0 (segment 0 "a"))) + (module (memory 0 0) (data (i32.const 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 (i32.const 0) "a") (data (i32.const 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 (i32.const 0) "abc") (data (i32.const 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 (i32.const 3) "ab") (data (i32.const 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 (i32.const 0) "a") (data (i32.const 2) "b") (data (i32.const 1) "c") + ) "data segment not disjoint and ordered" ) (assert_invalid (module (memory 0 65536)) - "linear 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)) - "linear 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)) - "linear memory pages must be less or equal to 65535 (4GiB)" + "memory size must be less than 65536 pages (4GiB)" ) ;; Test alignment annotation rules @@ -73,7 +112,8 @@ ) (module - (memory 1 (segment 0 "ABC\a7D") (segment 20 "WASM")) + (memory 1) + (data (i32.const 0) "ABC\a7D") (data (i32.const 20) "WASM") ;; Data section (func $data (result i32) 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)) diff --git a/ml-proto/test/return.wast b/ml-proto/test/return.wast index 2124b831d9..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 $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 3ec8f9d870..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 $dummy3) + (table anyfunc (elem $dummy3)) (func "as-call_indirect-func" (call_indirect $sig (unreachable) (i32.const 1) (i32.const 2) (i32.const 3)) )