Skip to content

Commit

Permalink
Update interpreter and test suite for table64
Browse files Browse the repository at this point in the history
  • Loading branch information
sbc100 committed Apr 30, 2024
1 parent 9ed8215 commit fcb7714
Show file tree
Hide file tree
Showing 21 changed files with 327 additions and 147 deletions.
5 changes: 2 additions & 3 deletions interpreter/binary/decode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion interpreter/binary/encode.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
108 changes: 63 additions & 45 deletions interpreter/exec/eval.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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));
]

Expand Down Expand Up @@ -411,15 +429,15 @@ 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
let old_size = Memory.size mem in
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
Expand Down Expand Up @@ -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 =
Expand Down
6 changes: 5 additions & 1 deletion interpreter/host/spectest.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions interpreter/runtime/elem.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 := []
5 changes: 0 additions & 5 deletions interpreter/runtime/memory.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion interpreter/runtime/memory.mli
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 36 additions & 21 deletions interpreter/runtime/table.ml
Original file line number Diff line number Diff line change
@@ -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}
Expand All @@ -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
Loading

0 comments on commit fcb7714

Please sign in to comment.