summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wasm-binary.cpp31
-rw-r--r--test/lit/downgrade-reftypes.wast61
2 files changed, 78 insertions, 14 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 91309c906..1d0e99415 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1393,6 +1393,18 @@ void WasmBinaryWriter::writeInlineBuffer(const char* data, size_t size) {
void WasmBinaryWriter::writeType(Type type) {
if (type.isRef()) {
+ // The only reference types allowed without GC are funcref and externref. We
+ // internally use more refined versions of those types, but we cannot emit
+ // those more refined types.
+ if (!wasm->features.hasGC()) {
+ if (Type::isSubType(type, Type(HeapType::func, Nullable))) {
+ o << S32LEB(BinaryConsts::EncodedType::funcref);
+ return;
+ }
+ assert(Type::isSubType(type, Type(HeapType::ext, Nullable)));
+ o << S32LEB(BinaryConsts::EncodedType::externref);
+ return;
+ }
auto heapType = type.getHeapType();
if (heapType.isBasic() && type.isNullable()) {
switch (heapType.getBasic()) {
@@ -1433,20 +1445,10 @@ void WasmBinaryWriter::writeType(Type type) {
o << S32LEB(BinaryConsts::EncodedType::nullref);
return;
case HeapType::noext:
- // See comment on writeHeapType.
- if (!wasm->features.hasGC()) {
- o << S32LEB(BinaryConsts::EncodedType::externref);
- } else {
- o << S32LEB(BinaryConsts::EncodedType::nullexternref);
- }
+ o << S32LEB(BinaryConsts::EncodedType::nullexternref);
return;
case HeapType::nofunc:
- // See comment on writeHeapType.
- if (!wasm->features.hasGC()) {
- o << S32LEB(BinaryConsts::EncodedType::funcref);
- } else {
- o << S32LEB(BinaryConsts::EncodedType::nullfuncref);
- }
+ o << S32LEB(BinaryConsts::EncodedType::nullfuncref);
return;
}
}
@@ -1491,9 +1493,10 @@ void WasmBinaryWriter::writeHeapType(HeapType type) {
// only actually valid with GC enabled. When GC is not enabled, emit the
// corresponding valid top types instead.
if (!wasm->features.hasGC()) {
- if (type == HeapType::nofunc || type.isSignature()) {
+ if (HeapType::isSubType(type, HeapType::func)) {
type = HeapType::func;
- } else if (type == HeapType::noext) {
+ } else {
+ assert(HeapType::isSubType(type, HeapType::ext));
type = HeapType::ext;
}
}
diff --git a/test/lit/downgrade-reftypes.wast b/test/lit/downgrade-reftypes.wast
new file mode 100644
index 000000000..94343933f
--- /dev/null
+++ b/test/lit/downgrade-reftypes.wast
@@ -0,0 +1,61 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+
+;; Write to a binary, lowering away refined GC types.
+;; RUN: wasm-as %s -all --disable-gc -g -o %s.wasm
+
+;; Read it back and verify that the types were lowered away.
+;; RUN: wasm-dis %s.wasm -all -o - | filecheck %s
+
+(module
+
+ ;; CHECK: (type $f (func))
+ (type $f (func))
+
+ ;; CHECK: (func $foo (type $f)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block $label$1 (result funcref)
+ ;; CHECK-NEXT: (br $label$1
+ ;; CHECK-NEXT: (ref.func $foo)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block $label$2 (result funcref)
+ ;; CHECK-NEXT: (br $label$2
+ ;; CHECK-NEXT: (ref.null nofunc)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block $label$3 (result externref)
+ ;; CHECK-NEXT: (br $label$3
+ ;; CHECK-NEXT: (ref.null noextern)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $foo (type $f)
+ (drop
+ (block $l1 (result (ref $f))
+ (br $l1
+ (ref.func $foo)
+ )
+ )
+ )
+ (drop
+ (block $l2 (result nullfuncref)
+ ;; Branch to ensure the blocks remain in the output.
+ (br $l2
+ (ref.null nofunc)
+ )
+ )
+ )
+ (drop
+ (block $l3 (result nullexternref)
+ (br $l3
+ (ref.null noextern)
+ )
+ )
+ )
+ )
+)