diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/parser/context-decls.cpp | 44 | ||||
-rw-r--r-- | src/parser/contexts.h | 55 | ||||
-rw-r--r-- | src/parser/parsers.h | 53 | ||||
-rw-r--r-- | src/parser/wat-parser.cpp | 1 | ||||
-rw-r--r-- | src/parser/wat-parser.h | 2 | ||||
-rw-r--r-- | src/wasm-builder.h | 2 | ||||
-rw-r--r-- | src/wasm-ir-builder.h | 3 | ||||
-rw-r--r-- | src/wasm/wasm-io.cpp | 3 | ||||
-rw-r--r-- | src/wasm/wasm-ir-builder.cpp | 19 | ||||
-rw-r--r-- | src/wat-parser.h | 32 |
10 files changed, 166 insertions, 48 deletions
diff --git a/src/parser/context-decls.cpp b/src/parser/context-decls.cpp index 17b389488..721127614 100644 --- a/src/parser/context-decls.cpp +++ b/src/parser/context-decls.cpp @@ -69,9 +69,7 @@ Result<> ParseDeclsCtx::addFunc(Name name, TypeUseT type, std::optional<LocalsT>, Index pos) { - if (import && hasNonImport) { - return in.err(pos, "import after non-import"); - } + CHECK_ERR(checkImport(pos, import)); auto f = addFuncDecl(pos, name, import); CHECK_ERR(f); CHECK_ERR(addExports(in, wasm, *f, exports, ExternalKind::Function)); @@ -109,9 +107,7 @@ Result<> ParseDeclsCtx::addMemory(Name name, ImportNames* import, MemType type, Index pos) { - if (import && hasNonImport) { - return in.err(pos, "import after non-import"); - } + CHECK_ERR(checkImport(pos, import)); auto m = addMemoryDecl(pos, name, import, type); CHECK_ERR(m); CHECK_ERR(addExports(in, wasm, *m, exports, ExternalKind::Memory)); @@ -156,9 +152,7 @@ Result<> ParseDeclsCtx::addGlobal(Name name, GlobalTypeT, std::optional<ExprT>, Index pos) { - if (import && hasNonImport) { - return in.err(pos, "import after non-import"); - } + CHECK_ERR(checkImport(pos, import)); auto g = addGlobalDecl(pos, name, import); CHECK_ERR(g); CHECK_ERR(addExports(in, wasm, *g, exports, ExternalKind::Global)); @@ -190,4 +184,36 @@ Result<> ParseDeclsCtx::addData(Name name, return Ok{}; } +Result<Tag*> +ParseDeclsCtx::addTagDecl(Index pos, Name name, ImportNames* importNames) { + auto t = std::make_unique<Tag>(); + if (name) { + if (wasm.getTagOrNull(name)) { + // TODO: if the existing tag is not explicitly named, fix its name and + // continue. + return in.err(pos, "repeated tag name"); + } + t->setExplicitName(name); + } else { + name = (importNames ? "timport$" : "") + std::to_string(tagCounter++); + name = Names::getValidTagName(wasm, name); + t->name = name; + } + applyImportNames(*t, importNames); + return wasm.addTag(std::move(t)); +} + +Result<> ParseDeclsCtx::addTag(Name name, + const std::vector<Name>& exports, + ImportNames* import, + TypeUseT type, + Index pos) { + CHECK_ERR(checkImport(pos, import)); + auto t = addTagDecl(pos, name, import); + CHECK_ERR(t); + CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Tag)); + tagDefs.push_back({name, pos, Index(tagDefs.size())}); + return Ok{}; +} + } // namespace wasm::WATParser diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 192442c84..ed4d1283c 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -286,6 +286,7 @@ struct NullInstrParserCtx { using MemoryIdxT = Ok; using DataIdxT = Ok; using LabelIdxT = Ok; + using TagIdxT = Ok; using MemargT = Ok; @@ -309,6 +310,8 @@ struct NullInstrParserCtx { DataIdxT getDataFromName(Name) { return Ok{}; } LabelIdxT getLabelFromIdx(uint32_t) { return Ok{}; } LabelIdxT getLabelFromName(Name) { return Ok{}; } + TagIdxT getTagFromIdx(uint32_t) { return Ok{}; } + TagIdxT getTagFromName(Name) { return Ok{}; } MemargT getMemarg(uint64_t, uint32_t) { return Ok{}; } @@ -393,6 +396,7 @@ struct NullInstrParserCtx { Result<> makeRefIsNull(Index) { return Ok{}; } Result<> makeRefFunc(Index, FuncIdxT) { return Ok{}; } Result<> makeRefEq(Index) { return Ok{}; } + Result<> makeThrow(Index, TagIdxT) { return Ok{}; } template<typename HeapTypeT> Result<> makeCallRef(Index, HeapTypeT, bool) { return Ok{}; } @@ -480,6 +484,7 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx { std::vector<DefPos> memoryDefs; std::vector<DefPos> globalDefs; std::vector<DefPos> dataDefs; + std::vector<DefPos> tagDefs; // Positions of typeuses that might implicitly define new types. std::vector<Index> implicitTypeDefs; @@ -489,10 +494,22 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx { int memoryCounter = 0; int globalCounter = 0; int dataCounter = 0; + int tagCounter = 0; // Used to verify that all imports come before all non-imports. bool hasNonImport = false; + Result<> checkImport(Index pos, ImportNames* import) { + if (import) { + if (hasNonImport) { + return in.err(pos, "import after non-import"); + } + } else { + hasNonImport = true; + } + return Ok{}; + } + ParseDeclsCtx(std::string_view in, Module& wasm) : in(in), wasm(wasm) {} void addFuncType(SignatureT) {} @@ -568,6 +585,14 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx { std::optional<ExprT>, std::vector<char>&& data, Index pos); + + Result<Tag*> addTagDecl(Index pos, Name name, ImportNames* importNames); + + Result<> addTag(Name name, + const std::vector<Name>& exports, + ImportNames* import, + TypeUseT type, + Index pos); }; // Phase 2: Parse type definitions into a TypeBuilder. @@ -814,6 +839,16 @@ struct ParseModuleTypesCtx : TypeParserCtx<ParseModuleTypesCtx>, g->type = type.type; return Ok{}; } + + Result<> + addTag(Name, const std::vector<Name>&, ImportNames*, TypeUse use, Index pos) { + auto& t = wasm.tags[index]; + if (!use.type.isSignature()) { + return in.err(pos, "tag type must be a signature"); + } + t->sig = use.type.getSignature(); + return Ok{}; + } }; // Phase 5: Parse module element definitions, including instructions. @@ -830,6 +865,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { using GlobalIdxT = Name; using MemoryIdxT = Name; using DataIdxT = Name; + using TagIdxT = Name; using MemargT = Memarg; @@ -990,6 +1026,20 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return irBuilder.getLabelIndex(name); } + Result<Name> getTagFromIdx(uint32_t idx) { + if (idx >= wasm.tags.size()) { + return in.err("tag index out of bounds"); + } + return wasm.tags[idx]->name; + } + + Result<Name> getTagFromName(Name name) { + if (!wasm.getTagOrNull(name)) { + return in.err("tag $" + name.toString() + " does not exist"); + } + return name; + } + Result<TypeUseT> makeTypeUse(Index pos, std::optional<HeapTypeT> type, ParamsT* params, @@ -1009,6 +1059,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { Index); Result<> addData(Name, Name* mem, std::optional<ExprT> offset, DataStringT, Index pos); + Result<Index> addScratchLocal(Index pos, Type type) { if (!func) { return in.err(pos, @@ -1288,6 +1339,10 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { Result<> makeRefEq(Index pos) { return withLoc(pos, irBuilder.makeRefEq()); } + Result<> makeThrow(Index pos, Name tag) { + return withLoc(pos, irBuilder.makeThrow(tag)); + } + Result<> makeCallRef(Index pos, HeapType type, bool isReturn) { return withLoc(pos, irBuilder.makeCallRef(type, isReturn)); } diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 41e625657..9201314dc 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -174,6 +174,7 @@ template<typename Ctx> MaybeResult<typename Ctx::MemoryIdxT> maybeMemuse(Ctx&); template<typename Ctx> Result<typename Ctx::GlobalIdxT> globalidx(Ctx&); template<typename Ctx> Result<typename Ctx::LocalIdxT> localidx(Ctx&); template<typename Ctx> Result<typename Ctx::LabelIdxT> labelidx(Ctx&); +template<typename Ctx> Result<typename Ctx::TagIdxT> tagidx(Ctx&); template<typename Ctx> Result<typename Ctx::TypeUseT> typeuse(Ctx&); MaybeResult<ImportNames> inlineImport(ParseInput&); Result<std::vector<Name>> inlineExports(ParseInput&); @@ -186,6 +187,7 @@ template<typename Ctx> MaybeResult<> memory(Ctx&); template<typename Ctx> MaybeResult<> global(Ctx&); template<typename Ctx> Result<typename Ctx::DataStringT> datastring(Ctx&); template<typename Ctx> MaybeResult<> data(Ctx&); +template<typename Ctx> MaybeResult<> tag(Ctx&); template<typename Ctx> MaybeResult<> modulefield(Ctx&); template<typename Ctx> Result<> module(Ctx&); @@ -1274,7 +1276,9 @@ Result<> makeTryOrCatchBody(Ctx& ctx, Index pos, Type type, bool isTry) { } template<typename Ctx> Result<> makeThrow(Ctx& ctx, Index pos) { - return ctx.in.err("unimplemented instruction"); + auto tag = tagidx(ctx); + CHECK_ERR(tag); + return ctx.makeThrow(pos, *tag); } template<typename Ctx> Result<> makeRethrow(Ctx& ctx, Index pos) { @@ -1627,6 +1631,18 @@ template<typename Ctx> Result<typename Ctx::LabelIdxT> labelidx(Ctx& ctx) { return ctx.in.err("expected label index or identifier"); } +// tagidx ::= x:u32 => x +// | v:id => x (if tags[x] = v) +template<typename Ctx> Result<typename Ctx::TagIdxT> tagidx(Ctx& ctx) { + if (auto x = ctx.in.takeU32()) { + return ctx.getTagFromIdx(*x); + } + if (auto id = ctx.in.takeID()) { + return ctx.getTagFromName(*id); + } + return ctx.in.err("expected tag index or identifier"); +} + // typeuse ::= '(' 'type' x:typeidx ')' => x, [] // (if typedefs[x] = [t1*] -> [t2*] // | '(' 'type' x:typeidx ')' ((t1,IDs):param)* (t2:result)* => x, IDs @@ -2011,6 +2027,36 @@ template<typename Ctx> MaybeResult<> data(Ctx& ctx) { return Ok{}; } +// tag ::= '(' 'tag' id? ('(' 'export' name ')')* +// ('(' 'import' mod:name nm:name ')')? typeuse ')' +template<typename Ctx> MaybeResult<> tag(Ctx& ctx) { + auto pos = ctx.in.getPos(); + if (!ctx.in.takeSExprStart("tag"sv)) { + return {}; + } + + Name name; + if (auto id = ctx.in.takeID()) { + name = *id; + } + + auto exports = inlineExports(ctx.in); + CHECK_ERR(exports); + + auto import = inlineImport(ctx.in); + CHECK_ERR(import); + + auto type = typeuse(ctx); + CHECK_ERR(type); + + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected end of tag"); + } + + CHECK_ERR(ctx.addTag(name, *exports, import.getPtr(), *type, pos)); + return Ok{}; +} + // modulefield ::= deftype // | import // | func @@ -2021,6 +2067,7 @@ template<typename Ctx> MaybeResult<> data(Ctx& ctx) { // | start // | elem // | data +// | tag template<typename Ctx> MaybeResult<> modulefield(Ctx& ctx) { if (auto t = ctx.in.peek(); !t || t->isRParen()) { return {}; @@ -2045,6 +2092,10 @@ template<typename Ctx> MaybeResult<> modulefield(Ctx& ctx) { CHECK_ERR(res); return Ok{}; } + if (auto res = tag(ctx)) { + CHECK_ERR(res); + return Ok{}; + } return ctx.in.err("unrecognized module field"); } diff --git a/src/parser/wat-parser.cpp b/src/parser/wat-parser.cpp index 7e106d3b9..be3bca5c8 100644 --- a/src/parser/wat-parser.cpp +++ b/src/parser/wat-parser.cpp @@ -146,6 +146,7 @@ Result<> parseModule(Module& wasm, std::string_view input) { CHECK_ERR(parseDefs(ctx, decls.funcDefs, func)); CHECK_ERR(parseDefs(ctx, decls.memoryDefs, memory)); CHECK_ERR(parseDefs(ctx, decls.globalDefs, global)); + CHECK_ERR(parseDefs(ctx, decls.tagDefs, tag)); // TODO: Parse types of other module elements. } { diff --git a/src/parser/wat-parser.h b/src/parser/wat-parser.h index d3ad8d7f3..b31523af9 100644 --- a/src/parser/wat-parser.h +++ b/src/parser/wat-parser.h @@ -29,4 +29,4 @@ Result<> parseModule(Module& wasm, std::string_view in); } // namespace wasm::WATParser -#endif // paser_wat_parser_h +#endif // parser_wat_parser_h diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 1dd7a7e09..2f379b4e1 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -849,7 +849,7 @@ public: Throw* makeThrow(Tag* tag, const std::vector<Expression*>& args) { return makeThrow(tag->name, args); } - Throw* makeThrow(Name tag, const std::vector<Expression*>& args) { + template<typename T> Throw* makeThrow(Name tag, const T& args) { auto* ret = wasm.allocator.alloc<Throw>(); ret->tag = tag; ret->operands.set(args); diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 9b8ae043f..e7613b373 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -146,7 +146,7 @@ public: // [[nodiscard]] Result<> makeTableFill(); // [[nodiscard]] Result<> makeTableCopy(); // [[nodiscard]] Result<> makeTry(); - // [[nodiscard]] Result<> makeThrow(); + [[nodiscard]] Result<> makeThrow(Name tag); // [[nodiscard]] Result<> makeRethrow(); // [[nodiscard]] Result<> makeTupleMake(); // [[nodiscard]] Result<> makeTupleExtract(); @@ -203,6 +203,7 @@ public: [[nodiscard]] Result<> visitCall(Call*); [[nodiscard]] Result<> visitCallIndirect(CallIndirect*); [[nodiscard]] Result<> visitCallRef(CallRef*); + [[nodiscard]] Result<> visitThrow(Throw*); private: Module& wasm; diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp index a340b4c23..37d28ca4b 100644 --- a/src/wasm/wasm-io.cpp +++ b/src/wasm/wasm-io.cpp @@ -25,12 +25,11 @@ // #include "wasm-io.h" +#include "parser/wat-parser.h" #include "support/debug.h" #include "support/path.h" #include "wasm-binary.h" #include "wasm-s-parser.h" -#include "wat-parser.h" - namespace wasm { diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index dfbf156b2..9bca1967b 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -445,6 +445,17 @@ Result<> IRBuilder::visitCallRef(CallRef* curr) { return Ok{}; } +Result<> IRBuilder::visitThrow(Throw* curr) { + auto numArgs = wasm.getTag(curr->tag)->sig.params.size(); + curr->operands.resize(numArgs); + for (size_t i = 0; i < numArgs; ++i) { + auto arg = pop(); + CHECK_ERR(arg); + curr->operands[numArgs - 1 - i] = *arg; + } + return Ok{}; +} + Result<> IRBuilder::visitFunctionStart(Function* func) { if (!scopeStack.empty()) { return Err{"unexpected start of function"}; @@ -1005,7 +1016,13 @@ Result<> IRBuilder::makeRefEq() { // Result<> IRBuilder::makeTry() {} -// Result<> IRBuilder::makeThrow() {} +Result<> IRBuilder::makeThrow(Name tag) { + Throw curr(wasm.allocator); + curr.tag = tag; + CHECK_ERR(visitThrow(&curr)); + push(builder.makeThrow(tag, curr.operands)); + return Ok{}; +} // Result<> IRBuilder::makeRethrow() {} diff --git a/src/wat-parser.h b/src/wat-parser.h deleted file mode 100644 index bb31ed0b1..000000000 --- a/src/wat-parser.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 WebAssembly Community Group participants - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef wasm_wat_parser_h -#define wasm_wat_parser_h - -#include <string_view> - -#include "support/result.h" -#include "wasm.h" - -namespace wasm::WATParser { - -// Parse a single WAT module. -Result<> parseModule(Module& wasm, std::string_view in); - -} // namespace wasm::WATParser - -#endif // wasm_wat_parser.h |