Skip to content

Commit dc4d236

Browse files
authored
Update interpreter and test suite for table64 (WebAssembly#53)
1 parent 9ed8215 commit dc4d236

22 files changed

+329
-152
lines changed

.github/workflows/ci-interpreter.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ jobs:
3131
- name: Build interpreter
3232
run: cd interpreter && opam exec make
3333
- name: Run tests
34-
run: cd interpreter && opam exec make JS="node --experimental-wasm-memory64" ci
34+
# Re-enable the JS tests once table64 is available under node
35+
#run: cd interpreter && opam exec make JS="node --experimental-wasm-memory64" ci
36+
run: cd interpreter && opam exec make ci

interpreter/binary/decode.ml

+2-3
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,8 @@ let limits uN s =
190190

191191
let table_type s =
192192
let t = ref_type s in
193-
let lim, is64 = limits u32 s in
194-
require (not is64) s (pos s - 1) "tables cannot have 64-bit indices";
195-
TableType (lim, t)
193+
let lim, is64 = limits u64 s in
194+
TableType (lim, (if is64 then I64IndexType else I32IndexType), t)
196195

197196
let memory_type s =
198197
let lim, is64 = limits u64 s in

interpreter/binary/encode.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ struct
123123
byte flags; vu min; opt vu max
124124

125125
let table_type = function
126-
| TableType (lim, t) -> ref_type t; limits u32 lim I32IndexType
126+
| TableType (lim, it, t) -> ref_type t; limits u64 lim it
127127

128128
let memory_type = function
129129
| MemoryType (lim, it) -> limits u64 lim it

interpreter/exec/eval.ml

+57-45
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ let local (frame : frame) x = lookup "local" frame.locals x
9393

9494
let any_ref inst x i at =
9595
try Table.load (table inst x) i with Table.Bounds ->
96-
Trap.error at ("undefined element " ^ Int32.to_string i)
96+
Trap.error at ("undefined element " ^ Int64.to_string i)
9797

9898
let func_ref inst x i at =
9999
match any_ref inst x i at with
100100
| FuncRef f -> f
101-
| NullRef _ -> Trap.error at ("uninitialized element " ^ Int32.to_string i)
102-
| _ -> Crash.error at ("type mismatch for element " ^ Int32.to_string i)
101+
| NullRef _ -> Trap.error at ("uninitialized element " ^ Int64.to_string i)
102+
| _ -> Crash.error at ("type mismatch for element " ^ Int64.to_string i)
103103

104104
let func_type_of = function
105105
| Func.AstFunc (t, inst, f) -> t
@@ -140,12 +140,12 @@ let data_oob frame x i n =
140140
(Data.size (data frame.inst x))
141141

142142
let table_oob frame x i n =
143-
I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n))
144-
(I64_convert.extend_i32_u (Table.size (table frame.inst x)))
143+
I64.gt_u (I64.add (Table.index_of_num i) (Table.index_of_num n))
144+
(Table.size (table frame.inst x))
145145

146146
let elem_oob frame x i n =
147-
I64.gt_u (I64.add (I64_convert.extend_i32_u i) (I64_convert.extend_i32_u n))
148-
(I64_convert.extend_i32_u (Elem.size (elem frame.inst x)))
147+
I64.gt_u (I64.add (Table.index_of_num i) (Table.index_of_num n))
148+
(Elem.size (elem frame.inst x))
149149

150150
let inc_address i at =
151151
match i with
@@ -206,7 +206,8 @@ let rec step (c : config) : config =
206206
| Call x, vs ->
207207
vs, [Invoke (func frame.inst x) @@ e.at]
208208

