Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 6e728c0

Browse files
authored
[interpreter/test] Implement new array allocation instructions (#283)
1 parent fc5c49e commit 6e728c0

32 files changed

+496
-190
lines changed

interpreter/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,9 @@ op:
304304
struct.get(_<sign>)? <var> <var>
305305
struct.set <var> <var>
306306
array.new(_<default>)? <var>
307+
array.new_fixed <var> <nat>
308+
array.new_elem <var> <var>
309+
array.new_data <var> <var>
307310
array.get(_<sign>)? <var>
308311
array.set <var>
309312
array.len <var>

interpreter/binary/decode.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,10 @@ let rec instr s =
593593
| 0x16l -> array_set (at var s)
594594
| 0x17l -> let _ = var s in array_len (* TODO: remove var *)
595595

596+
| 0x19l -> let x = at var s in let n = u32 s in array_new_fixed x n
597+
| 0x1bl -> let x = at var s in let y = at var s in array_new_data x y
598+
| 0x1cl -> let x = at var s in let y = at var s in array_new_elem x y
599+
596600
| 0x20l -> i31_new
597601
| 0x21l -> i31_get_s
598602
| 0x22l -> i31_get_u

interpreter/binary/encode.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ struct
397397

398398
| ArrayNew (x, Explicit) -> op 0xfb; op 0x11; var x
399399
| ArrayNew (x, Implicit) -> op 0xfb; op 0x12; var x
400+
| ArrayNewFixed (x, n) -> op 0xfb; op 0x19; var x; u32 n
401+
| ArrayNewElem (x, y) -> op 0xfb; op 0x1c; var x; var y
402+
| ArrayNewData (x, y) -> op 0xfb; op 0x1b; var x; var y
400403
| ArrayGet (x, None) -> op 0xfb; op 0x13; var x
401404
| ArrayGet (x, Some SX) -> op 0xfb; op 0x14; var x
402405
| ArrayGet (x, Some ZX) -> op 0xfb; op 0x15; var x

interpreter/exec/eval.ml

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,13 @@ let rec step (c : config) : config =
173173
let FuncType (ts1, ts2) = block_type c.frame.inst bt e.at in
174174
let n1 = List.length ts1 in
175175
let n2 = List.length ts2 in
176-
let args, vs' = take n1 vs e.at, drop n1 vs e.at in
176+
let args, vs' = split n1 vs e.at in
177177
vs', [Label (n2, [], (args, List.map plain es')) @@ e.at]
178178

