From fcb77148cb9d6c4128e50cce9a550aa7d24b07cc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 24 Apr 2024 15:04:20 -0700 Subject: [PATCH 1/4] Update interpreter and test suite for table64 --- interpreter/binary/decode.ml | 5 +- interpreter/binary/encode.ml | 2 +- interpreter/exec/eval.ml | 108 +++++++++++++++++++-------------- interpreter/host/spectest.ml | 6 +- interpreter/runtime/elem.ml | 6 +- interpreter/runtime/memory.ml | 5 -- interpreter/runtime/memory.mli | 1 - interpreter/runtime/table.ml | 57 ++++++++++------- interpreter/runtime/table.mli | 6 +- interpreter/syntax/types.ml | 12 ++-- interpreter/text/arrange.ml | 6 +- interpreter/text/parser.mly | 37 ++++++----- interpreter/util/lib.ml | 59 ++++++++++++++---- interpreter/util/lib.mli | 22 +++++-- interpreter/valid/valid.ml | 38 ++++++------ test/core/call_indirect.wast | 10 +++ test/core/table.wast | 12 ++-- test/core/table64.wast | 26 ++++++++ test/core/table_get.wast | 5 ++ test/core/table_init.wast | 41 ++++++++++++- test/core/table_set.wast | 10 +++ 21 files changed, 327 insertions(+), 147 deletions(-) create mode 100644 test/core/table64.wast diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 03edd1c05..067fab8f3 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -190,9 +190,8 @@ let limits uN s = let table_type s = let t = ref_type s in - let lim, is64 = limits u32 s in - require (not is64) s (pos s - 1) "tables cannot have 64-bit indices"; - TableType (lim, t) + let lim, is64 = limits u64 s in + TableType (lim, (if is64 then I64IndexType else I32IndexType), t) let memory_type s = let lim, is64 = limits u64 s in diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 83649a648..743b0c5d1 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -123,7 +123,7 @@ struct byte flags; vu min; opt vu max let table_type = function - | TableType (lim, t) -> ref_type t; limits u32 lim I32IndexType + | TableType (lim, it, t) -> ref_type t; limits u64 lim it let memory_type = function | MemoryType (lim, it) -> limits u64 lim it diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 2388448f2..13271ba91 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -42,6 +42,11 @@ let numeric_error at = function | exn -> raise exn +let value_of_index it x = + match it with + | I64IndexType -> Num (I64 x) + | I32IndexType -> Num (I32 (Int64.to_int32 x)) + (* Administrative Expressions & Configurations *) type 'a stack = 'a list @@ -93,13 +98,13 @@ let local (frame : frame) x = lookup "local" frame.locals x let any_ref inst x i at = try Table.load (table inst x) i with Table.Bounds -> - Trap.error at ("undefined element " ^ Int32.to_string i) + Trap.error at ("undefined element " ^ Int64.to_string i) let func_ref inst x i at = match any_ref inst x i at with | FuncRef f -> f - | NullRef _ -> Trap.error at ("uninitialized element " ^ Int32.to_string i) - | _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i) + | NullRef _ -> Trap.error at ("uninitialized element " ^ Int64.to_string i) + | _ -> Crash.error at ("type mismatch for element " ^ Int64.to_string i) let func_type_of = function | Func.AstFunc (t, inst, f) -> t @@ -140,12 +145,12 @@ let data_oob frame x i n = (Data.size (data frame.inst x)) let table_oob frame x i n = - I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) - (I64_convert.extend_i32_u (Table.size (table frame.inst x))) + I64.gt_u (I64.add (Table.index_of_num i) (Table.index_of_num n)) + (Table.size (table frame.inst x)) let elem_oob frame x i n = - I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n)) - (I64_convert.extend_i32_u (Elem.size (elem frame.inst x))) + I64.gt_u (I64.add (Table.index_of_num i) (Table.index_of_num n)) + (Elem.size (elem frame.inst x)) let inc_address i at = match i with @@ -206,7 +211,8 @@ let rec step (c : config) : config = | Call x, vs -> vs, [Invoke (func frame.inst x) @@ e.at] - | CallIndirect (x, y), Num (I32 i) :: vs -> + | CallIndirect (x, y), Num n :: vs -> + let i = Table.index_of_num n in let func = func_ref frame.inst x i e.at in if type_ frame.inst y <> Func.type_of func then vs, [Trapping "indirect call type mismatch" @@ e.at] @@ -241,85 +247,97 @@ let rec step (c : config) : config = with Global.NotMutable -> Crash.error e.at "write to immutable global" | Global.Type -> Crash.error e.at "type mismatch at global write") - | TableGet x, Num (I32 i) :: vs' -> + | TableGet x, Num n :: vs' -> + let i = Table.index_of_num n in (try Ref (Table.load (table frame.inst x) i) :: vs', [] with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) - | TableSet x, Ref r :: Num (I32 i) :: vs' -> + | TableSet x, Ref r :: Num n :: vs' -> + let i = Table.index_of_num n in (try Table.store (table frame.inst x) i r; vs', [] with exn -> vs', [Trapping (table_error e.at exn) @@ e.at]) | TableSize x, vs -> - Num (I32 (Table.size (table frame.inst x))) :: vs, [] + let tab = table frame.inst x in + value_of_index (Table.index_of tab) (Table.size (table frame.inst x)) :: vs, [] - | TableGrow x, Num (I32 delta) :: Ref r :: vs' -> + | TableGrow x, Num delta :: Ref r :: vs' -> let tab = table frame.inst x in + let delta_64 = Table.index_of_num delta in let old_size = Table.size tab in let result = - try Table.grow tab delta r; old_size - with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1l - in Num (I32 result) :: vs', [] + try Table.grow tab delta_64 r; old_size + with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1L + in (value_of_index (Table.index_of tab) result) :: vs', [] - | TableFill x, Num (I32 n) :: Ref r :: Num (I32 i) :: vs' -> + | TableFill x, Num n :: Ref r :: Num i :: vs' -> + let n_64 = Table.index_of_num n in if table_oob frame x i n then vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] - else if n = 0l then + else if n_64 = 0L then vs', [] else - let _ = assert (I32.lt_u i 0xffff_ffffl) in + let i_64 = Table.index_of_num i in + let _ = assert (I64.lt_u i_64 0xffff_ffff_ffff_ffffL) in vs', List.map (at e.at) [ - Plain (Const (I32 i @@ e.at)); + Plain (Const (I64 i_64 @@ e.at)); Refer r; Plain (TableSet x); - Plain (Const (I32 (I32.add i 1l) @@ e.at)); + Plain (Const (I64 (I64.add i_64 1L) @@ e.at)); Refer r; - Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (Const (I64 (I64.sub n_64 1L) @@ e.at)); Plain (TableFill x); ] - | TableCopy (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + | TableCopy (x, y), Num n :: Num s :: Num d :: vs' -> + let n_64 = Table.index_of_num n in + let s_64 = Table.index_of_num s in + let d_64 = Table.index_of_num d in if table_oob frame x d n || table_oob frame y s n then vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] - else if n = 0l then + else if n_64 = 0L then vs', [] - else if I32.le_u d s then + else if I64.le_u d_64 s_64 then vs', List.map (at e.at) [ - Plain (Const (I32 d @@ e.at)); - Plain (Const (I32 s @@ e.at)); + Plain (Const (I64 d_64 @@ e.at)); + Plain (Const (I64 s_64 @@ e.at)); Plain (TableGet y); Plain (TableSet x); - Plain (Const (I32 (I32.add d 1l) @@ e.at)); - Plain (Const (I32 (I32.add s 1l) @@ e.at)); - Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (Const (I64 (I64.add d_64 1L) @@ e.at)); + Plain (Const (I64 (I64.add s_64 1L) @@ e.at)); + Plain (Const (I64 (I64.sub n_64 1L) @@ e.at)); Plain (TableCopy (x, y)); ] else (* d > s *) - let n' = I32.sub n 1l in + let n' = I64.sub n_64 1L in vs', List.map (at e.at) [ - Plain (Const (I32 (I32.add d n') @@ e.at)); - Plain (Const (I32 (I32.add s n') @@ e.at)); + Plain (Const (I64 (I64.add d_64 n') @@ e.at)); + Plain (Const (I64 (I64.add s_64 n') @@ e.at)); Plain (TableGet y); Plain (TableSet x); - Plain (Const (I32 d @@ e.at)); - Plain (Const (I32 s @@ e.at)); - Plain (Const (I32 n' @@ e.at)); + Plain (Const (I64 d_64 @@ e.at)); + Plain (Const (I64 s_64 @@ e.at)); + Plain (Const (I64 n' @@ e.at)); Plain (TableCopy (x, y)); ] - | TableInit (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' -> + | TableInit (x, y), Num n :: Num s :: Num d :: vs' -> + let n_64 = Table.index_of_num n in if table_oob frame x d n || elem_oob frame y s n then vs', [Trapping (table_error e.at Table.Bounds) @@ e.at] - else if n = 0l then + else if n_64 = 0L then vs', [] else + let d_64 = Table.index_of_num d in + let s_64 = Table.index_of_num s in let seg = elem frame.inst y in vs', List.map (at e.at) [ - Plain (Const (I32 d @@ e.at)); - Refer (Elem.load seg s); + Plain (Const (I64 d_64 @@ e.at)); + Refer (Elem.load seg s_64); Plain (TableSet x); - Plain (Const (I32 (I32.add d 1l) @@ e.at)); - Plain (Const (I32 (I32.add s 1l) @@ e.at)); - Plain (Const (I32 (I32.sub n 1l) @@ e.at)); + Plain (Const (I64 (I64.add d_64 1L) @@ e.at)); + Plain (Const (I64 (I64.add s_64 1L) @@ e.at)); + Plain (Const (I64 (I64.sub n_64 1L) @@ e.at)); Plain (TableInit (x, y)); ] @@ -411,7 +429,7 @@ let rec step (c : config) : config = | MemorySize, vs -> let mem = memory frame.inst (0l @@ e.at) in - Memory.value_of_address (Memory.index_of mem) (Memory.size mem) :: vs, [] + value_of_index (Memory.index_of mem) (Memory.size mem) :: vs, [] | MemoryGrow, Num delta :: vs' -> let mem = memory frame.inst (0l @@ e.at) in @@ -419,7 +437,7 @@ let rec step (c : config) : config = let result = try Memory.grow mem (Memory.address_of_num delta); old_size with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1L - in (Memory.value_of_address (Memory.index_of mem) result) :: vs', [] + in (value_of_index (Memory.index_of mem) result) :: vs', [] | MemoryFill, Num n :: Num k :: Num i :: vs' -> let n_64 = Memory.address_of_num n in @@ -709,7 +727,7 @@ let create_func (inst : module_inst) (f : func) : func_inst = let create_table (inst : module_inst) (tab : table) : table_inst = let {ttype} = tab.it in - let TableType (_lim, t) = ttype in + let TableType (_lim, _it, t) = ttype in Table.alloc ttype (NullRef t) let create_memory (inst : module_inst) (mem : memory) : memory_inst = diff --git a/interpreter/host/spectest.ml b/interpreter/host/spectest.ml index 28679d9e1..2555ec683 100644 --- a/interpreter/host/spectest.ml +++ b/interpreter/host/spectest.ml @@ -19,7 +19,10 @@ let global (GlobalType (t, _) as gt) = in Global.alloc gt v let table = - Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) + Table.alloc (TableType ({min = 10L; max = Some 20L}, I32IndexType, FuncRefType)) + (NullRef FuncRefType) +let table64 = + Table.alloc (TableType ({min = 10L; max = Some 20L}, I64IndexType, FuncRefType)) (NullRef FuncRefType) let memory = Memory.alloc (MemoryType ({min = 1L; max = Some 2L}, I32IndexType)) let func f t = Func.alloc_host t (f t) @@ -51,5 +54,6 @@ let lookup name t = | "global_f32", _ -> ExternGlobal (global (GlobalType (NumType F32Type, Immutable))) | "global_f64", _ -> ExternGlobal (global (GlobalType (NumType F64Type, Immutable))) | "table", _ -> ExternTable table + | "table64", _ -> ExternTable table64 | "memory", _ -> ExternMemory memory | _ -> raise Not_found diff --git a/interpreter/runtime/elem.ml b/interpreter/runtime/elem.ml index 366ec6df0..816d532bc 100644 --- a/interpreter/runtime/elem.ml +++ b/interpreter/runtime/elem.ml @@ -4,10 +4,10 @@ type t = elem exception Bounds let alloc rs = ref rs -let size seg = Lib.List32.length !seg +let size seg = Lib.List64.length !seg let load seg i = - if i < 0l || i >= Lib.List32.length !seg then raise Bounds; - Lib.List32.nth !seg i + if i < 0L || i >= Lib.List64.length !seg then raise Bounds; + Lib.List64.nth !seg i let drop seg = seg := [] diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index 4f13bdd7b..45ff9a529 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -50,11 +50,6 @@ let type_of mem = let index_of mem = let (MemoryType (_, it)) = type_of mem in it -let value_of_address it x = - match it with - | I64IndexType -> Num (I64 x) - | I32IndexType -> Num (I32 (Int64.to_int32 x)) - let address_of_num x = match x with | I64 i -> i diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index 860316727..8ba92fc95 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -22,7 +22,6 @@ val type_of : memory -> memory_type val index_of : memory -> index_type val size : memory -> size val bound : memory -> address -val value_of_address : index_type -> address -> value val address_of_value : value -> address val address_of_num : num -> address val grow : memory -> size -> unit diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index e7fc317e8..3cbd748e1 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -1,8 +1,8 @@ open Types open Values -type size = int32 -type index = int32 +type size = int64 +type index = int64 type count = int32 type table = {mutable ty : table_type; mutable content : ref_ array} @@ -17,47 +17,62 @@ exception OutOfMemory let valid_limits {min; max} = match max with | None -> true - | Some m -> I32.le_u min m + | Some m -> I64.le_u min m -let create size r = - try Lib.Array32.make size r +let valid_index it i = + match it with + | I32IndexType -> I64.le_u i 0xffff_ffffL + | I64IndexType -> true + +let create size it r = + try Lib.Array64.make size r with Out_of_memory | Invalid_argument _ -> raise OutOfMemory -let alloc (TableType (lim, _) as ty) r = +let alloc (TableType (lim, it, _) as ty) r = if not (valid_limits lim) then raise Type; - {ty; content = create lim.min r} + {ty; content = create lim.min it r} let size tab = - Lib.Array32.length tab.content + Lib.Array64.length tab.content let type_of tab = tab.ty +let index_of tab = + let (TableType (_, it, _)) = type_of tab in it + +let index_of_num x = + match x with + | I64 i -> i + | I32 i -> I64_convert.extend_i32_u i + | _ -> raise Type + let grow tab delta r = - let TableType (lim, t) = tab.ty in + let TableType (lim, it, t) = tab.ty in assert (lim.min = size tab); let old_size = lim.min in - let new_size = Int32.add old_size delta in - if I32.gt_u old_size new_size then raise SizeOverflow else + let new_size = Int64.add old_size delta in + if I64.gt_u old_size new_size then raise SizeOverflow else let lim' = {lim with min = new_size} in + if not (valid_index it new_size) then raise SizeOverflow else if not (valid_limits lim') then raise SizeLimit else - let after = create new_size r in + let after = create new_size it r in Array.blit tab.content 0 after 0 (Array.length tab.content); - tab.ty <- TableType (lim', t); + tab.ty <- TableType (lim', it, t); tab.content <- after let load tab i = - if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; - Lib.Array32.get tab.content i + if i < 0L || i >= Lib.Array64.length tab.content then raise Bounds; + Lib.Array64.get tab.content i let store tab i r = - let TableType (lim, t) = tab.ty in + let TableType (_lim, _it, t) = tab.ty in if type_of_ref r <> t then raise Type; - if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; - Lib.Array32.set tab.content i r + if i < 0L || i >= Lib.Array64.length tab.content then raise Bounds; + Lib.Array64.set tab.content i r let blit tab offset rs = let data = Array.of_list rs in - let len = Lib.Array32.length data in - if offset < 0l || offset > Int32.sub (Lib.Array32.length tab.content) len then raise Bounds; - Lib.Array32.blit data 0l tab.content offset len + let len = Lib.Array64.length data in + if offset < 0L || offset > Int64.sub (Lib.Array64.length tab.content) len then raise Bounds; + Lib.Array64.blit data 0L tab.content offset len diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index cf424e357..a0ae68fc8 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -4,8 +4,8 @@ open Values type table type t = table -type size = int32 -type index = int32 +type size = int64 +type index = int64 type count = int32 exception Type @@ -16,7 +16,9 @@ exception OutOfMemory val alloc : table_type -> ref_ -> table (* raises Type, OutOfMemory *) val type_of : table -> table_type +val index_of : table -> index_type val size : table -> size +val index_of_num : num -> index val grow : table -> size -> ref_ -> unit (* raises SizeOverflow, SizeLimit, OutOfMemory *) diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 3e6daf1cd..9296c909f 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -10,7 +10,7 @@ type func_type = FuncType of result_type * result_type type 'a limits = {min : 'a; max : 'a option} type mutability = Immutable | Mutable -type table_type = TableType of Int32.t limits * ref_type +type table_type = TableType of Int64.t limits * index_type * ref_type type memory_type = MemoryType of Int64.t limits * index_type type global_type = GlobalType of value_type * mutability type extern_type = @@ -89,8 +89,8 @@ let match_limits ge lim1 lim2 = let match_func_type ft1 ft2 = ft1 = ft2 -let match_table_type (TableType (lim1, et1)) (TableType (lim2, et2)) = - et1 = et2 && match_limits I32.ge_u lim1 lim2 +let match_table_type (TableType (lim1, it1, et1)) (TableType (lim2, it2, et2)) = + it1 = it2 && et1 = et2 && match_limits I64.ge_u lim1 lim2 let match_memory_type (MemoryType (lim1, it1)) (MemoryType (lim2, it2)) = it1 = it2 && match_limits I64.ge_u lim1 lim2 @@ -147,8 +147,10 @@ let string_of_memory_type = function let string_of_table_type = function - | TableType (lim, t) -> string_of_limits I32.to_string_u lim ^ " " ^ - string_of_ref_type t + | TableType (lim, it, t) -> + string_of_num_type (num_type_of_index_type it) ^ + " " ^ string_of_limits I64.to_string_u lim ^ + " " ^ string_of_ref_type t let string_of_global_type = function | GlobalType (t, Immutable) -> string_of_value_type t diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 7a1132f24..a22b54496 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -533,9 +533,9 @@ let func f = (* Tables & memories *) let table off i tab = - let {ttype = TableType (lim, t)} = tab.it in - Node ("table $" ^ nat (off + i) ^ " " ^ limits nat32 lim, - [atom ref_type t] + let {ttype = TableType (lim, it, t)} = tab.it in + Node ("table $" ^ nat (off + i) ^ " " ^ index_type it ^ " " ^ + limits nat64 lim, [atom ref_type t] ) let memory off i mem = diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 07ce0472b..e5e855d3c 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -206,12 +206,12 @@ let index_type_of_num_type t loc = match t with | I32Type -> I32IndexType | I64Type -> I64IndexType - | _ -> error (at loc) "illegal memory index type" + | _ -> error (at loc) "illegal index type" let index_type_of_value_type t loc = match t with | NumType t -> index_type_of_num_type t loc - | _ -> error (at loc) "illegal memory index type" + | _ -> error (at loc) "illegal index type" let memory_data init it c x at = let size = Int64.(div (add (of_int (String.length init)) 65535L) 65536L) in @@ -222,6 +222,18 @@ let memory_data init it c x at = [{dinit = init; dmode = Active {index = x; offset = [instr @@ at] @@ at} @@ at} @@ at], [], [] +let table_data init it t c x at = + let instr = match it with + | I32IndexType -> i32_const (0l @@ at) + | I64IndexType -> i64_const (0L @@ at) in + let einit = init c in + let size = Lib.List32.length einit in + let size64 = Int64.of_int32 size in + let emode = Active {index = x; offset = [instr @@ at] @@ at} @@ at in + [{ttype = TableType ({min = size64; max = Some size64}, it, t)} @@ at], + [{etype = t; einit; emode} @@ at], + [], [] + %} %token LPAR RPAR @@ -313,16 +325,13 @@ func_type_result : { $3 @ $5 } table_type : - | limits32 ref_type { TableType ($1, $2) } + | value_type limits64 ref_type { TableType ($2, index_type_of_value_type $1 $sloc, $3) } + | limits64 ref_type { TableType ($1, I32IndexType, $2) } memory_type : | value_type limits64 { MemoryType ($2, index_type_of_value_type $1 $sloc) } | limits64 { MemoryType ($1, I32IndexType) } -limits32 : - | NAT { {min = nat32 $1 $loc($1); max = None} } - | NAT NAT { {min = nat32 $1 $loc($1); max = Some (nat32 $2 $loc($2))} } - limits64 : | NAT { {min = nat64 $1 $loc($1); max = None} } | NAT NAT { {min = nat64 $1 $loc($1); max = Some (nat64 $2 $loc($2))} } @@ -810,19 +819,15 @@ table_fields : let offset = [i32_const (0l @@ at) @@ at] @@ at in let einit = $4 c :: $5 c in let size = Lib.List32.length einit in + let size64 = Int64.of_int32 size in let emode = Active {index = x; offset} @@ at in - [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], + [{ttype = TableType ({min = size64; max = Some size64}, I32IndexType, $1)} @@ at], [{etype = $1; einit; emode} @@ at], [], [] } | ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ - { fun c x at -> - let offset = [i32_const (0l @@ at) @@ at] @@ at in - let einit = $4 c in - let size = Lib.List32.length einit in - let emode = Active {index = x; offset} @@ at in - [{ttype = TableType ({min = size; max = Some size}, $1)} @@ at], - [{etype = FuncRefType; einit; emode} @@ at], - [], [] } + { table_data $4 I32IndexType FuncRefType } + | value_type ref_type LPAR ELEM elem_var_list RPAR /* Sugar */ + { table_data $5 (index_type_of_value_type $1 $sloc) FuncRefType } data : | LPAR DATA bind_var_opt string_list RPAR diff --git a/interpreter/util/lib.ml b/interpreter/util/lib.ml index 90c4e4fe0..051661e86 100644 --- a/interpreter/util/lib.ml +++ b/interpreter/util/lib.ml @@ -152,23 +152,60 @@ struct | x::xs -> f i x :: mapi' f (Int32.add i 1l) xs end -module Array32 = +module List64 = +struct + let rec make n x = make' n x [] + and make' n x xs = + if n = 0L then xs else make' (Int64.sub n 1L) x (x::xs) + + let rec length xs = length' xs 0L + and length' xs n = + match xs with + | [] -> n + | _::xs' when n < Int64.max_int -> length' xs' (Int64.add n 1L) + | _ -> failwith "length" + + let rec nth xs n = + match n, xs with + | 0L, x::_ -> x + | n, _::xs' when n > 0L -> nth xs' (Int64.sub n 1L) + | _ -> failwith "nth" + + let rec take n xs = + match n, xs with + | 0L, _ -> [] + | n, x::xs' when n > 0L -> x :: take (Int64.sub n 1L) xs' + | _ -> failwith "take" + + let rec drop n xs = + match n, xs with + | 0L, _ -> xs + | n, _::xs' when n > 0L -> drop (Int64.sub n 1L) xs' + | _ -> failwith "drop" + + let rec mapi f xs = mapi' f 0L xs + and mapi' f i = function + | [] -> [] + | x::xs -> f i x :: mapi' f (Int64.add i 1L) xs +end + +module Array64 = struct let make n x = - if n < 0l || Int64.of_int32 n > Int64.of_int max_int then - invalid_arg "Array32.make"; - Array.make (Int32.to_int n) x + if n < 0L || n > Int64.of_int max_int then + invalid_arg "Array64.make"; + Array.make (Int64.to_int n) x - let length a = Int32.of_int (Array.length a) + let length a = Int64.of_int (Array.length a) - let index_of_int32 i = - if i < 0l || Int64.of_int32 i > Int64.of_int max_int then -1 else - Int32.to_int i + let index_of_int64 i = + if i < 0L || i > Int64.of_int max_int then -1 else + Int64.to_int i - let get a i = Array.get a (index_of_int32 i) - let set a i x = Array.set a (index_of_int32 i) x + let get a i = Array.get a (index_of_int64 i) + let set a i x = Array.set a (index_of_int64 i) x let blit a1 i1 a2 i2 n = - Array.blit a1 (index_of_int32 i1) a2 (index_of_int32 i2) (index_of_int32 n) + Array.blit a1 (index_of_int64 i1) a2 (index_of_int64 i2) (index_of_int64 n) end module Bigarray = diff --git a/interpreter/util/lib.mli b/interpreter/util/lib.mli index b66b8b0e8..9179956f9 100644 --- a/interpreter/util/lib.mli +++ b/interpreter/util/lib.mli @@ -38,13 +38,23 @@ sig val mapi : (int32 -> 'a -> 'b) -> 'a list -> 'b list end -module Array32 : +module List64 : sig - val make : int32 -> 'a -> 'a array - val length : 'a array -> int32 - val get : 'a array -> int32 -> 'a - val set : 'a array -> int32 -> 'a -> unit - val blit : 'a array -> int32 -> 'a array -> int32 -> int32 -> unit + val make : int64 -> 'a -> 'a list + val length : 'a list -> int64 + val nth : 'a list -> int64 -> 'a (* raises Failure *) + val take : int64 -> 'a list -> 'a list (* raises Failure *) + val drop : int64 -> 'a list -> 'a list (* raises Failure *) + val mapi : (int64 -> 'a -> 'b) -> 'a list -> 'b list +end + +module Array64 : +sig + val make : int64 -> 'a -> 'a array + val length : 'a array -> int64 + val get : 'a array -> int64 -> 'a + val set : 'a array -> int64 -> 'a -> unit + val blit : 'a array -> int64 -> 'a array -> int64 -> int64 -> unit end module Bigarray : diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 3ada40081..291b9f405 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -292,12 +292,12 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type ts1 --> ts2 | CallIndirect (x, y) -> - let TableType (lim, t) = table c x in + let TableType (lim, it, t) = table c x in let FuncType (ts1, ts2) = type_ c y in require (t = FuncRefType) x.at ("type mismatch: instruction requires table of functions" ^ " but table has " ^ string_of_ref_type t); - (ts1 @ [NumType I32Type]) --> ts2 + (ts1 @ [value_type_of_index_type it]) --> ts2 | LocalGet x -> [] --> [local c x] @@ -318,35 +318,35 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type [t] --> [] | TableGet x -> - let TableType (_lim, t) = table c x in - [NumType I32Type] --> [RefType t] + let TableType (_lim, it, t) = table c x in + [value_type_of_index_type it] --> [RefType t] | TableSet x -> - let TableType (_lim, t) = table c x in - [NumType I32Type; RefType t] --> [] + let TableType (_lim, it, t) = table c x in + [value_type_of_index_type it; RefType t] --> [] | TableSize x -> let _tt = table c x in [] --> [NumType I32Type] | TableGrow x -> - let TableType (_lim, t) = table c x in + let TableType (_lim, _it, t) = table c x in [RefType t; NumType I32Type] --> [NumType I32Type] | TableFill x -> - let TableType (_lim, t) = table c x in + let TableType (_lim, _it, t) = table c x in [NumType I32Type; RefType t; NumType I32Type] --> [] | TableCopy (x, y) -> - let TableType (_lim1, t1) = table c x in - let TableType (_lim2, t2) = table c y in + let TableType (_lim1, _it, t1) = table c x in + let TableType (_lim2, _it, t2) = table c y in require (t1 = t2) x.at ("type mismatch: source element type " ^ string_of_ref_type t1 ^ " does not match destination element type " ^ string_of_ref_type t2); [NumType I32Type; NumType I32Type; NumType I32Type] --> [] | TableInit (x, y) -> - let TableType (_lim1, t1) = table c x in + let TableType (_lim1, _it, t1) = table c x in let t2 = elem c y in require (t1 = t2) x.at ("type mismatch: element segment's type " ^ string_of_ref_type t1 ^ @@ -571,9 +571,14 @@ let check_func_type (ft : func_type) at = List.iter (fun t -> check_value_type t at) ts2 let check_table_type (tt : table_type) at = - let TableType (lim, t) = tt in - check_limits I32.le_u lim 0xffff_ffffl at "table size must be at most 2^32-1"; - check_ref_type t at + let TableType (lim, it, t) = tt in + match it with + | I64IndexType -> + check_limits I64.le_u lim 0xffff_ffff_ffff_ffffL at + "table size must be at most 2^64-1" + | I32IndexType -> + check_limits I64.le_u lim 0xffff_ffffL at + "table size must be at most 2^32-1" let check_memory_type (mt : memory_type) at = let MemoryType (lim, it) = mt in @@ -589,7 +594,6 @@ let check_global_type (gt : global_type) at = let GlobalType (t, mut) = gt in check_value_type t at - let check_type (t : type_) = check_func_type t.it t.at @@ -644,11 +648,11 @@ let check_elem_mode (c : context) (t : ref_type) (mode : segment_mode) = match mode.it with | Passive -> () | Active {index; offset} -> - let TableType (_, et) = table c index in + let TableType (_, it, et) = table c index in require (t = et) mode.at ("type mismatch: element segment's type " ^ string_of_ref_type t ^ " does not match table's element type " ^ string_of_ref_type et); - check_const c offset (NumType I32Type) + check_const c offset (value_type_of_index_type it) | Declarative -> () let check_elem (c : context) (seg : elem_segment) = diff --git a/test/core/call_indirect.wast b/test/core/call_indirect.wast index 79b8dc393..ba267fea5 100644 --- a/test/core/call_indirect.wast +++ b/test/core/call_indirect.wast @@ -61,10 +61,15 @@ ) ) + (table $t64 i64 funcref + (elem $const-i32) + ) + ;; Syntax (func (call_indirect (i32.const 0)) + (call_indirect $t64 (i64.const 0)) (call_indirect (param i64) (i64.const 0) (i32.const 0)) (call_indirect (param i64) (param) (param f64 i32 i64) (i64.const 0) (f64.const 0) (i32.const 0) (i64.const 0) (i32.const 0) @@ -94,6 +99,9 @@ (func (export "type-i32") (result i32) (call_indirect (type $out-i32) (i32.const 0)) ) + (func (export "type-i32-t64") (result i32) + (call_indirect $t64 (type $out-i32) (i64.const 0)) + ) (func (export "type-i64") (result i64) (call_indirect (type $out-i64) (i32.const 1)) ) @@ -474,6 +482,8 @@ (assert_return (invoke "type-f64") (f64.const 0xf64)) (assert_return (invoke "type-f64-i32") (f64.const 0xf64) (i32.const 32)) +(assert_return (invoke "type-i32-t64") (i32.const 0x132)) + (assert_return (invoke "type-index") (i64.const 100)) (assert_return (invoke "type-first-i32") (i32.const 32)) diff --git a/test/core/table.wast b/test/core/table.wast index 0bd04f5cc..0d3a07ec2 100644 --- a/test/core/table.wast +++ b/test/core/table.wast @@ -24,17 +24,17 @@ "size minimum must not be greater than maximum" ) -(assert_malformed +(assert_invalid (module quote "(table 0x1_0000_0000 funcref)") - "i32 constant out of range" + "table size must be at most 2^32-1" ) -(assert_malformed +(assert_invalid (module quote "(table 0x1_0000_0000 0x1_0000_0000 funcref)") - "i32 constant out of range" + "table size must be at most 2^32-1" ) -(assert_malformed +(assert_invalid (module quote "(table 0 0x1_0000_0000 funcref)") - "i32 constant out of range" + "table size must be at most 2^32-1" ) diff --git a/test/core/table64.wast b/test/core/table64.wast new file mode 100644 index 000000000..175c773c8 --- /dev/null +++ b/test/core/table64.wast @@ -0,0 +1,26 @@ +;; Test table section structure +;; Largely duplicated from table.wast, but with all tables using a 64-bit index. + +(module (table i64 0 funcref)) +(module (table i64 1 funcref)) +(module (table i64 0 0 funcref)) +(module (table i64 0 1 funcref)) +(module (table i64 1 256 funcref)) +(module (table i64 0 65536 funcref)) +(module (table i64 0 0xffff_ffff funcref)) + +(module (table i64 0 funcref) (table i64 0 funcref)) +(module (table (import "spectest" "table64") i64 0 funcref) (table i64 0 funcref)) + +(assert_invalid (module (elem (i32.const 0))) "unknown table") +(assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") + + +(assert_invalid + (module (table i64 1 0 funcref)) + "size minimum must not be greater than maximum" +) +(assert_invalid + (module (table i64 0xffff_ffff 0 funcref)) + "size minimum must not be greater than maximum" +) diff --git a/test/core/table_get.wast b/test/core/table_get.wast index 0dedb19f5..b472ad255 100644 --- a/test/core/table_get.wast +++ b/test/core/table_get.wast @@ -1,6 +1,7 @@ (module (table $t2 2 externref) (table $t3 3 funcref) + (table $t64 i64 3 funcref) (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) @@ -15,6 +16,9 @@ (func $f3 (export "get-funcref") (param $i i32) (result funcref) (table.get $t3 (local.get $i)) ) + (func $f4 (export "get-funcref-t64") (param $i i64) (result funcref) + (table.get $t64 (local.get $i)) + ) (func (export "is_null-funcref") (param $i i32) (result i32) (ref.is_null (call $f3 (local.get $i))) @@ -27,6 +31,7 @@ (assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1)) (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) +(assert_return (invoke "get-funcref-t64" (i64.const 0)) (ref.null func)) (assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0)) (assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0)) diff --git a/test/core/table_init.wast b/test/core/table_init.wast index 0b2d26f77..fa1e0fdf8 100644 --- a/test/core/table_init.wast +++ b/test/core/table_init.wast @@ -21,10 +21,13 @@ (import "a" "ef4" (func (result i32))) ;; index 4 (table $t0 30 30 funcref) (table $t1 30 30 funcref) + (table $t64 i64 30 30 funcref) (elem (table $t0) (i32.const 2) func 3 1 4 1) + (elem (table $t64) (i64.const 2) func 3 1 4 1) (elem funcref (ref.func 2) (ref.func 7) (ref.func 1) (ref.func 8)) (elem (table $t0) (i32.const 12) func 7 5 2 3 6) + (elem (table $t64) (i64.const 12) func 7 5 2 3 6) (elem funcref (ref.func 5) (ref.func 9) (ref.func 2) (ref.func 7) (ref.func 6)) (func (result i32) (i32.const 5)) ;; index 5 @@ -33,9 +36,13 @@ (func (result i32) (i32.const 8)) (func (result i32) (i32.const 9)) ;; index 9 (func (export "test") - (table.init $t0 1 (i32.const 7) (i32.const 0) (i32.const 4))) + (table.init $t0 2 (i32.const 7) (i32.const 0) (i32.const 4))) + (func (export "test-t64") + (table.init $t64 2 (i32.const 7) (i32.const 0) (i32.const 4))) (func (export "check") (param i32) (result i32) (call_indirect $t0 (type 0) (local.get 0))) + (func (export "check-t64") (param i64) (result i32) + (call_indirect $t64 (type 0) (local.get 0))) ) (invoke "test") @@ -70,6 +77,38 @@ (assert_trap (invoke "check" (i32.const 28)) "uninitialized element") (assert_trap (invoke "check" (i32.const 29)) "uninitialized element") +(invoke "test-t64") +(assert_trap (invoke "check-t64" (i64.const 0)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 1)) "uninitialized element") +(assert_return (invoke "check-t64" (i64.const 2)) (i32.const 3)) +(assert_return (invoke "check-t64" (i64.const 3)) (i32.const 1)) +(assert_return (invoke "check-t64" (i64.const 4)) (i32.const 4)) +(assert_return (invoke "check-t64" (i64.const 5)) (i32.const 1)) +(assert_trap (invoke "check-t64" (i64.const 6)) "uninitialized element") +(assert_return (invoke "check-t64" (i64.const 7)) (i32.const 2)) +(assert_return (invoke "check-t64" (i64.const 8)) (i32.const 7)) +(assert_return (invoke "check-t64" (i64.const 9)) (i32.const 1)) +(assert_return (invoke "check-t64" (i64.const 10)) (i32.const 8)) +(assert_trap (invoke "check-t64" (i64.const 11)) "uninitialized element") +(assert_return (invoke "check-t64" (i64.const 12)) (i32.const 7)) +(assert_return (invoke "check-t64" (i64.const 13)) (i32.const 5)) +(assert_return (invoke "check-t64" (i64.const 14)) (i32.const 2)) +(assert_return (invoke "check-t64" (i64.const 15)) (i32.const 3)) +(assert_return (invoke "check-t64" (i64.const 16)) (i32.const 6)) +(assert_trap (invoke "check-t64" (i64.const 17)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 18)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 19)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 20)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 21)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 22)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 23)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 24)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 25)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 26)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 27)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 28)) "uninitialized element") +(assert_trap (invoke "check-t64" (i64.const 29)) "uninitialized element") + (module (type (func (result i32))) ;; type #0 (import "a" "ef0" (func (result i32))) ;; index 0 diff --git a/test/core/table_set.wast b/test/core/table_set.wast index 3362f9567..246e01ad9 100644 --- a/test/core/table_set.wast +++ b/test/core/table_set.wast @@ -1,6 +1,7 @@ (module (table $t2 1 externref) (table $t3 2 funcref) + (table $t64 i64 2 funcref) (elem (table $t3) (i32.const 1) func $dummy) (func $dummy) @@ -10,6 +11,9 @@ (func $f3 (export "get-funcref") (param $i i32) (result funcref) (table.get $t3 (local.get $i)) ) + (func $f4 (export "get-funcref-t64") (param $i i64) (result funcref) + (table.get $t64 (local.get $i)) + ) (func (export "set-externref") (param $i i32) (param $r externref) (table.set (local.get $i) (local.get $r)) @@ -20,6 +24,9 @@ (func (export "set-funcref-from") (param $i i32) (param $j i32) (table.set $t3 (local.get $i) (table.get $t3 (local.get $j))) ) + (func (export "set-funcref-t64") (param $i i64) (param $r funcref) + (table.set $t64 (local.get $i) (local.get $r)) + ) (func (export "is_null-funcref") (param $i i32) (result i32) (ref.is_null (call $f3 (local.get $i))) @@ -32,6 +39,9 @@ (assert_return (invoke "set-externref" (i32.const 0) (ref.null extern))) (assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) +(assert_return (invoke "set-funcref-t64" (i64.const 0) (ref.null func))) +(assert_return (invoke "get-funcref-t64" (i64.const 0)) (ref.null func)) + (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) (assert_return (invoke "set-funcref-from" (i32.const 0) (i32.const 1))) (assert_return (invoke "is_null-funcref" (i32.const 0)) (i32.const 0)) From 6ea555ae47072f577c31e51fe67988e6d581de4a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 1 May 2024 08:18:11 -0700 Subject: [PATCH 2/4] feedback --- interpreter/exec/eval.ml | 11 +++++------ interpreter/runtime/memory.ml | 4 ++-- interpreter/runtime/memory.mli | 2 +- interpreter/runtime/table.ml | 8 ++++---- interpreter/runtime/table.mli | 2 +- interpreter/text/arrange.ml | 2 +- test/core/table.wast | 30 ++++++++++++++++++++++++++---- test/core/table64.wast | 26 -------------------------- 8 files changed, 40 insertions(+), 45 deletions(-) delete mode 100644 test/core/table64.wast diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 13271ba91..ed9d575f1 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -259,16 +259,15 @@ let rec step (c : config) : config = | TableSize x, vs -> let tab = table frame.inst x in - value_of_index (Table.index_of tab) (Table.size (table frame.inst x)) :: vs, [] + value_of_index (Table.index_type_of tab) (Table.size (table frame.inst x)) :: vs, [] | TableGrow x, Num delta :: Ref r :: vs' -> let tab = table frame.inst x in - let delta_64 = Table.index_of_num delta in let old_size = Table.size tab in let result = - try Table.grow tab delta_64 r; old_size + try Table.grow tab (Table.index_of_num delta) r; old_size with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1L - in (value_of_index (Table.index_of tab) result) :: vs', [] + in (value_of_index (Table.index_type_of tab) result) :: vs', [] | TableFill x, Num n :: Ref r :: Num i :: vs' -> let n_64 = Table.index_of_num n in @@ -429,7 +428,7 @@ let rec step (c : config) : config = | MemorySize, vs -> let mem = memory frame.inst (0l @@ e.at) in - value_of_index (Memory.index_of mem) (Memory.size mem) :: vs, [] + value_of_index (Memory.index_type_of mem) (Memory.size mem) :: vs, [] | MemoryGrow, Num delta :: vs' -> let mem = memory frame.inst (0l @@ e.at) in @@ -437,7 +436,7 @@ let rec step (c : config) : config = let result = try Memory.grow mem (Memory.address_of_num delta); old_size with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1L - in (value_of_index (Memory.index_of mem) result) :: vs', [] + in (value_of_index (Memory.index_type_of mem) result) :: vs', [] | MemoryFill, Num n :: Num k :: Num i :: vs' -> let n_64 = Memory.address_of_num n in diff --git a/interpreter/runtime/memory.ml b/interpreter/runtime/memory.ml index 45ff9a529..ef0a98289 100644 --- a/interpreter/runtime/memory.ml +++ b/interpreter/runtime/memory.ml @@ -47,7 +47,7 @@ let size mem = let type_of mem = mem.ty -let index_of mem = +let index_type_of mem = let (MemoryType (_, it)) = type_of mem in it let address_of_num x = @@ -69,7 +69,7 @@ let grow mem delta = if I64.gt_u old_size new_size then raise SizeOverflow else let lim' = {lim with min = new_size} in if not (valid_limits lim') then raise SizeLimit else - let after = create new_size (index_of mem) in + let after = create new_size (index_type_of mem) in let dim = Array1_64.dim mem.content in Array1.blit (Array1_64.sub mem.content 0L dim) (Array1_64.sub after 0L dim); mem.ty <- MemoryType (lim', it); diff --git a/interpreter/runtime/memory.mli b/interpreter/runtime/memory.mli index 8ba92fc95..1bcaa3b87 100644 --- a/interpreter/runtime/memory.mli +++ b/interpreter/runtime/memory.mli @@ -19,7 +19,7 @@ val page_size : int64 val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *) val type_of : memory -> memory_type -val index_of : memory -> index_type +val index_type_of : memory -> index_type val size : memory -> size val bound : memory -> address val address_of_value : value -> address diff --git a/interpreter/runtime/table.ml b/interpreter/runtime/table.ml index 3cbd748e1..ea532e49b 100644 --- a/interpreter/runtime/table.ml +++ b/interpreter/runtime/table.ml @@ -24,13 +24,13 @@ let valid_index it i = | I32IndexType -> I64.le_u i 0xffff_ffffL | I64IndexType -> true -let create size it r = +let create size r = try Lib.Array64.make size r with Out_of_memory | Invalid_argument _ -> raise OutOfMemory let alloc (TableType (lim, it, _) as ty) r = if not (valid_limits lim) then raise Type; - {ty; content = create lim.min it r} + {ty; content = create lim.min r} let size tab = Lib.Array64.length tab.content @@ -38,7 +38,7 @@ let size tab = let type_of tab = tab.ty -let index_of tab = +let index_type_of tab = let (TableType (_, it, _)) = type_of tab in it let index_of_num x = @@ -56,7 +56,7 @@ let grow tab delta r = let lim' = {lim with min = new_size} in if not (valid_index it new_size) then raise SizeOverflow else if not (valid_limits lim') then raise SizeLimit else - let after = create new_size it r in + let after = create new_size r in Array.blit tab.content 0 after 0 (Array.length tab.content); tab.ty <- TableType (lim', it, t); tab.content <- after diff --git a/interpreter/runtime/table.mli b/interpreter/runtime/table.mli index a0ae68fc8..b77093815 100644 --- a/interpreter/runtime/table.mli +++ b/interpreter/runtime/table.mli @@ -16,7 +16,7 @@ exception OutOfMemory val alloc : table_type -> ref_ -> table (* raises Type, OutOfMemory *) val type_of : table -> table_type -val index_of : table -> index_type +val index_type_of : table -> index_type val size : table -> size val index_of_num : num -> index val grow : table -> size -> ref_ -> unit diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index a22b54496..af6e98ab6 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -534,7 +534,7 @@ let func f = let table off i tab = let {ttype = TableType (lim, it, t)} = tab.it in - Node ("table $" ^ nat (off + i) ^ " " ^ index_type it ^ " " ^ + Node ("table $" ^ nat (off + i) ^ " " ^ index_type it ^ " " ^ limits nat64 lim, [atom ref_type t] ) diff --git a/test/core/table.wast b/test/core/table.wast index 0d3a07ec2..d61a7d1b7 100644 --- a/test/core/table.wast +++ b/test/core/table.wast @@ -11,10 +11,6 @@ (module (table 0 funcref) (table 0 funcref)) (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) -(assert_invalid (module (elem (i32.const 0))) "unknown table") -(assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") - - (assert_invalid (module (table 1 0 funcref)) "size minimum must not be greater than maximum" @@ -37,6 +33,32 @@ "table size must be at most 2^32-1" ) +;; Same as above but with i64 index types + +(module (table i64 0 funcref)) +(module (table i64 1 funcref)) +(module (table i64 0 0 funcref)) +(module (table i64 0 1 funcref)) +(module (table i64 1 256 funcref)) +(module (table i64 0 65536 funcref)) +(module (table i64 0 0xffff_ffff funcref)) + +(module (table i64 0 funcref) (table i64 0 funcref)) +(module (table (import "spectest" "table64") i64 0 funcref) (table i64 0 funcref)) + +(assert_invalid + (module (table i64 1 0 funcref)) + "size minimum must not be greater than maximum" +) +(assert_invalid + (module (table i64 0xffff_ffff 0 funcref)) + "size minimum must not be greater than maximum" +) + +;; Elem segments with no table + +(assert_invalid (module (elem (i32.const 0))) "unknown table") +(assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") ;; Duplicate table identifiers diff --git a/test/core/table64.wast b/test/core/table64.wast deleted file mode 100644 index 175c773c8..000000000 --- a/test/core/table64.wast +++ /dev/null @@ -1,26 +0,0 @@ -;; Test table section structure -;; Largely duplicated from table.wast, but with all tables using a 64-bit index. - -(module (table i64 0 funcref)) -(module (table i64 1 funcref)) -(module (table i64 0 0 funcref)) -(module (table i64 0 1 funcref)) -(module (table i64 1 256 funcref)) -(module (table i64 0 65536 funcref)) -(module (table i64 0 0xffff_ffff funcref)) - -(module (table i64 0 funcref) (table i64 0 funcref)) -(module (table (import "spectest" "table64") i64 0 funcref) (table i64 0 funcref)) - -(assert_invalid (module (elem (i32.const 0))) "unknown table") -(assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") - - -(assert_invalid - (module (table i64 1 0 funcref)) - "size minimum must not be greater than maximum" -) -(assert_invalid - (module (table i64 0xffff_ffff 0 funcref)) - "size minimum must not be greater than maximum" -) From dfd275ca57699ee2384deb0b0456655a389edac5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 1 May 2024 08:47:24 -0700 Subject: [PATCH 3/4] Disable node tests --- .github/workflows/ci-interpreter.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-interpreter.yml b/.github/workflows/ci-interpreter.yml index f0fc5d342..866a8da70 100644 --- a/.github/workflows/ci-interpreter.yml +++ b/.github/workflows/ci-interpreter.yml @@ -31,4 +31,6 @@ jobs: - name: Build interpreter run: cd interpreter && opam exec make - name: Run tests - run: cd interpreter && opam exec make JS="node --experimental-wasm-memory64" ci + # Re-enable the JS tests once table64 is available under node + #run: cd interpreter && opam exec make JS="node --experimental-wasm-memory64" ci + run: cd interpreter && opam exec make ci From c437e902c534b17fdb63007ff3e1a6b519a6b471 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 1 May 2024 08:50:35 -0700 Subject: [PATCH 4/4] feedback --- interpreter/exec/eval.ml | 5 ----- interpreter/syntax/values.ml | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index ed9d575f1..6bb3ac5eb 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -42,11 +42,6 @@ let numeric_error at = function | exn -> raise exn -let value_of_index it x = - match it with - | I64IndexType -> Num (I64 x) - | I32IndexType -> Num (I32 (Int64.to_int32 x)) - (* Administrative Expressions & Configurations *) type 'a stack = 'a list diff --git a/interpreter/syntax/values.ml b/interpreter/syntax/values.ml index eefe37d5d..1a2168f6b 100644 --- a/interpreter/syntax/values.ml +++ b/interpreter/syntax/values.ml @@ -151,6 +151,11 @@ let default_value = function let value_of_bool b = Num (I32 (if b then 1l else 0l)) +let value_of_index it x = + match it with + | I64IndexType -> Num (I64 x) + | I32IndexType -> Num (I32 (Int64.to_int32 x)) + let string_of_num = function | I32 i -> I32.to_string_s i | I64 i -> I64.to_string_s i