summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ir/CMakeLists.txt1
-rw-r--r--src/ir/table-utils.cpp73
-rw-r--r--src/ir/table-utils.h4
-rw-r--r--src/passes/Print.cpp11
-rw-r--r--src/wasm/wasm-binary.cpp28
-rw-r--r--src/wasm/wasm-s-parser.cpp8
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;
}