179179
| Loop (bt, es'), vs ->
180180
let FuncType (ts1, ts2) = block_type c.frame.inst bt e.at in
181181
let n1 = List.length ts1 in
182-
let args, vs' = take n1 vs e.at, drop n1 vs e.at in
182+
let args, vs' = split n1 vs e.at in
183183
vs', [Label (n1, [e' @@ e.at], (args, List.map plain es')) @@ e.at]
184184

185185
| If (bt, es1, es2), Num (I32 i) :: vs' ->
@@ -813,11 +813,66 @@ let rec step (c : config) : config =
813813
try default_value (unpacked_storage_type st), vs'
814814
with Failure _ -> Crash.error e.at "non-defaultable type"
815815
in
816-
let data =
817-
try Data.alloc_array (type_ c.frame.inst x) rtt n arg
816+
let data =
817+
try Data.alloc_array (type_ c.frame.inst x) rtt (Lib.List32.make n arg)
818818
with Failure _ -> Crash.error e.at "type mismatch packing value"
819819
in Ref (Data.DataRef data) :: vs'', []
820820

821+
| ArrayNewFixed (x, n), Ref (Rtt.RttRef rtt) :: vs' ->
822+
let args, vs'' = split (I32.to_int_u n) vs' e.at in
823+
let data =
824+
try Data.alloc_array (type_ c.frame.inst x) rtt (List.rev args)
825+
with Failure _ -> Crash.error e.at "type mismatch packing value"
826+
in Ref (Data.DataRef data) :: vs'', []
827+
828+
| ArrayNewElem (x, y),
829+
Ref (Rtt.RttRef rtt) :: Num (I32 n) :: Num (I32 s) :: vs' ->
830+
if elem_oob c.frame y s n then
831+
vs', [Trapping (table_error e.at Table.Bounds) @@ e.at]
832+
else
833+
let seg = elem c.frame.inst y in
834+
let args =
835+
List.map (fun r -> Ref r) (Lib.List32.take n (Lib.List32.drop s !seg)) in
836+
let data =
837+
try Data.alloc_array (type_ c.frame.inst x) rtt args
838+
with Failure _ -> Crash.error e.at "type mismatch packing value"
839+
in Ref (Data.DataRef data) :: vs', []
840+
841+
| ArrayNewData (x, y),
842+
Ref (Rtt.RttRef rtt) :: Num (I32 n) :: Num (I32 s) :: vs' ->
843+
if data_oob c.frame y s n then
844+
vs', [Trapping (memory_error e.at Memory.Bounds) @@ e.at]
845+
else
846+
let ArrayType (FieldType (st, _)) = array_type c.frame.inst x in
847+
let seg = data c.frame.inst y in
848+
let bs = Bytes.of_string !seg in
849+
let args = Lib.List32.init n
850+
(fun i ->
851+
let j = I32.to_int_u s + I32.to_int_u i * storage_size st in
852+
match st with
853+
| PackedStorageType Pack8 ->
854+
Num (I32 (I32.of_int_u (Bytes.get_uint8 bs j)))
855+
| PackedStorageType Pack16 ->
856+
Num (I32 (I32.of_int_u (Bytes.get_uint16_le bs j)))
857+
| ValueStorageType (NumType I32Type) ->
858+
Num (I32 (Bytes.get_int32_le bs j))
859+
| ValueStorageType (NumType I64Type) ->
860+
Num (I64 (Bytes.get_int64_le bs j))
861+
| ValueStorageType (NumType F32Type) ->
862+
Num (F32 (F32.of_bits (Bytes.get_int32_le bs j)))
863+
| ValueStorageType (NumType F64Type) ->
864+
Num (F64 (F64.of_bits (Bytes.get_int64_le bs j)))
865+
| ValueStorageType (VecType V128Type) ->
866+
Vec (V128 (V128.of_bits (String.sub !seg j 16)))
867+
| _ ->
868+
Crash.error e.at "type mismatch packing value"
869+
)
870+
in
871+
let data =
872+
try Data.alloc_array (type_ c.frame.inst x) rtt args
873+
with Failure _ -> Crash.error e.at "type mismatch packing value"
874+
in Ref (Data.DataRef data) :: vs', []
875+
821876
| ArrayGet (x, exto), Num (I32 i) :: Ref (NullRef _) :: vs' ->
822877
vs', [Trapping "null array reference" @@ e.at]
823878

interpreter/runtime/data.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ let alloc_struct x rtt vs =
4343
let StructType fts = as_struct_str_type (expand_ctx_type (def_of x)) in
4444
Struct (x, rtt, List.map2 alloc_field fts vs)
4545

46-
let alloc_array x rtt n v =
46+
let alloc_array x rtt vs =
4747
let ArrayType ft = as_array_str_type (expand_ctx_type (def_of x)) in
48-
Array (x, rtt, List.init (Int32.to_int n) (fun _ -> alloc_field ft v))
48+
Array (x, rtt, List.map (alloc_field ft) vs)
4949

5050

5151
let type_inst_of = function

interpreter/runtime/data.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type t = data
1414
type ref_ += DataRef of data
1515

1616
val alloc_struct : sem_var -> Rtt.t -> value list -> data
17-
val alloc_array : sem_var -> Rtt.t -> int32 -> value -> data
17+
val alloc_array : sem_var -> Rtt.t -> value list -> data
1818

1919
val struct_type_of : data -> struct_type
2020
val array_type_of : data -> array_type

interpreter/syntax/ast.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ and instr' =
205205
| StructGet of idx * idx * extension option (* read structure field *)
206206
| StructSet of idx * idx (* write structure field *)
207207
| ArrayNew of idx * initop (* allocate array *)
208+
| ArrayNewFixed of idx * int32 (* allocate fixed array *)
209+
| ArrayNewElem of idx * idx (* allocate array from element segment *)
210+
| ArrayNewData of idx * idx (* allocate array from data segment *)
208211
| ArrayGet of idx * extension option (* read array slot *)
209212
| ArraySet of idx (* write array slot *)
210213
| ArrayLen (* read array length *)

interpreter/syntax/free.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ let rec instr (e : instr) =
123123
| RefNull t -> heap_type t
124124
| RefFunc x -> funcs (idx x)
125125
| I31New | I31Get _ -> empty
126-
| StructNew (x, _) | ArrayNew (x, _) -> types (idx x)
126+
| StructNew (x, _) | ArrayNew (x, _) | ArrayNewFixed (x, _) -> types (idx x)
127+
| ArrayNewElem (x, y) -> types (idx x) ++ elems (idx y)
128+
| ArrayNewData (x, y) -> types (idx x) ++ datas (idx y)
127129
| StructGet (x, _, _) | StructSet (x, _) -> types (idx x)
128130
| ArrayGet (x, _) | ArraySet x -> types (idx x)
129131
| ArrayLen -> empty

interpreter/syntax/operators.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ let struct_get_s x y = StructGet (x, y, Some SX)
133133
let struct_set x y = StructSet (x, y)
134134
let array_new x = ArrayNew (x, Explicit)
135135
let array_new_default x = ArrayNew (x, Implicit)
136+
let array_new_fixed x n = ArrayNewFixed (x, n)
137+
let array_new_elem x y = ArrayNewElem (x, y)
138+
let array_new_data x y = ArrayNewData (x, y)
136139
let array_get x = ArrayGet (x, None)
137140
let array_get_u x = ArrayGet (x, Some ZX)
138141
let array_get_s x = ArrayGet (x, Some SX)

interpreter/syntax/types.ml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ let num_size = function
7979
let vec_size = function
8080
| V128Type -> 16
8181

82+
let value_size = function
83+
| NumType t -> num_size t
84+
| VecType t -> vec_size t
85+
| RefType _ | BotType -> failwith "value_size"
86+
8287
let packed_size = function
8388
| Pack8 -> 1
8489
| Pack16 -> 2
@@ -88,11 +93,9 @@ let packed_size = function
8893
let packed_shape_size = function
8994
| Pack8x8 | Pack16x4 | Pack32x2 -> 8
9095

91-
92-
let is_packed_storage_type = function
93-
| ValueStorageType _ -> false
94-
| PackedStorageType _ -> true
95-
96+
let storage_size = function
97+
| PackedStorageType pt -> packed_size pt
98+
| ValueStorageType t -> value_size t
9699

97100
let is_syn_var = function SynVar _ -> true | _ -> false
98101
let is_sem_var = function SemVar _ -> true | _ -> false
@@ -132,6 +135,11 @@ let defaultable_value_type = function
132135
| BotType -> assert false
133136

134137

138+
let is_packed_storage_type = function
139+
| ValueStorageType _ -> false
140+
| PackedStorageType _ -> true
141+
142+
135143
(* Projections *)
136144

137145
let unpacked_storage_type = function

interpreter/text/arrange.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,9 @@ let rec instr e =
547547
"struct.get" ^ opt_s extension exto ^ " " ^ var x ^ " " ^ var y, []
548548
| StructSet (x, y) -> "struct.set " ^ var x ^ " " ^ var y, []
549549
| ArrayNew (x, op) -> "array.new" ^ initop op ^ " " ^ var x, []
550+
| ArrayNewFixed (x, n) -> "array.new_fixed " ^ var x ^ " " ^ nat32 n, []
551+
| ArrayNewElem (x, y) -> "array.new_elem " ^ var x ^ " " ^ var y, []
552+
| ArrayNewData (x, y) -> "array.new_data " ^ var x ^ " " ^ var y, []
550553
| ArrayGet (x, exto) -> "array.get" ^ opt_s extension exto ^ " " ^ var x, []
551554
| ArraySet x -> "array.set " ^ var x, []
552555
| ArrayLen -> "array.len", []

interpreter/text/lexer.mll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ rule token = parse
296296

297297
| "array.new" { ARRAY_NEW array_new }
298298
| "array.new_default" { ARRAY_NEW array_new_default }
299+
| "array.new_fixed" { ARRAY_NEW_FIXED }
300+
| "array.new_elem" { ARRAY_NEW_ELEM }
301+
| "array.new_data" { ARRAY_NEW_DATA }
299302
| "array.get" { ARRAY_GET array_get }
300303
| "array.get_"(sign as s) { ARRAY_GET (ext s array_get_s array_get_u) }
301304
| "array.set" { ARRAY_SET }

interpreter/text/parser.mly

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ let inline_func_type_explicit (c : context) x ft at =
272272
%token REF_NULL REF_FUNC REF_I31 REF_DATA REF_ARRAY REF_EXTERN
273273
%token REF_TEST REF_CAST REF_EQ
274274
%token I31_NEW I32_GET
275-
%token STRUCT_NEW STRUCT_GET STRUCT_SET ARRAY_NEW ARRAY_GET ARRAY_SET ARRAY_LEN
275+
%token STRUCT_NEW STRUCT_GET STRUCT_SET
276+
%token ARRAY_NEW ARRAY_NEW_FIXED ARRAY_NEW_ELEM ARRAY_NEW_DATA
277+
%token ARRAY_GET ARRAY_SET ARRAY_LEN
276278
%token RTT_CANON
277279
%token VEC_LOAD VEC_STORE VEC_LOAD_LANE VEC_STORE_LANE
278280
%token VEC_CONST VEC_UNARY VEC_BINARY VEC_TERNARY VEC_TEST
@@ -461,6 +463,9 @@ type_use :
461463

462464
/* Immediates */
463465

466+
nat32 :
467+
| NAT { nat32 $1 (at ()) }
468+
464469
num :
465470
| NAT { $1 @@ at () }
466471
| INT { $1 @@ at () }
@@ -586,6 +591,9 @@ plain_instr :
586591
| STRUCT_GET var var { fun c -> $1 ($2 c type_) ($3 c field) }
587592
| STRUCT_SET var var { fun c -> struct_set ($2 c type_) ($3 c field) }
588593
| ARRAY_NEW var { fun c -> $1 ($2 c type_) }
594+
| ARRAY_NEW_FIXED var nat32 { fun c -> array_new_fixed ($2 c type_) $3 }
595+
| ARRAY_NEW_ELEM var var { fun c -> array_new_elem ($2 c type_) ($3 c elem) }
596+
| ARRAY_NEW_DATA var var { fun c -> array_new_data ($2 c type_) ($3 c data) }
589597
| ARRAY_GET var { fun c -> $1 ($2 c type_) }
590598
| ARRAY_SET var { fun c -> array_set ($2 c type_) }
591599
| ARRAY_LEN { fun c -> array_len }

interpreter/util/lib.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ end
130130

131131
module List32 =
132132
struct
133+
let rec init n f = init' n f []
134+
and init' n f xs =
135+
if n = 0l then xs else init' (Int32.sub n 1l) f (f (Int32.sub n 1l) :: xs)
136+
133137
let rec make n x = make' n x []
134138
and make' n x xs =
135139
if n = 0l then xs else make' (Int32.sub n 1l) x (x::xs)

interpreter/util/lib.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ end
3333

3434
module List32 :
3535
sig
36+
val init : int32 -> (int32 -> 'a) -> 'a list
3637
val make : int32 -> 'a -> 'a list
3738
val length : 'a list -> int32
3839
val nth : 'a list -> int32 -> 'a (* raises Failure *)

interpreter/valid/valid.ml

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,8 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type
755755
let StructType fts = struct_type c x in
756756
require
757757
( initop = Explicit || List.for_all (fun ft ->
758-
defaultable_value_type (unpacked_field_type ft)) fts ) e.at
759-
("field type is not defaultable");
758+
defaultable_value_type (unpacked_field_type ft)) fts ) x.at
759+
"field type is not defaultable";
760760
let ts = if initop = Implicit then [] else List.map unpacked_field_type fts in
761761
(ts @ [RefType (NonNullable, RttHeapType (SynVar x.it))]) -->
762762
[RefType (NonNullable, DefHeapType (SynVar x.it))]
@@ -784,12 +784,35 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type
784784
let ArrayType ft = array_type c x in
785785
require
786786
( initop = Explicit ||
787-
defaultable_value_type (unpacked_field_type ft) ) e.at
788-
("array type is not defaultable");
787+
defaultable_value_type (unpacked_field_type ft) ) x.at
788+
"array type is not defaultable";
789789
let ts = if initop = Implicit then [] else [unpacked_field_type ft] in
790790
(ts @ [NumType I32Type; RefType (NonNullable, RttHeapType (SynVar x.it))]) -->
791791
[RefType (NonNullable, DefHeapType (SynVar x.it))]
792792

