diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index fc512f56a..edcd1bb5f 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -629,6 +629,8 @@ let rec instr s = (match u32 s with | 0x00l -> let x = at idx s in struct_new x | 0x01l -> let x = at idx s in struct_new_default x + | 0x20l -> let x = at idx s in struct_new_desc x + | 0x21l -> let x = at idx s in struct_new_default_desc x | 0x02l -> let x = at idx s in let i = idx s in struct_get x i | 0x03l -> let x = at idx s in let i = idx s in struct_get_s x i | 0x04l -> let x = at idx s in let i = idx s in struct_get_u x i diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 07792bcdf..14313a934 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -445,8 +445,10 @@ struct | I31Get S -> op 0xfb; op 0x1d | I31Get U -> op 0xfb; op 0x1e - | StructNew (x, Explicit) -> op 0xfb; op 0x00; idx x - | StructNew (x, Implicit) -> op 0xfb; op 0x01; idx x + | StructNew (x, Explicit, NoDesc) -> op 0xfb; op 0x00; idx x + | StructNew (x, Implicit, NoDesc) -> op 0xfb; op 0x01; idx x + | StructNew (x, Explicit, Desc) -> op 0xfb; op 0x20; idx x + | StructNew (x, Implicit, Desc) -> op 0xfb; op 0x21; idx x | StructGet (x, i, None) -> op 0xfb; op 0x02; idx x; u32 i | StructGet (x, i, Some S) -> op 0xfb; op 0x03; idx x; u32 i | StructGet (x, i, Some U) -> op 0xfb; op 0x04; idx x; u32 i diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 57305bec9..fc0e2e30c 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -110,7 +110,6 @@ let data (inst : moduleinst) x = lookup "data segment" inst.datas x let elem (inst : moduleinst) x = lookup "element segment" inst.elems x let local (frame : frame) x = lookup "local" frame.locals x -let desc_type (inst : moduleinst) x = expand_deftype_to_desctype (type_ inst x) let comp_type (inst : moduleinst) x = expand_deftype (type_ inst x) let struct_type (inst : moduleinst) x = structtype_of_comptype (comp_type inst x) let array_type (inst : moduleinst) x = arraytype_of_comptype (comp_type inst x) @@ -726,12 +725,11 @@ let rec step (c : config) : config = | I31Get ext, Ref (I31.I31Ref i) :: vs' -> Num (I32 (I31.to_i32 ext i)) :: vs', [] - | StructNew (x, initop), vs' -> - let DescT (_, dt, _) = desc_type c.frame.inst x in + | StructNew (x, initop, descop), vs' -> let desc, vs'' = - match dt, vs' with - | Some _, Ref desc :: vs'' -> Some desc, vs'' - | None, _ -> None, vs' + match descop, vs' with + | Desc, Ref desc :: vs'' -> Some desc, vs'' + | NoDesc, _ -> None, vs' | _ -> Crash.error e.at "missing descriptor" in let fts = struct_type c.frame.inst x in diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 387a9f381..049b278af 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -140,6 +140,7 @@ type vstoreop = (vectype, unit) memop type vlaneop = (vectype, packsize) memop type initop = Explicit | Implicit +type descop = Desc | NoDesc type externop = Internalize | Externalize @@ -229,7 +230,7 @@ and instr' = | RefEq (* reference equality *) | RefI31 (* scalar reference *) | I31Get of sx (* read scalar *) - | StructNew of typeidx * initop (* allocate structure *) + | StructNew of typeidx * initop * descop (* allocate structure *) | StructGet of typeidx * fieldidx * sx option (* read structure field *) | StructSet of typeidx * fieldidx (* write structure field *) | ArrayNew of typeidx * initop (* allocate array *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 8c4575492..cb6632ed4 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -175,7 +175,8 @@ let rec instr (e : instr) = | RefNull t -> heaptype t | RefFunc x -> funcs (idx x) | RefI31 | I31Get _ -> empty - | StructNew (x, _) | ArrayNew (x, _) | ArrayNewFixed (x, _) -> types (idx x) + | StructNew (x, _, _) | ArrayNew (x, _) | ArrayNewFixed (x, _) -> + types (idx x) | ArrayNewElem (x, y) -> types (idx x) ++ elems (idx y) | ArrayNewData (x, y) -> types (idx x) ++ datas (idx y) | StructGet (x, _, _) | StructSet (x, _) -> types (idx x) diff --git a/interpreter/syntax/mnemonics.ml b/interpreter/syntax/mnemonics.ml index d2aaecfda..7ae5b5266 100644 --- a/interpreter/syntax/mnemonics.ml +++ b/interpreter/syntax/mnemonics.ml @@ -182,8 +182,10 @@ let ref_eq = RefEq let ref_i31 = RefI31 let i31_get_u = I31Get U let i31_get_s = I31Get S -let struct_new x = StructNew (x, Explicit) -let struct_new_default x = StructNew (x, Implicit) +let struct_new x = StructNew (x, Explicit, NoDesc) +let struct_new_default x = StructNew (x, Implicit, NoDesc) +let struct_new_desc x = StructNew (x, Explicit, Desc) +let struct_new_default_desc x = StructNew (x, Implicit, Desc) let struct_get x y = StructGet (x, y, None) let struct_get_u x y = StructGet (x, y, Some U) let struct_get_s x y = StructGet (x, y, Some S) diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index c374be470..9a2850ed3 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -479,6 +479,10 @@ let initop = function | Explicit -> "" | Implicit -> "_default" +let descop = function + | Desc -> "_desc" + | NoDesc -> "" + let constop v = string_of_numtype (type_of_num v) ^ ".const" let vconstop v = string_of_vectype (type_of_vec v) ^ ".const i32x4" @@ -570,7 +574,8 @@ let rec instr e = | RefEq -> "ref.eq", [] | RefI31 -> "ref.i31", [] | I31Get sx -> "i31.get" ^ ext sx, [] - | StructNew (x, op) -> "struct.new" ^ initop op ^ " " ^ idx x, [] + | StructNew (x, init, desc) -> + "struct.new" ^ initop init ^ descop desc ^ " " ^ idx x, [] | StructGet (x, i, sxo) -> "struct.get" ^ opt_s ext sxo ^ " " ^ idx x ^ " " ^ nat32 i, [] | StructSet (x, i) -> "struct.set " ^ idx x ^ " " ^ nat32 i, [] diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index ffbe55b74..a6e25146b 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -350,6 +350,8 @@ rule token = parse | "struct.new" -> STRUCT_NEW struct_new | "struct.new_default" -> STRUCT_NEW struct_new_default + | "struct.new_desc" -> STRUCT_NEW struct_new_desc + | "struct.new_default_desc" -> STRUCT_NEW struct_new_default_desc | "struct.get" -> STRUCT_GET struct_get | "struct.get_u" -> STRUCT_GET struct_get_u | "struct.get_s" -> STRUCT_GET struct_get_s diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index ba62fc170..0dce3563e 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -875,7 +875,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins | I31Get ext -> [RefT (Null, I31HT)] --> [NumT I32T], [] - | StructNew (x, initop) -> + | StructNew (x, initop, descop) -> let fts = struct_type c x in require ( initop = Explicit || List.for_all (fun ft -> @@ -884,8 +884,14 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins let ts = if initop = Implicit then [] else List.map unpacked_fieldtype fts in let DescT (_, dt, _) = expand_deftype_to_desctype (type_ c x) in let dt = match dt with - | Some dt -> [RefT (Null, UseHT (Exact, dt))] - | None -> [] + | Some dt -> + require (descop = Desc) x.at + "type with descriptor requires descriptor allocation"; + [RefT (Null, UseHT (Exact, dt))] + | None -> + require (descop = NoDesc) x.at + "type without descriptor requires non-descriptor allocation"; + [] in (ts @ dt) --> [RefT (NoNull, UseHT (Exact, Def (type_ c x)))], [] diff --git a/proposals/custom-descriptors/Overview.md b/proposals/custom-descriptors/Overview.md index 25bcacea4..b20d8246d 100644 --- a/proposals/custom-descriptors/Overview.md +++ b/proposals/custom-descriptors/Overview.md @@ -21,16 +21,12 @@ to alleviate anticipated problems that will arise from the use of its primary fe to reduce startup time when there are many prototypes to populate. 2. A way to deduplicate lists of fields in type sections. - Using custom RTTs may otherwise lead to more duplication in the type section + Using custom descriptors may otherwise lead to more duplication in the type section than there is today. We should validate that these problem actually arise in practice and quantify their cost before we commit to including these extra solutions in the final version of the proposal. -This proposal and the custom descriptors are informally called "custom RTTs," -although the RTT is more precisely the engine-managed type information inside the custom descriptor, -not the custom descriptor itself. - ## Custom Descriptor Definitions Custom descriptor types are defined struct types with a `describes` clause saying @@ -40,8 +36,8 @@ what type their custom descriptors have. ```wasm (rec - (type $foo (descriptor $foo.rtt) (struct (field ...))) - (type $foo.rtt (describes $foo) (struct (field ...))) + (type $foo (descriptor $foo.desc) (struct (field ...))) + (type $foo.desc (describes $foo) (struct (field ...))) ) ``` @@ -59,19 +55,19 @@ but type `$C` is different. ```wasm (rec - (type $A (descriptor $A.rtt) (struct (field i32))) - (type $A.rtt (describes $A) (struct (field i32))) + (type $A (descriptor $A.desc) (struct (field i32))) + (type $A.desc (describes $A) (struct (field i32))) ) (rec - (type $B (descriptor $B.rtt) (struct (field i32))) - (type $B.rtt (describes $B) (struct (field i32))) + (type $B (descriptor $B.desc) (struct (field i32))) + (type $B.desc (describes $B) (struct (field i32))) ) (rec ;; Different: no describes or descriptor clauses. (type $C (struct (field i32))) - (type $C.rtt (struct (field i32))) + (type $C.desc (struct (field i32))) ) ``` @@ -80,9 +76,9 @@ creating arbitrarily long chains of meta-descriptors: ```wasm (rec - (type $foo (descriptor $foo.rtt) (struct)) - (type $foo.rtt (describes $foo) (descriptor $foo.meta-rtt) (struct)) - (type $foo.meta-rtt (describes $foo.rtt) (struct)) + (type $foo (descriptor $foo.desc) (struct)) + (type $foo.desc (describes $foo) (descriptor $foo.meta-desc) (struct)) + (type $foo.meta-desc (describes $foo.desc) (struct)) ) ``` @@ -123,8 +119,8 @@ This is the same strategy we use for ensuring supertype chains do not have cycle (type $pong (describes $ping) (descriptor $ping) (struct)) ;; Invalid describes clause: $foo is not a previously defined type. - (type $foo.rtt (describes $foo) (struct)) - (type $foo (descriptor $foo.rtt) (struct)) + (type $foo.desc (describes $foo) (struct)) + (type $foo (descriptor $foo.desc) (struct)) ) ``` @@ -165,50 +161,50 @@ might be laid out after the engine-managed RTT for the type they describe. ```wasm (rec - (type $super (sub (descriptor $super.rtt) (struct))) - (type $super.rtt (sub (describes $super) (struct))) + (type $super (sub (descriptor $super.desc) (struct))) + (type $super.desc (sub (describes $super) (struct))) ;; Ok - (type $sub (sub $super (descriptor $sub.rtt) (struct))) - (type $sub.rtt (sub $super.rtt (describes $sub) (struct))) + (type $sub (sub $super (descriptor $sub.desc) (struct))) + (type $sub.desc (sub $super.desc (describes $sub) (struct))) ) (rec (type $super (sub (struct))) ;; Ok - (type $sub (sub $super (descriptor $sub.rtt) (struct))) - (type $sub.rtt (describes $sub) (struct)) + (type $sub (sub $super (descriptor $sub.desc) (struct))) + (type $sub.desc (describes $sub) (struct)) ) (rec - (type $super (sub (descriptor $super.rtt) (struct ))) - (type $super.rtt (sub (describes $super) (struct))) + (type $super (sub (descriptor $super.desc) (struct ))) + (type $super.desc (sub (describes $super) (struct))) - (type $other (descriptor $sub.rtt) (struct)) + (type $other (descriptor $sub.desc) (struct)) ;; Invalid: Must describe an immediate subtype of $super. - (type $sub.rtt (sub $super.rtt (describes $other) (struct))) + (type $sub.desc (sub $super.desc (describes $other) (struct))) ) (rec - (type $super (sub (descriptor $super.rtt) (struct))) - (type $super.rtt (sub (describes $super) (struct))) + (type $super (sub (descriptor $super.desc) (struct))) + (type $super.desc (sub (describes $super) (struct))) - ;; Invalid: Must be described by an immediate subtype of $super.rtt. + ;; Invalid: Must be described by an immediate subtype of $super.desc. (type $sub (sub $super (struct))) ;; Invalid: Must describe an immediate subtype of $super. - (type $sub.rtt (sub $super.rtt (struct))) + (type $sub.desc (sub $super.desc (struct))) ) (rec - (type $super (sub (descriptor $super.rtt) (struct))) - (type $super.rtt (sub (describes $super) (struct))) + (type $super (sub (descriptor $super.desc) (struct))) + (type $super.desc (sub (describes $super) (struct))) - ;; Invalid: $other.rtt must be a an immediate subtype of $super.rtt. - (type $sub (sub $super (descriptor $other.rtt) (struct))) - (type $other.rtt (describes $sub) (struct)) + ;; Invalid: $other.desc must be a an immediate subtype of $super.desc. + (type $sub (sub $super (descriptor $other.desc) (struct))) + (type $other.desc (describes $sub) (struct)) ) ``` @@ -228,13 +224,79 @@ This may be relaxed in the future. ```wasm (rec ;; Invalid: descriptor clauses may only be used with structs. - (type $array (descriptor $array.rtt) (array i8)) + (type $array (descriptor $array.desc) (array i8)) ;; Invalid: describes clauses may only be used with structs. - (type $array.rtt (describes $array) (func)) + (type $array.desc (describes $array) (func)) +) +``` + +## Allocation With Descriptors + +`struct.new` and `struct.new_default` cannot be used +to allocate types with descriptors. +Instead, the new instructions `struct.new_desc` and +`struct.new_default_desc` must be used. +`struct.new_desc` and `struct.new_default_desc` take +exact references (described below) to the descriptors of the allocated type +as their last operands. + +```wasm +(rec + (type $A (descriptor $A.desc) (struct (field i32))) + (type $A.desc (describes $A) (struct (field i32))) +) + +(func $new (param $desc (ref null (exact $A.desc))) + (drop + ;; Valid + (struct.new_desc $A + (i32.const 1) + (local.get $desc) + ) + ) + (drop + ;; Valid + (struct.new_default_desc $A + (local.get $desc) + ) + ) + (drop + ;; Not valid. Cannot use struct.new to allocate $A. + (struct.new $A + (i32.const 1) + ) + ) + (drop + ;; Not valid. Cannot use struct.new_default to allocate $A. + (struct.new_default $A) + ) ) ``` +``` +struct.new_desc x + +C |- struct.new_desc x : t* (ref null (exact y)) -> (ref (exact x)) + -- C.types[x] ~ descriptor y (struct (field t)*) +``` + +``` +struct.new_default_desc x + +C |- struct.new_default_desc x : (ref null (exact y)) -> (ref (exact x)) + -- C.types[x] ~ descriptor y (struct (field t)*) + -- defaultable(t)* +``` + +`struct.new_desc` and `struct.new_default_desc` are constant instructions. + +> Note: The descriptors could alternatively be the first operands. +> They are chosen to be the last operands here because in a hypothetical future +> where we have variants of these instructions that do not take type immediates, +> the descriptors would have to be on top of the stack to determine the type of +> the allocation. This is consistent with GC accessor instructions. + ## Exact Types Allocating an instance of a type with a custom descriptor necessarily @@ -244,20 +306,21 @@ this could allow the following unsound program to validate and run: ```wasm (rec - (type $foo (sub (descriptor $foo.rtt) (struct))) - (type $foo.rtt (sub (describes $foo) (struct))) + (type $foo (sub (descriptor $foo.desc) (struct))) + (type $foo.desc (sub (describes $foo) (struct))) - (type $bar (sub $foo (descriptor $bar.rtt) (struct (field $bar-only i32)))) - (type $bar.rtt (sub $foo.rtt (describes $bar) (struct))) + (type $bar (sub $foo (descriptor $bar.desc) (struct (field $bar-only i32)))) + (type $bar.desc (sub $foo.desc (describes $bar) (struct))) ) (func $unsound (result i32) - (local $rtt (ref $foo.rtt)) - ;; We can store a $bar.rtt in the local due to subtyping. - (local.set $rtt (struct.new $bar.rtt)) - ;; Allocate a $foo with a $foo.rtt that is actually a $bar.rtt. - (struct.new $foo (local.get $rtt)) - ;; Now cast the $foo to a $bar. This will succeed because it has an RTT for $bar. + (local $desc (ref $foo.desc)) + ;; We can store a $bar.desc in the local due to subtyping. + (local.set $desc (struct.new $bar.desc)) + ;; Allocate a $foo with a $foo.desc that is actually a $bar.desc. + (struct.new_desc $foo (local.get $desc)) + ;; Now cast the $foo to a $bar. This will succeed because it has a descriptor + ;; for $bar and therefore an RTT for $bar. (ref.cast (ref $bar)) ;; Out-of-bounds read. (struct.get $bar $bar-only) @@ -265,9 +328,10 @@ this could allow the following unsound program to validate and run: ``` The problem here is that the normal subtyping rules make it possible -to allocate a `$foo` with an RTT for `$bar`, +to allocate a `$foo` with a descriptor for `$bar`, causing subsequent casts to behave incorrectly. -One solution would be to have `struct.new` dynamically check that the provided descriptor value +One solution would be to have `struct.new_desc` dynamically check +that the provided descriptor value describes precisely the allocated type. A better solution would be to allow userspace to perform that check if necessary, but also be able to statically prove via the type system that it is not necessary. @@ -306,7 +370,6 @@ none <: (exact $sub) <: $sub <: $super <: struct <: eq <: any But no version of `$sub` is in a subtyping relation with `(exact $super)`. - All instructions that create references to a particular defined heap type (e.g. `ref.func`, `struct.new`, `array.new`, etc.) are refined to produce references to the exact version of that heap type. @@ -315,31 +378,10 @@ Since only defined types have exact versions, instructions like `ref.i31` or `any.convert_extern` that produce references to abstract heap types do not produce references to exact types. -When allocating types with custom descriptors, -`struct.new` and `struct.new_default` take references to the exact descriptors -as their last operands. -This makes the unsound program above invalid. - -``` -struct.new x - -C |- struct.new x : t* (ref null (exact y)) -> (ref (exact x)) - -- C.types[x] ~ descriptor y (struct (field t)*) -``` - -``` -struct.new_default x - -C |- struct.new_default x : (ref null (exact y)) -> (ref (exact x)) - -- C.types[x] ~ descriptor y (struct (field t)*) - -- defaultable(t)* -``` - -> Note: The descriptors could alternatively be the first operands. -> They are chosen to be the last operands here because in a hypothetical future -> where we have variants of these instructions that do not take type immediates, -> the descriptors would have to be on top of the stack to determine the type of -> the allocation. This is consistent with GC accessor instructions. +Since `struct.new_desc` and `struct.new_default_desc` +take references to the exact descriptors +as their last operands, +the unsound program above is invalid. ### Exact Function Imports @@ -573,7 +615,7 @@ WebAssembly. ) (global $counter (export "counter") (ref $counter) - (struct.new_default $counter + (struct.new_default_desc $counter (global.get $counter.vtable) ) ) @@ -821,7 +863,7 @@ and additionally expose a constructor: ) (func $counter.new (type $new_t) (param i32) (result (ref $counter)) - (struct.new $counter + (struct.new_desc $counter (local.get 0) (global.get $counter.vtable) ) @@ -970,6 +1012,8 @@ The new instructions are encoded as follows: ``` instr ::= ... + | 0xFB 32:u32 x:typeidx => struct.new_desc x + | 0xFB 33:u32 x:typeidx => struct.new_default_desc x | 0xFB 34:u32 x:typeidx => ref.get_desc x | 0xFB 35:u32 ht:heaptype => ref.cast_desc (ref ht) | 0xFB 36:u32 ht:heaptype => ref.cast_desc (ref null ht) diff --git a/test/core/custom-descriptors/br_on_cast_desc.wast b/test/core/custom-descriptors/br_on_cast_desc.wast index e5d4358e9..e888ff3cf 100644 --- a/test/core/custom-descriptors/br_on_cast_desc.wast +++ b/test/core/custom-descriptors/br_on_cast_desc.wast @@ -1126,13 +1126,13 @@ (global $b2-exact (ref null (exact $b)) (struct.new $b)) (global $b1 (ref null $b) (global.get $b1-exact)) (global $b2 (ref null $b) (global.get $b2-exact)) - (global $a1 (ref null $a) (struct.new $a (global.get $b1-exact))) + (global $a1 (ref null $a) (struct.new_desc $a (global.get $b1-exact))) (global $d1-exact (ref null (exact $d)) (struct.new $d)) (global $d2-exact (ref null (exact $d)) (struct.new $d)) (global $d1 (ref null $d) (global.get $d1-exact)) (global $d2 (ref null $d) (global.get $d2-exact)) - (global $c1 (ref null $c) (struct.new $c (global.get $d1-exact))) + (global $c1 (ref null $c) (struct.new_desc $c (global.get $d1-exact))) (global $c1-as-a (ref null $a) (global.get $c1)) @@ -1916,7 +1916,7 @@ (global $b1 (ref (exact $b)) (struct.new $b)) (global $b2 (ref (exact $b)) (struct.new $b)) - (global $a1 (ref (exact $a)) (struct.new $a (global.get $b1))) + (global $a1 (ref (exact $a)) (struct.new_desc $a (global.get $b1))) (func $assert-eq-i32 (param i32 i32) (if diff --git a/test/core/custom-descriptors/br_on_cast_desc_fail.wast b/test/core/custom-descriptors/br_on_cast_desc_fail.wast index 268f69132..d85e9836e 100644 --- a/test/core/custom-descriptors/br_on_cast_desc_fail.wast +++ b/test/core/custom-descriptors/br_on_cast_desc_fail.wast @@ -1112,13 +1112,13 @@ (global $b2-exact (ref null (exact $b)) (struct.new $b)) (global $b1 (ref null $b) (global.get $b1-exact)) (global $b2 (ref null $b) (global.get $b2-exact)) - (global $a1 (ref null $a) (struct.new $a (global.get $b1-exact))) + (global $a1 (ref null $a) (struct.new_desc $a (global.get $b1-exact))) (global $d1-exact (ref null (exact $d)) (struct.new $d)) (global $d2-exact (ref null (exact $d)) (struct.new $d)) (global $d1 (ref null $d) (global.get $d1-exact)) (global $d2 (ref null $d) (global.get $d2-exact)) - (global $c1 (ref null $c) (struct.new $c (global.get $d1-exact))) + (global $c1 (ref null $c) (struct.new_desc $c (global.get $d1-exact))) (global $c1-as-a (ref null $a) (global.get $c1)) @@ -1902,7 +1902,7 @@ (global $b1 (ref (exact $b)) (struct.new $b)) (global $b2 (ref (exact $b)) (struct.new $b)) - (global $a1 (ref (exact $a)) (struct.new $a (global.get $b1))) + (global $a1 (ref (exact $a)) (struct.new_desc $a (global.get $b1))) (func $assert-eq-i32 (param i32 i32) (if diff --git a/test/core/custom-descriptors/ref_cast_desc.wast b/test/core/custom-descriptors/ref_cast_desc.wast index 71897e1d3..722965a9d 100644 --- a/test/core/custom-descriptors/ref_cast_desc.wast +++ b/test/core/custom-descriptors/ref_cast_desc.wast @@ -497,13 +497,13 @@ (global $b2-exact (ref null (exact $b)) (struct.new $b)) (global $b1 (ref null $b) (global.get $b1-exact)) (global $b2 (ref null $b) (global.get $b2-exact)) - (global $a1 (ref null $a) (struct.new $a (global.get $b1-exact))) + (global $a1 (ref null $a) (struct.new_desc $a (global.get $b1-exact))) (global $d1-exact (ref null (exact $d)) (struct.new $d)) (global $d2-exact (ref null (exact $d)) (struct.new $d)) (global $d1 (ref null $d) (global.get $d1-exact)) (global $d2 (ref null $d) (global.get $d2-exact)) - (global $c1 (ref null $c) (struct.new $c (global.get $d1-exact))) + (global $c1 (ref null $c) (struct.new_desc $c (global.get $d1-exact))) (global $c1-as-a (ref null $a) (global.get $c1)) diff --git a/test/core/custom-descriptors/ref_get_desc.wast b/test/core/custom-descriptors/ref_get_desc.wast index 97c80394a..5d10b1bd5 100644 --- a/test/core/custom-descriptors/ref_get_desc.wast +++ b/test/core/custom-descriptors/ref_get_desc.wast @@ -305,9 +305,9 @@ (global $b1 (ref (exact $b)) (struct.new $b (i32.const 1))) (global $b2 (ref (exact $b)) (struct.new $b (i32.const 2))) - (global $a1 (ref null $a) (struct.new $a (global.get $b1))) - (global $a2 (ref null (exact $a)) (struct.new $a (global.get $b2))) - (global $a3 (ref (exact $a)) (struct.new $a (struct.new $b (i32.const 3)))) + (global $a1 (ref null $a) (struct.new_desc $a (global.get $b1))) + (global $a2 (ref null (exact $a)) (struct.new_desc $a (global.get $b2))) + (global $a3 (ref (exact $a)) (struct.new_desc $a (struct.new $b (i32.const 3)))) (global $null (ref null $a) (ref.null none)) (global $null-exact (ref null (exact $a)) (ref.null (exact $a))) @@ -315,10 +315,10 @@ (func $null (result (ref null $a)) (ref.null none)) (func $null-exact (result (ref null (exact $a))) (ref.null (exact $a))) (func $alloc-i32 (param i32) (result (ref (exact $a))) - (struct.new $a (struct.new $b (local.get 0))) + (struct.new_desc $a (struct.new $b (local.get 0))) ) (func $alloc-desc (param (ref (exact $b))) (result (ref (exact $a))) - (struct.new $a (local.get 0)) + (struct.new_desc $a (local.get 0)) ) (func (export "null") (result anyref) @@ -346,7 +346,7 @@ (func (export "alloc-0") (result i32) (struct.get $b 0 (ref.get_desc $a - (struct.new $a + (struct.new_desc $a (struct.new $b (i32.const 0) ) @@ -374,13 +374,13 @@ (local.set 0 (struct.new_default $b)) (ref.eq (local.get 0) - (ref.get_desc $a (struct.new $a (local.get 0))) + (ref.get_desc $a (struct.new_desc $a (local.get 0))) ) ) (func (export "not-equal") (result i32) (ref.eq (struct.new_default $b) - (ref.get_desc $a (struct.new $a (struct.new_default $b))) + (ref.get_desc $a (struct.new_desc $a (struct.new_default $b))) ) ) (func (export "chain-equal") (result i32) @@ -388,8 +388,8 @@ (local $two (ref null (exact $two))) (local $one (ref null (exact $one))) (local.set $three (struct.new $three)) - (local.set $two (struct.new $two (local.get $three))) - (local.set $one (struct.new $one (local.get $two))) + (local.set $two (struct.new_desc $two (local.get $three))) + (local.set $one (struct.new_desc $one (local.get $two))) (ref.eq (local.get $three) (ref.get_desc $two (ref.get_desc $one (local.get $one))) @@ -426,7 +426,7 @@ (global (export "b") (ref null (exact $b)) (struct.new $b)) (func (export "make-a") (result (ref null $a)) - (struct.new $a (global.get 0)) + (struct.new_desc $a (global.get 0)) ) (func (export "check-eq") (param (ref null $a)) (result i32) @@ -453,11 +453,11 @@ ) (func (export "imported-check-equal") (result i32) - (call $check-eq (struct.new $a (global.get $b))) + (call $check-eq (struct.new_desc $a (global.get $b))) ) (func (export "imported-check-not-equal") (result i32) - (call $check-eq (struct.new $a (struct.new $b))) + (call $check-eq (struct.new_desc $a (struct.new $b))) ) ) diff --git a/test/core/custom-descriptors/struct_new_desc.wast b/test/core/custom-descriptors/struct_new_desc.wast index e4dedc1c3..41c9c7e1d 100644 --- a/test/core/custom-descriptors/struct_new_desc.wast +++ b/test/core/custom-descriptors/struct_new_desc.wast @@ -11,78 +11,78 @@ ) (func (param (ref null (exact $empty.desc))) (result (ref (exact $empty))) - (struct.new $empty (local.get 0)) + (struct.new_desc $empty (local.get 0)) ) (func (param (ref null (exact $empty.desc))) (result (ref (exact $empty))) - (struct.new_default $empty (local.get 0)) + (struct.new_default_desc $empty (local.get 0)) ) (func (param (ref (exact $empty.desc))) (result (ref (exact $empty))) - (struct.new $empty (local.get 0)) + (struct.new_desc $empty (local.get 0)) ) (func (param (ref (exact $empty.desc))) (result (ref (exact $empty))) - (struct.new_default $empty (local.get 0)) + (struct.new_default_desc $empty (local.get 0)) ) (func (result (ref (exact $empty))) - (struct.new $empty (ref.null none)) + (struct.new_desc $empty (ref.null none)) ) (func (result (ref (exact $empty))) - (struct.new_default $empty (ref.null none)) + (struct.new_default_desc $empty (ref.null none)) ) (func (result (ref (exact $empty))) - (struct.new $empty (unreachable)) + (struct.new_desc $empty (unreachable)) ) (func (result (ref (exact $empty))) - (struct.new_default $empty (unreachable)) + (struct.new_default_desc $empty (unreachable)) ) (func (param (ref null (exact $one.desc))) (result (ref (exact $one))) - (struct.new $one (i32.const 0) (local.get 0)) + (struct.new_desc $one (i32.const 0) (local.get 0)) ) (func (param (ref null (exact $one.desc))) (result (ref (exact $one))) - (struct.new_default $one (local.get 0)) + (struct.new_default_desc $one (local.get 0)) ) (func (param (ref (exact $one.desc))) (result (ref (exact $one))) - (struct.new $one (i32.const 0) (local.get 0)) + (struct.new_desc $one (i32.const 0) (local.get 0)) ) (func (param (ref (exact $one.desc))) (result (ref (exact $one))) - (struct.new_default $one (local.get 0)) + (struct.new_default_desc $one (local.get 0)) ) (func (result (ref (exact $one))) - (struct.new $one (i32.const 0) (ref.null none)) + (struct.new_desc $one (i32.const 0) (ref.null none)) ) (func (result (ref (exact $one))) - (struct.new_default $one (ref.null none)) + (struct.new_default_desc $one (ref.null none)) ) (func (result (ref (exact $one))) - (struct.new $one (i32.const 0) (unreachable)) + (struct.new_desc $one (i32.const 0) (unreachable)) ) (func (result (ref (exact $one))) - (struct.new_default $one (unreachable)) + (struct.new_default_desc $one (unreachable)) ) (func (param (ref null (exact $pair.desc))) (result (ref (exact $pair))) - (struct.new $pair (i32.const 1) (i64.const 2) (local.get 0)) + (struct.new_desc $pair (i32.const 1) (i64.const 2) (local.get 0)) ) (func (param (ref null (exact $pair.desc))) (result (ref (exact $pair))) - (struct.new_default $pair (local.get 0)) + (struct.new_default_desc $pair (local.get 0)) ) (func (param (ref (exact $pair.desc))) (result (ref (exact $pair))) - (struct.new $pair (i32.const 1) (i64.const 2) (local.get 0)) + (struct.new_desc $pair (i32.const 1) (i64.const 2) (local.get 0)) ) (func (param (ref (exact $pair.desc))) (result (ref (exact $pair))) - (struct.new_default $pair (local.get 0)) + (struct.new_default_desc $pair (local.get 0)) ) (func (result (ref (exact $pair))) - (struct.new $pair (i32.const 1) (i64.const 2) (ref.null none)) + (struct.new_desc $pair (i32.const 1) (i64.const 2) (ref.null none)) ) (func (result (ref (exact $pair))) - (struct.new_default $pair (ref.null none)) + (struct.new_default_desc $pair (ref.null none)) ) (func (result (ref (exact $pair))) - (struct.new $pair (i32.const 1) (i64.const 2) (unreachable)) + (struct.new_desc $pair (i32.const 1) (i64.const 2) (unreachable)) ) (func (result (ref (exact $pair))) - (struct.new_default $pair (unreachable)) + (struct.new_default_desc $pair (unreachable)) ) ) @@ -95,14 +95,14 @@ ) (global $d (ref (exact $d)) (struct.new $d)) - (global $c (ref (exact $c)) (struct.new $c (global.get $d))) - (global $b (ref (exact $b)) (struct.new $b (global.get $c))) - (global $a (ref (exact $a)) (struct.new $a (global.get $b))) + (global $c (ref (exact $c)) (struct.new_desc $c (global.get $d))) + (global $b (ref (exact $b)) (struct.new_desc $b (global.get $c))) + (global $a (ref (exact $a)) (struct.new_desc $a (global.get $b))) (func (result (ref (exact $a))) - (struct.new $a - (struct.new $b - (struct.new $c + (struct.new_desc $a + (struct.new_desc $b + (struct.new_desc $c (struct.new $d) ) ) @@ -116,14 +116,84 @@ (type $a (descriptor $b) (struct (field i32))) (type $b (describes $a) (struct)) ) - ;; Missing descriptor. + ;; Missing descriptor and wrong allocation. (func (result anyref) (struct.new $a (i32.const 0)) ) ) + "type with descriptor requires descriptor allocation" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Missing descriptor with correct allocation. + (func (result anyref) + (struct.new_desc $a (i32.const 0)) + ) + ) "type mismatch" ) +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Wrong allocation. + (func (result anyref) + (struct.new $a (i32.const 0) (ref.null none)) + ) + ) + "type with descriptor requires descriptor allocation" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Missing descriptor and wrong allocation. + (func (result anyref) + (struct.new_default $a) + ) + ) + "type with descriptor requires descriptor allocation" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Missing descriptor with correct allocation. + (func (result anyref) + (struct.new_default_desc $a) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Wrong allocation. + (func (result anyref) + (struct.new_default $a (ref.null none)) + ) + ) + "type with descriptor requires descriptor allocation" +) + (assert_invalid (module (rec @@ -139,6 +209,81 @@ "type mismatch" ) +(assert_invalid + (module + (rec + (type $struct (struct (field i32))) + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Descriptor provided and wrong allocation for a type without a descriptor. + (func (result anyref) + (struct.new_desc $struct (i32.const 0) (struct.new $b)) + ) + ) + "type without descriptor requires non-descriptor allocation" +) + +(assert_invalid + (module + (rec + (type $struct (struct (field i32))) + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Wrong allocation for a type without a descriptor. + (func (result anyref) + (struct.new_desc $struct (i32.const 0)) + ) + ) + "type without descriptor requires non-descriptor allocation" +) + +(assert_invalid + (module + (rec + (type $struct (struct (field i32))) + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Descriptor provided when allocating a type without a descriptor. + (func (result anyref) + (struct.new_default $struct (struct.new $b)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $struct (struct (field i32))) + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Descriptor provided and wrong allocation for a type without a descriptor. + (func (result anyref) + (struct.new_default_desc $struct (struct.new $b)) + ) + ) + "type without descriptor requires non-descriptor allocation" +) + +(assert_invalid + (module + (rec + (type $struct (struct (field i32))) + (type $a (descriptor $b) (struct (field i32))) + (type $b (describes $a) (struct)) + ) + ;; Wrong allocation for a type without a descriptor. + (func (result anyref) + (struct.new_default_desc $struct) + ) + ) + "type without descriptor requires non-descriptor allocation" +) + (assert_invalid (module (rec @@ -147,7 +292,7 @@ ) ;; Descriptor does not have expected type. (func (param (ref struct)) (result anyref) - (struct.new $a (i32.const 0) (local.get 0)) + (struct.new_desc $a (i32.const 0) (local.get 0)) ) ) "type mismatch" @@ -161,7 +306,7 @@ ) ;; Descriptor must be exact. (func (param (ref $b)) (result anyref) - (struct.new $a (i32.const 0) (local.get 0)) + (struct.new_desc $a (i32.const 0) (local.get 0)) ) ) "type mismatch" @@ -175,7 +320,7 @@ ) ;; Allocated type cannot be used as descriptor. (func (param (ref (exact $a))) (result anyref) - (struct.new $a (i32.const 0) (local.get 0)) + (struct.new_desc $a (i32.const 0) (local.get 0)) ) ) "type mismatch" @@ -191,7 +336,7 @@ ) ;; Unrelated descriptor cannot be used as desciptor. (func (param (ref (exact $d))) (result anyref) - (struct.new $a (i32.const 0) (local.get 0)) + (struct.new_desc $a (i32.const 0) (local.get 0)) ) ) "type mismatch" @@ -207,7 +352,7 @@ ) ;; Subtype descriptor cannot be used as desciptor. (func (param (ref (exact $d))) (result anyref) - (struct.new $a (i32.const 0) (local.get 0)) + (struct.new_desc $a (i32.const 0) (local.get 0)) ) ) "type mismatch" @@ -223,7 +368,7 @@ ) ;; Supertype descriptor cannot be used as desciptor. (func (param (ref (exact $b))) (result anyref) - (struct.new $c (i32.const 0) (local.get 0)) + (struct.new_desc $c (i32.const 0) (local.get 0)) ) ) "type mismatch" @@ -237,7 +382,7 @@ ) ;; The correct descriptor is supplied, but the fields are missing. (func (result anyref) - (struct.new $a (struct.new $b)) + (struct.new_desc $a (struct.new $b)) ) ) "type mismatch" @@ -261,20 +406,20 @@ ) (global $b (export "b") (ref null (exact $b)) (struct.new $b)) - (global $a (export "a") (ref (exact $a)) (struct.new $a (global.get $b))) + (global $a (export "a") (ref (exact $a)) (struct.new_desc $a (global.get $b))) (global $null-b (ref null (exact $b)) (ref.null none)) (func (export "new-new") (result (ref (exact $a))) - (struct.new $a (struct.new $b)) + (struct.new_desc $a (struct.new $b)) ) (func (export "new-global") (result (ref (exact $a))) - (struct.new $a (global.get $b)) + (struct.new_desc $a (global.get $b)) ) (func (export "new-call") (result (ref (exact $a))) - (struct.new $a (call $new-b)) + (struct.new_desc $a (call $new-b)) ) (func $new-b (result (ref null (exact $b))) @@ -282,7 +427,7 @@ ) (func (export "new-pair") (result (ref (exact $pair))) - (struct.new $pair + (struct.new_desc $pair (i32.const 0) (i64.const 1) (struct.new $pair.desc @@ -292,23 +437,23 @@ ) (func (export "new-chain") (result (ref (exact $one))) - (struct.new $one - (struct.new $two + (struct.new_desc $one + (struct.new_desc $two (struct.new $three) ) ) ) (func (export "new-null") (result (ref (exact $a))) - (struct.new $a (ref.null none)) + (struct.new_desc $a (ref.null none)) ) (func (export "new-null-global") (result (ref (exact $a))) - (struct.new $a (global.get $null-b)) + (struct.new_desc $a (global.get $null-b)) ) (func (export "new-null-call") (result (ref (exact $a))) - (struct.new $a (call $null)) + (struct.new_desc $a (call $null)) ) (func $null (result (ref null (exact $b))) @@ -316,7 +461,7 @@ ) (func (export "new-null-pair") (result (ref (exact $pair))) - (struct.new $pair + (struct.new_desc $pair (i32.const 0) (i64.const 1) (ref.null (exact $pair.desc)) @@ -324,14 +469,14 @@ ) (func (export "new-null-chain-1") (result (ref (exact $one))) - (struct.new $one + (struct.new_desc $one (ref.null (exact $two)) ) ) (func (export "new-null-chain-2") (result (ref (exact $one))) - (struct.new $one - (struct.new $two + (struct.new_desc $one + (struct.new_desc $two (ref.null (exact $three)) ) ) @@ -357,7 +502,7 @@ (type $a (descriptor $b) (struct)) (type $b (describes $a) (struct)) ) - (global (ref (exact $a)) (struct.new $a (ref.null none))) + (global (ref (exact $a)) (struct.new_desc $a (ref.null none))) ) "null descriptor reference" ) @@ -368,7 +513,7 @@ (type $a (descriptor $b) (struct)) (type $b (describes $a) (struct)) ) - (global (ref (exact $a)) (struct.new $a (ref.null (exact $b)))) + (global (ref (exact $a)) (struct.new_desc $a (ref.null (exact $b)))) ) "null descriptor reference" ) @@ -380,7 +525,7 @@ (type $b (describes $a) (struct)) ) (global (ref null (exact $b)) (ref.null none)) - (global (ref (exact $a)) (struct.new $a (global.get 0))) + (global (ref (exact $a)) (struct.new_desc $a (global.get 0))) ) "null descriptor reference" ) @@ -421,22 +566,22 @@ (import "A" "new-b" (func $new-b (result (ref null (exact $b))))) (import "A" "new-null-b" (func $new-null-b (result (ref null (exact $b))))) - (global (export "a") (ref (exact $a)) (struct.new $a (global.get $b))) + (global (export "a") (ref (exact $a)) (struct.new_desc $a (global.get $b))) (func (export "new-global") (result (ref (exact $a))) - (struct.new $a (global.get $b)) + (struct.new_desc $a (global.get $b)) ) (func (export "new-call") (result (ref (exact $a))) - (struct.new $a (call $new-b)) + (struct.new_desc $a (call $new-b)) ) (func (export "null-global") (result (ref (exact $a))) - (struct.new $a (global.get $null-b)) + (struct.new_desc $a (global.get $null-b)) ) (func (export "null-call") (result (ref (exact $a))) - (struct.new $a (call $new-null-b)) + (struct.new_desc $a (call $new-null-b)) ) )