diff options
-rw-r--r-- | src/wasm/wasm-binary.cpp | 31 | ||||
-rw-r--r-- | test/lit/downgrade-reftypes.wast | 61 |
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) + ) + ) + ) + ) +) |