diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-binary.h | 6 | ||||
-rw-r--r-- | src/wasm-builder.h | 29 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 31 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 35 |
4 files changed, 83 insertions, 18 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index acde624f7..eb8e176ec 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1094,7 +1094,8 @@ enum ASTNodes { // typed function references opcodes - CallRef = 0x14, + CallRefUnannotated = 0x14, + CallRef = 0x17, RetCallRef = 0x15, // gc opcodes @@ -1742,7 +1743,8 @@ public: void visitTryOrTryInBlock(Expression*& out); void visitThrow(Throw* curr); void visitRethrow(Rethrow* curr); - void visitCallRef(CallRef* curr); + void visitCallRef(CallRef* curr, + std::optional<HeapType> maybeType = std::nullopt); void visitRefAs(RefAs* curr, uint8_t code); [[noreturn]] void throwError(std::string text); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index a29867e55..1eb31157d 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -1342,6 +1342,35 @@ public: } return makeBrOn(op, name, ref); } + + template<typename T> + Expression* validateAndMakeCallRef(Expression* target, + const T& args, + bool isReturn = false) { + if (target->type != Type::unreachable && !target->type.isRef()) { + throw ParseException("Non-reference type for a call_ref", line, col); + } + // TODO: This won't be necessary once type annotations are mandatory on + // call_ref. + if (target->type == Type::unreachable || + target->type.getHeapType() == HeapType::nofunc) { + // An unreachable target is not supported. Similiar to br_on_cast, just + // emit an unreachable sequence, since we don't have enough information + // to create a full call_ref. + std::vector<Expression*> children; + for (auto* arg : args) { + children.push_back(makeDrop(arg)); + } + children.push_back(makeDrop(target)); + children.push_back(makeUnreachable()); + return makeBlock(children, Type::unreachable); + } + auto heapType = target->type.getHeapType(); + if (!heapType.isSignature()) { + throw ParseException("Invalid reference type for a call_ref", line, col); + } + return makeCallRef(target, args, heapType.getSignature().results, isReturn); + } }; } // namespace wasm diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 782979520..e2bb0075b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3846,12 +3846,15 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { visitMemoryGrow(grow); break; } + case BinaryConsts::CallRefUnannotated: + visitCallRef((curr = allocator.alloc<CallRef>())->cast<CallRef>()); + break; case BinaryConsts::CallRef: case BinaryConsts::RetCallRef: { auto call = allocator.alloc<CallRef>(); call->isReturn = code == BinaryConsts::RetCallRef; curr = call; - visitCallRef(call); + visitCallRef(call, getTypeByIndex(getU32LEB())); break; } case BinaryConsts::AtomicPrefix: { @@ -6848,13 +6851,29 @@ void WasmBinaryBuilder::visitRethrow(Rethrow* curr) { curr->finalize(); } -void WasmBinaryBuilder::visitCallRef(CallRef* curr) { +void WasmBinaryBuilder::visitCallRef(CallRef* curr, + std::optional<HeapType> maybeType) { BYN_TRACE("zz node: CallRef\n"); curr->target = popNonVoidExpression(); - HeapType heapType = getTypeByIndex(getU32LEB()); - if (!Type::isSubType(curr->target->type, Type(heapType, Nullable))) { - throwError("Call target has invalid type: " + - curr->target->type.toString()); + HeapType heapType; + if (maybeType) { + heapType = *maybeType; + if (!Type::isSubType(curr->target->type, Type(heapType, Nullable))) { + throwError("Call target has invalid type: " + + curr->target->type.toString()); + } + } else { + auto type = curr->target->type; + if (type == Type::unreachable) { + // If our input is unreachable, then we cannot even find out how many + // inputs we have, and just set ourselves to unreachable as well. + curr->finalize(type); + return; + } + if (!type.isRef()) { + throwError("Non-ref type for a call_ref: " + type.toString()); + } + heapType = type.getHeapType(); } if (!heapType.isSignature()) { throwError("Invalid reference type for a call_ref: " + heapType.toString()); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index ab6230442..a9fd2de77 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2744,20 +2744,35 @@ Expression* SExpressionWasmBuilder::makeTupleExtract(Element& s) { } Expression* SExpressionWasmBuilder::makeCallRef(Element& s, bool isReturn) { - HeapType sigType = parseHeapType(*s[1]); + Index operandsStart = 1; + std::optional<HeapType> sigType; + try { + sigType = parseHeapType(*s[1]); + operandsStart = 2; + } catch (ParseException& p) { + // The type annotation is required for return_call_ref but temporarily + // optional for call_ref. + if (isReturn) { + throw; + } + } std::vector<Expression*> operands; - parseOperands(s, 2, s.size() - 1, operands); + parseOperands(s, operandsStart, s.size() - 1, operands); auto* target = parseExpression(s[s.size() - 1]); - if (!sigType.isSignature()) { - throw ParseException( - std::string(isReturn ? "return_call_ref" : "call_ref") + - " type annotation should be a signature", - s.line, - s.col); + if (sigType) { + if (!sigType->isSignature()) { + throw ParseException( + std::string(isReturn ? "return_call_ref" : "call_ref") + + " type annotation should be a signature", + s.line, + s.col); + } + return Builder(wasm).makeCallRef( + target, operands, sigType->getSignature().results, isReturn); } - return Builder(wasm).makeCallRef( - target, operands, sigType.getSignature().results, isReturn); + return ValidatingBuilder(wasm, s.line, s.col) + .validateAndMakeCallRef(target, operands, isReturn); } Expression* SExpressionWasmBuilder::makeI31New(Element& s) { |