209-
| CallIndirect (x, y), Num (I32 i) :: vs ->
209+
| CallIndirect (x, y), Num n :: vs ->
210+
let i = Table.index_of_num n in
210211
let func = func_ref frame.inst x i e.at in
211212
if type_ frame.inst y <> Func.type_of func then
212213
vs, [Trapping "indirect call type mismatch" @@ e.at]
@@ -241,85 +242,96 @@ let rec step (c : config) : config =
241242
with Global.NotMutable -> Crash.error e.at "write to immutable global"
242243
| Global.Type -> Crash.error e.at "type mismatch at global write")
243244

244-
| TableGet x, Num (I32 i) :: vs' ->
245+
| TableGet x, Num n :: vs' ->
246+
let i = Table.index_of_num n in
245247
(try Ref (Table.load (table frame.inst x) i) :: vs', []
246248
with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
247249

248-
| TableSet x, Ref r :: Num (I32 i) :: vs' ->
250+
| TableSet x, Ref r :: Num n :: vs' ->
251+
let i = Table.index_of_num n in
249252
(try Table.store (table frame.inst x) i r; vs', []
250253
with exn -> vs', [Trapping (table_error e.at exn) @@ e.at])
251254

252255
| TableSize x, vs ->
253-
Num (I32 (Table.size (table frame.inst x))) :: vs, []
256+
let tab = table frame.inst x in
257+
value_of_index (Table.index_type_of tab) (Table.size (table frame.inst x)) :: vs, []
254258

255-
| TableGrow x, Num (I32 delta) :: Ref r :: vs' ->
259+
| TableGrow x, Num delta :: Ref r :: vs' ->
256260
let tab = table frame.inst x in
257261
let old_size = Table.size tab in
258262
let result =
259-
try Table.grow tab delta r; old_size
260-
with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1l
261-
in Num (I32 result) :: vs', []
263+
try Table.grow tab (Table.index_of_num delta) r; old_size
264+
with Table.SizeOverflow | Table.SizeLimit | Table.OutOfMemory -> -1L
265+
in (value_of_index (Table.index_type_of tab) result) :: vs', []
262266

263-
| TableFill x, Num (I32 n) :: Ref r :: Num (I32 i) :: vs' ->
267+
| TableFill x, Num n :: Ref r :: Num i :: vs' ->
268+
let n_64 = Table.index_of_num n in
264269
if table_oob frame x i n then
265270
vs', [Trapping (table_error e.at Table.Bounds) @@ e.at]
266-
else if n = 0l then
271+
else if n_64 = 0L then
267272
vs', []
268273
else
269-
let _ = assert (I32.lt_u i 0xffff_ffffl) in
274+
let i_64 = Table.index_of_num i in
275+
let _ = assert (I64.lt_u i_64 0xffff_ffff_ffff_ffffL) in
270276
vs', List.map (at e.at) [
271-
Plain (Const (I32 i @@ e.at));
277+
Plain (Const (I64 i_64 @@ e.at));
272278
Refer r;
273279
Plain (TableSet x);
274-
Plain (Const (I32 (I32.add i 1l) @@ e.at));
280+
Plain (Const (I64 (I64.add i_64 1L) @@ e.at));
275281
Refer r;
276-
Plain (Const (I32 (I32.sub n 1l) @@ e.at));
282+
Plain (Const (I64 (I64.sub n_64 1L) @@ e.at));
277283
Plain (TableFill x);
278284
]
279285

280-
| TableCopy (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' ->
286+
| TableCopy (x, y), Num n :: Num s :: Num d :: vs' ->
287+
let n_64 = Table.index_of_num n in
288+
let s_64 = Table.index_of_num s in
289+
let d_64 = Table.index_of_num d in
281290
if table_oob frame x d n || table_oob frame y s n then
282291
vs', [Trapping (table_error e.at Table.Bounds) @@ e.at]
283-
else if n = 0l then
292+
else if n_64 = 0L then
284293
vs', []
285-
else if I32.le_u d s then
294+
else if I64.le_u d_64 s_64 then
286295
vs', List.map (at e.at) [
287-
Plain (Const (I32 d @@ e.at));
288-
Plain (Const (I32 s @@ e.at));
296+
Plain (Const (I64 d_64 @@ e.at));
297+
Plain (Const (I64 s_64 @@ e.at));
289298
Plain (TableGet y);
290299
Plain (TableSet x);
291-
Plain (Const (I32 (I32.add d 1l) @@ e.at));
292-
Plain (Const (I32 (I32.add s 1l) @@ e.at));
293-
Plain (Const (I32 (I32.sub n 1l) @@ e.at));
300+
Plain (Const (I64 (I64.add d_64 1L) @@ e.at));
301+
Plain (Const (I64 (I64.add s_64 1L) @@ e.at));
302+
Plain (Const (I64 (I64.sub n_64 1L) @@ e.at));
294303
Plain (TableCopy (x, y));
295304
]
296305
else (* d > s *)
297-
let n' = I32.sub n 1l in
306+
let n' = I64.sub n_64 1L in
298307
vs', List.map (at e.at) [
299-
Plain (Const (I32 (I32.add d n') @@ e.at));
300-
Plain (Const (I32 (I32.add s n') @@ e.at));
308+
Plain (Const (I64 (I64.add d_64 n') @@ e.at));
309+
Plain (Const (I64 (I64.add s_64 n') @@ e.at));
301310
Plain (TableGet y);
302311
Plain (TableSet x);
303-
Plain (Const (I32 d @@ e.at));
304-
Plain (Const (I32 s @@ e.at));
305-
Plain (Const (I32 n' @@ e.at));
312+
Plain (Const (I64 d_64 @@ e.at));
313+
Plain (Const (I64 s_64 @@ e.at));
314+
Plain (Const (I64 n' @@ e.at));
306315
Plain (TableCopy (x, y));
307316
]
308317

309-
| TableInit (x, y), Num (I32 n) :: Num (I32 s) :: Num (I32 d) :: vs' ->
318+
| TableInit (x, y), Num n :: Num s :: Num d :: vs' ->
319+
let n_64 = Table.index_of_num n in
310320
if table_oob frame x d n || elem_oob frame y s n then
311321
vs', [Trapping (table_error e.at Table.Bounds) @@ e.at]
312-
else if n = 0l then
322+
else if n_64 = 0L then
313323
vs', []
314324
else
325+
let d_64 = Table.index_of_num d in
326+
let s_64 = Table.index_of_num s in
315327
let seg = elem frame.inst y in
316328
vs', List.map (at e.at) [
317-
Plain (Const (I32 d @@ e.at));
318-
Refer (Elem.load seg s);
329+
Plain (Const (I64 d_64 @@ e.at));
330+
Refer (Elem.load seg s_64);
319331
Plain (TableSet x);
320-
Plain (Const (I32 (I32.add d 1l) @@ e.at));
321-
Plain (Const (I32 (I32.add s 1l) @@ e.at));
322-
Plain (Const (I32 (I32.sub n 1l) @@ e.at));
332+
Plain (Const (I64 (I64.add d_64 1L) @@ e.at));
333+
Plain (Const (I64 (I64.add s_64 1L) @@ e.at));
334+
Plain (Const (I64 (I64.sub n_64 1L) @@ e.at));
323335
Plain (TableInit (x, y));
324336
]
325337

@@ -411,15 +423,15 @@ let rec step (c : config) : config =
411423
| MemorySize, vs ->
412424
let mem = memory frame.inst (0l @@ e.at) in
413425

414-
Memory.value_of_address (Memory.index_of mem) (Memory.size mem) :: vs, []
426+
value_of_index (Memory.index_type_of mem) (Memory.size mem) :: vs, []
415427

416428
| MemoryGrow, Num delta :: vs' ->
417429
let mem = memory frame.inst (0l @@ e.at) in
418430
let old_size = Memory.size mem in
419431
let result =
420432
try Memory.grow mem (Memory.address_of_num delta); old_size
421433
with Memory.SizeOverflow | Memory.SizeLimit | Memory.OutOfMemory -> -1L
422-
in (Memory.value_of_address (Memory.index_of mem) result) :: vs', []
434+
in (value_of_index (Memory.index_type_of mem) result) :: vs', []
423435

424436
| MemoryFill, Num n :: Num k :: Num i :: vs' ->
425437
let n_64 = Memory.address_of_num n in
@@ -709,7 +721,7 @@ let create_func (inst : module_inst) (f : func) : func_inst =
709721

710722
let create_table (inst : module_inst) (tab : table) : table_inst =
711723
let {ttype} = tab.it in
712-
let TableType (_lim, t) = ttype in
724+
let TableType (_lim, _it, t) = ttype in
713725
Table.alloc ttype (NullRef t)
714726

715727
let create_memory (inst : module_inst) (mem : memory) : memory_inst =

interpreter/host/spectest.ml

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ let global (GlobalType (t, _) as gt) =
1919
in Global.alloc gt v
2020

2121
let table =
22-
Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType))
22+
Table.alloc (TableType ({min = 10L; max = Some 20L}, I32IndexType, FuncRefType))
23+
(NullRef FuncRefType)
24+
let table64 =
25+
Table.alloc (TableType ({min = 10L; max = Some 20L}, I64IndexType, FuncRefType))
2326
(NullRef FuncRefType)
2427
let memory = Memory.alloc (MemoryType ({min = 1L; max = Some 2L}, I32IndexType))
2528
let func f t = Func.alloc_host t (f t)
@@ -51,5 +54,6 @@ let lookup name t =
5154
| "global_f32", _ -> ExternGlobal (global (GlobalType (NumType F32Type, Immutable)))
5255
| "global_f64", _ -> ExternGlobal (global (GlobalType (NumType F64Type, Immutable)))
5356
| "table", _ -> ExternTable table
57+
| "table64", _ -> ExternTable table64
5458
| "memory", _ -> ExternMemory memory
5559
| _ -> raise Not_found

interpreter/runtime/elem.ml

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ type t = elem
44
exception Bounds
55

66
let alloc rs = ref rs
7-
let size seg = Lib.List32.length !seg
7+
let size seg = Lib.List64.length !seg
88

99
let load seg i =
10-
if i < 0l || i >= Lib.List32.length !seg then raise Bounds;
11-
Lib.List32.nth !seg i
10+
if i < 0L || i >= Lib.List64.length !seg then raise Bounds;
11+
Lib.List64.nth !seg i
1212

1313
let drop seg = seg := []

interpreter/runtime/memory.ml

+2-7
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,9 @@ let size mem =
4747
let type_of mem =
4848
mem.ty
4949

50-
let index_of mem =
50+
let index_type_of mem =
5151
let (MemoryType (_, it)) = type_of mem in it
5252

53-
let value_of_address it x =
54-
match it with
55-
| I64IndexType -> Num (I64 x)
56-
| I32IndexType -> Num (I32 (Int64.to_int32 x))
57-
5853
let address_of_num x =
5954
match x with
6055
| I64 i -> i
@@ -74,7 +69,7 @@ let grow mem delta =
7469
if I64.gt_u old_size new_size then raise SizeOverflow else
7570
let lim' = {lim with min = new_size} in
7671
if not (valid_limits lim') then raise SizeLimit else
77-
let after = create new_size (index_of mem) in
72+
let after = create new_size (index_type_of mem) in
7873
let dim = Array1_64.dim mem.content in
7974
Array1.blit (Array1_64.sub mem.content 0L dim) (Array1_64.sub after 0L dim);
8075
mem.ty <- MemoryType (lim', it);

interpreter/runtime/memory.mli

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ val page_size : int64
1919

2020
val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *)
2121
val type_of : memory -> memory_type
22-
val index_of : memory -> index_type
22+
val index_type_of : memory -> index_type
2323
val size : memory -> size
2424
val bound : memory -> address
25-
val value_of_address : index_type -> address -> value
2625
val address_of_value : value -> address
2726
val address_of_num : num -> address
2827
val grow : memory -> size -> unit

interpreter/runtime/table.ml

+33-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
open Types
22
open Values
33

4-
type size = int32
5-
type index = int32
4+
type size = int64
5+
type index = int64
66
type count = int32
77

88
type table = {mutable ty : table_type; mutable content : ref_ array}
@@ -17,47 +17,62 @@ exception OutOfMemory
1717
let valid_limits {min; max} =
1818
match max with
1919
| None -> true
20-
| Some m -> I32.le_u min m
20+
| Some m -> I64.le_u min m
21+
22+
let valid_index it i =
23+
match it with
24+
| I32IndexType -> I64.le_u i 0xffff_ffffL
25+
| I64IndexType -> true
2126

2227
let create size r =
23-
try Lib.Array32.make size r
28+
try Lib.Array64.make size r
2429
with Out_of_memory | Invalid_argument _ -> raise OutOfMemory
2530

26-
let alloc (TableType (lim, _) as ty) r =
31+
let alloc (TableType (lim, it, _) as ty) r =
2732
if not (valid_limits lim) then raise Type;
2833
{ty; content = create lim.min r}
2934

3035
let size tab =
31-
Lib.Array32.length tab.content
36+
Lib.Array64.length tab.content
3237

3338
let type_of tab =
3439
tab.ty
3540

41+
let index_type_of tab =
42+
let (TableType (_, it, _)) = type_of tab in it
43+
44+
let index_of_num x =
45+
match x with
46+
| I64 i -> i
47+
| I32 i -> I64_convert.extend_i32_u i
48+
| _ -> raise Type
49+
3650
let grow tab delta r =
37-
let TableType (lim, t) = tab.ty in
51+
let TableType (lim, it, t) = tab.ty in
3852
assert (lim.min = size tab);
3953
let old_size = lim.min in
40-
let new_size = Int32.add old_size delta in
41-
if I32.gt_u old_size new_size then raise SizeOverflow else
54+
let new_size = Int64.add old_size delta in
55+
if I64.gt_u old_size new_size then raise SizeOverflow else
4256
let lim' = {lim with min = new_size} in
57+
if not (valid_index it new_size) then raise SizeOverflow else
4358
if not (valid_limits lim') then raise SizeLimit else
4459
let after = create new_size r in
4560
Array.blit tab.content 0 after 0 (Array.length tab.content);
46-
tab.ty <- TableType (lim', t);
61+
tab.ty <- TableType (lim', it, t);
4762
tab.content <- after
4863

4964
let load tab i =
50-
if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds;
51-
Lib.Array32.get tab.content i
65+
if i < 0L || i >= Lib.Array64.length tab.content then raise Bounds;
66+
Lib.Array64.get tab.content i
5267

5368
let store tab i r =
54-
let TableType (lim, t) = tab.ty in
69+
let TableType (_lim, _it, t) = tab.ty in
5570
if type_of_ref r <> t then raise Type;
56-
if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds;
57-
Lib.Array32.set tab.content i r
71+
if i < 0L || i >= Lib.Array64.length tab.content then raise Bounds;
72+
Lib.Array64.set tab.content i r
5873

5974
let blit tab offset rs =
6075
let data = Array.of_list rs in
61-
let len = Lib.Array32.length data in
62-
if offset < 0l || offset > Int32.sub (Lib.Array32.length tab.content) len then raise Bounds;
63-
Lib.Array32.blit data 0l tab.content offset len
76+
let len = Lib.Array64.length data in
77+
if offset < 0L || offset > Int64.sub (Lib.Array64.length tab.content) len then raise Bounds;
78+
Lib.Array64.blit data 0L tab.content offset len

0 commit comments

Comments
 (0)