793+
| ArrayNewFixed (x, n) ->
794+
let ArrayType ft = array_type c x in
795+
let ts = Lib.List32.make n (unpacked_field_type ft) in
796+
(ts @ [RefType (NonNullable, RttHeapType (SynVar x.it))]) -->
797+
[RefType (NonNullable, DefHeapType (SynVar x.it))]
798+
799+
| ArrayNewElem (x, y) ->
800+
let ArrayType ft = array_type c x in
801+
let rt = elem c y in
802+
require (match_value_type c.types (RefType rt) (unpacked_field_type ft)) x.at
803+
("type mismatch: element segment's type " ^ string_of_ref_type rt ^
804+
" does not match array's field type " ^ string_of_field_type ft);
805+
[NumType I32Type; NumType I32Type; RefType (NonNullable, RttHeapType (SynVar x.it))] -->
806+
[RefType (NonNullable, DefHeapType (SynVar x.it))]
807+
808+
| ArrayNewData (x, y) ->
809+
let ArrayType ft = array_type c x in
810+
let () = data c y in
811+
require (is_num_type (unpacked_field_type ft)) x.at
812+
"array type is not numeric";
813+
[NumType I32Type; NumType I32Type; RefType (NonNullable, RttHeapType (SynVar x.it))] -->
814+
[RefType (NonNullable, DefHeapType (SynVar x.it))]
815+
793816
| ArrayGet (x, exto) ->
794817
let ArrayType (FieldType (st, _)) = array_type c x in
795818
require ((exto <> None) == is_packed_storage_type st) e.at
@@ -953,11 +976,9 @@ let check_func (c : context) (f : func) =
953976

