diff options
author | Alon Zakai <azakai@google.com> | 2021-03-02 23:41:16 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-02 15:41:16 -0800 |
commit | 5f88277c4bddc097d2f073e41488889f02b08103 (patch) | |
tree | d669c7c77f9945f696930c3b29c7d67a21a5d274 | |
parent | e7c6356c7529c29ef06f4541bc3164659e8917f6 (diff) | |
download | binaryen-5f88277c4bddc097d2f073e41488889f02b08103.tar.gz binaryen-5f88277c4bddc097d2f073e41488889f02b08103.tar.bz2 binaryen-5f88277c4bddc097d2f073e41488889f02b08103.zip |
[Wasm GC] Allow subtyping in arguments to struct.get etc. Fixes #3636 (#3644)
Note that Binaryen "canonicalizes" the type, so in the test output here
we end up with $grandchild twice. This is a consequence of us not
storing the heap type as an extra field. I can't think of a downside to
this canonicalization, aside from losing perfect roundtripping, but I think
that's a worthwhile tradeoff for efficiency as we've been thinking so far.
Fixes #3636
-rw-r--r-- | src/wasm/wasm-binary.cpp | 2 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 2 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.c | 28 | ||||
-rw-r--r-- | test/heap-types.wast | 4 | ||||
-rw-r--r-- | test/heap-types.wast.from-wast | 7 | ||||
-rw-r--r-- | test/heap-types.wast.fromBinary | 7 | ||||
-rw-r--r-- | test/heap-types.wast.fromBinary.noDebugInfo | 7 |
7 files changed, 45 insertions, 12 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 1f54a0038..d5579eedf 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -6417,7 +6417,7 @@ void WasmBinaryBuilder::validateHeapTypeUsingChild(Expression* child, return; } if ((!child->type.isRef() && !child->type.isRtt()) || - child->type.getHeapType() != heapType) { + !HeapType::isSubType(child->type.getHeapType(), heapType)) { throwError("bad heap type: expected " + heapType.toString() + " but found " + child->type.toString()); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 1271ff603..11121ced6 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -3451,7 +3451,7 @@ void SExpressionWasmBuilder::validateHeapTypeUsingChild(Expression* child, return; } if ((!child->type.isRef() && !child->type.isRtt()) || - child->type.getHeapType() != heapType) { + !HeapType::isSubType(child->type.getHeapType(), heapType)) { throw ParseException("bad heap type: expected " + heapType.toString() + " but found " + child->type.toString(), s.line, diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index 4faf7aa5e..04f552069 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -731,13 +731,27 @@ void test_core() { BinaryenRefEq(module, BinaryenRefNull(module, BinaryenTypeEqref()), BinaryenRefNull(module, BinaryenTypeEqref())), - BinaryenRefIs(module, BinaryenRefIsFunc(), BinaryenRefNull(module, BinaryenTypeAnyref())), - BinaryenRefIs(module, BinaryenRefIsData(), BinaryenRefNull(module, BinaryenTypeAnyref())), - BinaryenRefIs(module, BinaryenRefIsI31(), BinaryenRefNull(module, BinaryenTypeAnyref())), - BinaryenRefAs(module, BinaryenRefAsNonNull(), BinaryenRefNull(module, BinaryenTypeAnyref())), - BinaryenRefAs(module, BinaryenRefAsFunc(), BinaryenRefNull(module, BinaryenTypeAnyref())), - BinaryenRefAs(module, BinaryenRefAsData(), BinaryenRefNull(module, BinaryenTypeAnyref())), - BinaryenRefAs(module, BinaryenRefAsI31(), BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefIs(module, + BinaryenRefIsFunc(), + BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefIs(module, + BinaryenRefIsData(), + BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefIs(module, + BinaryenRefIsI31(), + BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefAs(module, + BinaryenRefAsNonNull(), + BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefAs(module, + BinaryenRefAsFunc(), + BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefAs(module, + BinaryenRefAsData(), + BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefAs(module, + BinaryenRefAsI31(), + BinaryenRefNull(module, BinaryenTypeAnyref())), // Exception handling BinaryenTry(module, NULL, tryBody, catchEvents, 1, catchBodies, 2, NULL), // (try $try_outer diff --git a/test/heap-types.wast b/test/heap-types.wast index e645ee74d..f340e9dee 100644 --- a/test/heap-types.wast +++ b/test/heap-types.wast @@ -58,6 +58,10 @@ (struct.get_s $struct.B 0 (local.get $tB)) ) (drop + ;; immutable fields allow subtyping. + (struct.get $child 0 (ref.null $grandchild)) + ) + (drop (ref.null $struct.A) ) (drop diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast index b4228fd20..6c07baf9a 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -5,6 +5,7 @@ (type $vector (array (mut f64))) (type $anyref_=>_none (func (param anyref))) (type $parent (struct )) + (type $grandchild (struct (field i32) (field i64))) (type $struct.C (struct (field $named-mut (mut f32)))) (type $none_=>_none (func)) (type $rtt_1_$parent_=>_none (func (param (rtt 1 $parent)))) @@ -12,7 +13,6 @@ (type $ref?|$struct.A|_=>_ref?|$struct.B| (func (param (ref null $struct.A)) (result (ref null $struct.B)))) (type $ref?|$vector|_=>_ref?|$matrix| (func (param (ref null $vector)) (result (ref null $matrix)))) (type $child (struct (field i32))) - (type $grandchild (struct (field i32) (field i64))) (type $words (array (mut i32))) (type $bytes (array (mut i8))) (global $rttparent (rtt 0 $parent) (rtt.canon $parent)) @@ -62,6 +62,11 @@ ) ) (drop + (struct.get $grandchild 0 + (ref.null $grandchild) + ) + ) + (drop (ref.null $struct.A) ) (drop diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary index 2fe6adbe1..795c789ca 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -5,6 +5,7 @@ (type $vector (array (mut f64))) (type $anyref_=>_none (func (param anyref))) (type $parent (struct )) + (type $grandchild (struct (field i32) (field i64))) (type $struct.C (struct (field $named-mut (mut f32)))) (type $none_=>_none (func)) (type $rtt_1_$parent_=>_none (func (param (rtt 1 $parent)))) @@ -12,7 +13,6 @@ (type $ref?|$struct.A|_=>_ref?|$struct.B| (func (param (ref null $struct.A)) (result (ref null $struct.B)))) (type $ref?|$vector|_=>_ref?|$matrix| (func (param (ref null $vector)) (result (ref null $matrix)))) (type $child (struct (field i32))) - (type $grandchild (struct (field i32) (field i64))) (type $words (array (mut i32))) (type $bytes (array (mut i8))) (global $rttparent (rtt 0 $parent) (rtt.canon $parent)) @@ -62,6 +62,11 @@ ) ) (drop + (struct.get $grandchild 0 + (ref.null $grandchild) + ) + ) + (drop (ref.null $struct.A) ) (drop diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo index dbfcb9cdd..6b1641407 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -5,6 +5,7 @@ (type $[mut:f64] (array (mut f64))) (type $anyref_=>_none (func (param anyref))) (type ${} (struct )) + (type ${i32_i64} (struct (field i32) (field i64))) (type ${mut:f32} (struct (field (mut f32)))) (type $none_=>_none (func)) (type $rtt_1_{}_=>_none (func (param (rtt 1 ${})))) @@ -12,7 +13,6 @@ (type $ref?|{i32_f32_f64}|_=>_ref?|{i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|}| (func (param (ref null ${i32_f32_f64})) (result (ref null ${i8_mut:i16_ref?|{i32_f32_f64}|_mut:ref?|{i32_f32_f64}|})))) (type $ref?|[mut:f64]|_=>_ref?|[ref?|[mut:f64]|]| (func (param (ref null $[mut:f64])) (result (ref null $[ref?|[mut:f64]|])))) (type ${i32} (struct (field i32))) - (type ${i32_i64} (struct (field i32) (field i64))) (type $[mut:i32] (array (mut i32))) (type $[mut:i8] (array (mut i8))) (global $global$0 (rtt 0 ${}) (rtt.canon ${})) @@ -62,6 +62,11 @@ ) ) (drop + (struct.get ${i32_i64} 0 + (ref.null ${i32_i64}) + ) + ) + (drop (ref.null ${i32_f32_f64}) ) (drop |