diff options
Diffstat (limited to 'src/wasm-builder.h')
-rw-r--r-- | src/wasm-builder.h | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 2277fed93..3ca3d9daf 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -18,6 +18,7 @@ #define wasm_wasm_builder_h #include "ir/manipulation.h" +#include "parsing.h" #include "wasm.h" namespace wasm { @@ -39,7 +40,7 @@ class Builder { public: Builder(Module& wasm) : wasm(wasm) {} - // make* functions, other globals + // make* functions create an expression instance. static std::unique_ptr<Function> makeFunction(Name name, Signature sig, @@ -1116,6 +1117,65 @@ public: } }; +// This class adds methods that first inspect the input. They may not have fully +// comprehensive error checking, when that can be left to the validator; the +// benefit of the validate* methods is that they can share code between the +// text and binary format parsers, for handling certain situations in the +// input which preclude even creating valid IR, which the validator depends +// on. +class ValidatingBuilder : public Builder { + size_t line = -1, col = -1; + +public: + ValidatingBuilder(Module& wasm, size_t line) : Builder(wasm), line(line) {} + ValidatingBuilder(Module& wasm, size_t line, size_t col) + : Builder(wasm), line(line), col(col) {} + + Expression* validateAndMakeBrOn(BrOnOp op, + Name name, + Expression* ref, + Expression* rtt = nullptr) { + if (op == BrOnCast) { + if (rtt->type == Type::unreachable) { + // An unreachable rtt is not supported: the text and binary formats do + // not provide the type, so if it's unreachable we should not even + // create a br_on_cast in such a case, as we'd have no idea what it + // casts to. + return makeSequence(makeDrop(ref), rtt); + } + } + if (op == BrOnNull) { + if (!ref->type.isRef() && ref->type != Type::unreachable) { + throw ParseException("Invalid ref for br_on_null", line, col); + } + } + return makeBrOn(op, name, ref, rtt); + } + + template<typename T> + Expression* validateAndMakeCallRef(Expression* target, + const T& args, + bool isReturn = false) { + if (!target->type.isRef()) { + if (target->type == Type::unreachable) { + // 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. + auto* block = makeBlock(args); + block->list.push_back(target); + block->finalize(Type::unreachable); + return block; + } + throw ParseException("Non-reference type for a call_ref", line, col); + } + 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 #endif // wasm_wasm_builder_h |