954977
let is_const (c : context) (e : instr) =
955978
match e.it with
956-
| Const _
957-
| VecConst _
958-
| I31New
959-
| RefNull _
960-
| RefFunc _
979+
| Const _ | VecConst _
980+
| RefNull _ | RefFunc _
981+
| I31New | StructNew _ | ArrayNew _ | ArrayNewFixed _
961982
| RttCanon _ -> true
962983
| GlobalGet x -> let GlobalType (_, mut) = global c x in mut = Immutable
963984
| _ -> false
@@ -1065,12 +1086,15 @@ let check_module (m : module_) =
10651086
funcs = c1.funcs @ List.map (fun f -> func_type c1 f.it.ftype) funcs;
10661087
tables = c1.tables @ List.map (fun tab -> tab.it.ttype) tables;
10671088
memories = c1.memories @ List.map (fun mem -> mem.it.mtype) memories;
1089+
refs = Free.module_ ({m.it with funcs = []; start = None} @@ m.at);
1090+
}
1091+
in
1092+
let c =
1093+
{ (List.fold_left check_global c2 globals) with
10681094
elems = List.map (fun elem -> elem.it.etype) elems;
10691095
datas = List.map (fun _data -> ()) datas;
1070-
refs = Free.module_ ({m.it with funcs = []; start = None} @@ m.at);
10711096
}
10721097
in
1073-
let c = List.fold_left check_global c2 globals in
10741098
List.iter (check_table c) tables;
10751099
List.iter (check_memory c) memories;
10761100
List.iter (check_elem c) elems;

0 commit comments

Comments
 (0)