diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ir/table-utils.cpp | 73 | ||||
-rw-r--r-- | src/ir/table-utils.h | 4 | ||||
-rw-r--r-- | src/passes/Print.cpp | 11 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 28 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 8 |
6 files changed, 124 insertions, 1 deletions
diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index e2bad94bd..40868899d 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -5,6 +5,7 @@ set(ir_SOURCES LocalGraph.cpp ReFinalize.cpp stack-utils.cpp + table-utils.cpp module-splitting.cpp ${ir_HEADERS} ) diff --git a/src/ir/table-utils.cpp b/src/ir/table-utils.cpp new file mode 100644 index 000000000..ef89e50f3 --- /dev/null +++ b/src/ir/table-utils.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2021 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. + */ + +#include "table-utils.h" +#include "find_all.h" +#include "module-utils.h" + +namespace wasm { + +namespace TableUtils { + +std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm) { + // Without reference types there are no ref.funcs or elem declare. + if (!wasm.features.hasReferenceTypes()) { + return {}; + } + + // Find all the names in the tables. + + std::unordered_set<Name> tableNames; + for (auto& table : wasm.tables) { + for (auto& segment : table->segments) { + for (auto name : segment.data) { + tableNames.insert(name); + } + } + } + + // Find all the names in ref.funcs. + using Names = std::unordered_set<Name>; + + ModuleUtils::ParallelFunctionAnalysis<Names> analysis( + wasm, [&](Function* func, Names& names) { + if (func->imported()) { + return; + } + for (auto* refFunc : FindAll<RefFunc>(func->body).list) { + names.insert(refFunc->func); + } + }); + + // Find the names that need to be declared. + + std::set<Name> ret; + + for (auto& kv : analysis.map) { + auto& names = kv.second; + for (auto name : names) { + if (!tableNames.count(name)) { + ret.insert(name); + } + } + } + + return ret; +} + +} // namespace TableUtils + +} // namespace wasm diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h index da0bb7241..80ffc0c06 100644 --- a/src/ir/table-utils.h +++ b/src/ir/table-utils.h @@ -94,6 +94,10 @@ inline Index getOrAppend(Table& table, Name name, Module& wasm) { return append(table, name, wasm); } +// Functions that we take a reference to, but are not in a Table, but get an +// "elem declare" mention in the text and binary formats. +std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm); + } // namespace TableUtils } // namespace wasm diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 0a25430cb..993eddb99 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -20,6 +20,7 @@ #include <ir/iteration.h> #include <ir/module-utils.h> +#include <ir/table-utils.h> #include <pass.h> #include <pretty_printing.h> #include <wasm-stack.h> @@ -2832,6 +2833,16 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { *curr, [&](Memory* memory) { visitMemory(memory); }); ModuleUtils::iterDefinedTables(*curr, [&](Table* table) { visitTable(table); }); + auto elemDeclareNames = TableUtils::getFunctionsNeedingElemDeclare(*curr); + if (!elemDeclareNames.empty()) { + doIndent(o, indent); + printMedium(o, "(elem"); + o << " declare func"; + for (auto name : elemDeclareNames) { + o << " $" << name; + } + o << ')' << maybeNewLine; + } ModuleUtils::iterDefinedGlobals( *curr, [&](Global* global) { visitGlobal(global); }); ModuleUtils::iterDefinedEvents(*curr, diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index d5579eedf..0993eb124 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -18,6 +18,7 @@ #include <fstream> #include "ir/module-utils.h" +#include "ir/table-utils.h" #include "support/bits.h" #include "support/debug.h" #include "wasm-binary.h" @@ -548,6 +549,10 @@ void WasmBinaryWriter::writeTableElements() { for (auto& table : wasm->tables) { elemCount += table->segments.size(); } + auto needingElemDecl = TableUtils::getFunctionsNeedingElemDeclare(*wasm); + if (!needingElemDecl.empty()) { + elemCount++; + } if (elemCount == 0) { return; } @@ -588,6 +593,16 @@ void WasmBinaryWriter::writeTableElements() { } } } + + if (!needingElemDecl.empty()) { + o << U32LEB(BinaryConsts::IsPassive | BinaryConsts::IsDeclarative); + o << U32LEB(0); // type (indicating funcref) + o << U32LEB(needingElemDecl.size()); + for (auto name : needingElemDecl) { + o << U32LEB(indexes.functionIndexes[name]); + } + } + finishSection(start); } @@ -2677,6 +2692,19 @@ void WasmBinaryBuilder::readTableElements() { bool usesExpressions = (flags & BinaryConsts::UsesExpressions) != 0; if (isPassive) { + bool isDeclarative = (flags & BinaryConsts::IsDeclarative) != 0; + if (isDeclarative) { + // "elem declare" is needed in wasm text and binary, but not in Binaryen + // IR; read and ignore the contents. + auto type = getU32LEB(); + WASM_UNUSED(type); + auto num = getU32LEB(); + for (Index i = 0; i < num; i++) { + getU32LEB(); + } + continue; + } + throwError("Only active elem segments are supported."); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 3baf19063..31ae188d0 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -51,7 +51,7 @@ int unhex(char c) { namespace wasm { static Name STRUCT("struct"), FIELD("field"), ARRAY("array"), I8("i8"), - I16("i16"), RTT("rtt"); + I16("i16"), RTT("rtt"), DECLARE("declare"); static Address getAddress(const Element* s) { return atoll(s->c_str()); } @@ -3257,6 +3257,7 @@ void SExpressionWasmBuilder::parseTable(Element& s, bool preParseImport) { // elem ::= (elem (expr) vec(funcidx)) // | (elem (offset (expr)) func vec(funcidx)) // | (elem (table tableidx) (offset (expr)) func vec(funcidx)) +// | (elem declare func $foo) // // abbreviation: // (offset (expr)) ≡ (expr) @@ -3270,6 +3271,11 @@ void SExpressionWasmBuilder::parseElem(Element& s) { if (!s[i]->isList()) { // optional segment id OR 'declare' OR start of elemList + if (s[i]->str() == DECLARE) { + // "elem declare" is needed in wasm text and binary, but not in Binaryen + // IR; ignore the contents. + return; + } i += 1; } |