summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/binaryen-c.cpp4
-rw-r--r--src/binaryen-c.h4
-rw-r--r--src/ir/table-utils.cpp19
-rw-r--r--src/ir/table-utils.h5
-rw-r--r--src/passes/Print.cpp13
-rw-r--r--src/wasm-binary.h4
-rw-r--r--src/wasm/wasm-binary.cpp13
-rw-r--r--src/wasm/wasm-s-parser.cpp47
-rw-r--r--test/example/c-api-multiple-tables.c1
-rw-r--r--test/multi-table.wast9
-rw-r--r--test/multi-table.wast.from-wast3
-rw-r--r--test/multi-table.wast.fromBinary3
-rw-r--r--test/multi-table.wast.fromBinary.noDebugInfo3
14 files changed, 87 insertions, 43 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index af2b7617f..bac893cf1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,8 @@ full changeset diff at the end of each section.
Current Trunk
-------------
+- Add `BinaryenUpdateMaps` to the C API.
+
- Adds a TrapsNeverHappen mode (#4059). This has many of the benefits of
IgnoreImplicitTraps, but can be used safely in more cases. IgnoreImplicitTraps
is now deprecated.
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 15c4cb90e..68b0f86c2 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -3775,6 +3775,10 @@ void BinaryenModuleOptimize(BinaryenModuleRef module) {
passRunner.run();
}
+void BinaryenModuleUpdateMaps(BinaryenModuleRef module) {
+ ((Module*)module)->updateMaps();
+}
+
int BinaryenGetOptimizeLevel(void) { return globalPassOptions.optimizeLevel; }
void BinaryenSetOptimizeLevel(int level) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index dc8bb890f..b2c4351b1 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -2253,6 +2253,10 @@ BINARYEN_API bool BinaryenModuleValidate(BinaryenModuleRef module);
// global optimize and shrink level.
BINARYEN_API void BinaryenModuleOptimize(BinaryenModuleRef module);
+// Updates the internal name mapping logic in a module. This must be called
+// after renaming module elements.
+BINARYEN_API void BinaryenModuleUpdateMaps(BinaryenModuleRef module);
+
// Gets the currently set optimize level. Applies to all modules, globally.
// 0, 1, 2 correspond to -O0, -O1, -O2 (default), etc.
BINARYEN_API int BinaryenGetOptimizeLevel(void);
diff --git a/src/ir/table-utils.cpp b/src/ir/table-utils.cpp
index 80ef885f9..79b90d249 100644
--- a/src/ir/table-utils.cpp
+++ b/src/ir/table-utils.cpp
@@ -64,6 +64,25 @@ std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm) {
return ret;
}
+bool usesExpressions(ElementSegment* curr, Module* module) {
+ // Binaryen IR always has ref.funcs for functions in tables for uniformity,
+ // so that by itself does not indicate if expressions should be used when
+ // emitting the table or not. But definitely anything that is not a ref.func
+ // implies we are post-MVP and must use expressions.
+ bool allElementsRefFunc =
+ std::all_of(curr->data.begin(), curr->data.end(), [](Expression* entry) {
+ return entry->is<RefFunc>();
+ });
+
+ // If the table has a specialized (non-MVP) type, then the segment must
+ // declare a type that is a subtype of that, so it must use the post-MVP form
+ // of using expressions.
+ bool hasTableOfSpecializedType =
+ curr->table.is() && module->getTable(curr->table)->type != Type::funcref;
+
+ return !allElementsRefFunc || hasTableOfSpecializedType;
+}
+
} // namespace TableUtils
} // namespace wasm
diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h
index 99a5bbf5b..e4cf409c1 100644
--- a/src/ir/table-utils.h
+++ b/src/ir/table-utils.h
@@ -110,6 +110,11 @@ inline Index getOrAppend(Table& table, Name name, Module& wasm) {
// "elem declare" mention in the text and binary formats.
std::set<Name> getFunctionsNeedingElemDeclare(Module& wasm);
+// Returns whether a segment uses arbitrary wasm expressions, as opposed to the
+// original tables from the MVP that use function indices. (Some post-MVP tables
+// do so, and some do not, depending on their type and use.)
+bool usesExpressions(ElementSegment* curr, Module* module);
+
} // namespace TableUtils
} // namespace wasm
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 4fa38442c..616ce9759 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2735,12 +2735,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
}
}
void visitElementSegment(ElementSegment* curr) {
- bool allElementsRefFunc =
- std::all_of(curr->data.begin(), curr->data.end(), [](Expression* entry) {
- return entry->is<RefFunc>();
- });
+ bool usesExpressions = TableUtils::usesExpressions(curr, currModule);
auto printElemType = [&]() {
- if (allElementsRefFunc) {
+ if (!usesExpressions) {
o << "func";
} else {
printType(o, curr->type, currModule);
@@ -2758,7 +2755,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
}
if (curr->table.is()) {
- if (!allElementsRefFunc || currModule->tables.size() > 1) {
+ if (usesExpressions || currModule->tables.size() > 1) {
// tableuse
o << " (table ";
printName(curr->table, o);
@@ -2768,7 +2765,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
o << ' ';
visit(curr->offset);
- if (!allElementsRefFunc || currModule->tables.size() > 1) {
+ if (usesExpressions || currModule->tables.size() > 1) {
o << ' ';
printElemType();
}
@@ -2777,7 +2774,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
printElemType();
}
- if (allElementsRefFunc) {
+ if (!usesExpressions) {
for (auto* entry : curr->data) {
auto* refFunc = entry->cast<RefFunc>();
o << ' ';
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 260bacecf..13925f5e1 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -346,8 +346,8 @@ enum SegmentFlag {
// Bit 1 if active: 0 = index 0, 1 = index given
HasIndex = 1 << 1,
// Table element segments only:
- // Bit 2: 0 = elemType is funcref and vector of func indexes given
- // 1 = elemType is given and vector of ref expressions is given
+ // Bit 2: 0 = elemType is funcref and a vector of func indexes given
+ // 1 = elemType is given and a vector of ref expressions is given
UsesExpressions = 1 << 2
};
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index ab229f111..ee3c1a6fa 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -584,11 +584,8 @@ void WasmBinaryWriter::writeElementSegments() {
Index tableIdx = 0;
bool isPassive = segment->table.isNull();
- // if all items are ref.func, we can use the shorter form.
- bool usesExpressions =
- std::any_of(segment->data.begin(),
- segment->data.end(),
- [](Expression* curr) { return !curr->is<RefFunc>(); });
+ // If the segment is MVP, we can use the shorter form.
+ bool usesExpressions = TableUtils::usesExpressions(segment.get(), wasm);
bool hasTableIndex = false;
if (!isPassive) {
@@ -620,7 +617,7 @@ void WasmBinaryWriter::writeElementSegments() {
// elemType
writeType(segment->type);
} else {
- // elemKind funcref
+ // MVP elemKind of funcref
o << U32LEB(0);
}
}
@@ -2864,12 +2861,12 @@ void WasmBinaryBuilder::readElementSegments() {
if (usesExpressions) {
segment->type = getType();
if (!segment->type.isFunction()) {
- throwError("Invalid type for an element segment");
+ throwError("Invalid type for a usesExpressions element segment");
}
} else {
auto elemKind = getU32LEB();
if (elemKind != 0x0) {
- throwError("Only funcref elem kinds are valid.");
+ throwError("Invalid kind (!= funcref(0)) since !usesExpressions.");
}
}
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index c9c8235e2..c9ca71a6d 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -21,6 +21,7 @@
#include <limits>
#include "ir/branch-utils.h"
+#include "ir/table-utils.h"
#include "shared-constants.h"
#include "support/string.h"
#include "wasm-binary.h"
@@ -3368,6 +3369,11 @@ void SExpressionWasmBuilder::parseElem(Element& s, Table* table) {
segment->table = table->name;
}
+ // We may be post-MVP also due to type reasons or otherwise, as detected by
+ // the utility function for Binaryen IR.
+ usesExpressions =
+ usesExpressions || TableUtils::usesExpressions(segment.get(), &wasm);
+
parseElemFinish(s, segment, i, usesExpressions);
}
@@ -3377,30 +3383,29 @@ ElementSegment* SExpressionWasmBuilder::parseElemFinish(
Index i,
bool usesExpressions) {
- if (usesExpressions) {
- for (; i < s.size(); i++) {
- if (!s[i]->isList()) {
- throw ParseException("expected a ref.* expression.");
- }
- auto& inner = *s[i];
- if (elementStartsWith(inner, ITEM)) {
- if (inner[1]->isList()) {
- // (item (ref.func $f))
- segment->data.push_back(parseExpression(inner[1]));
- } else {
- // (item ref.func $f)
- inner.list().removeAt(0);
- segment->data.push_back(parseExpression(inner));
- }
- } else {
- segment->data.push_back(parseExpression(inner));
- }
- }
- } else {
- for (; i < s.size(); i++) {
+ for (; i < s.size(); i++) {
+ if (!s[i]->isList()) {
+ // An MVP-style declaration: just a function name.
auto func = getFunctionName(*s[i]);
segment->data.push_back(
Builder(wasm).makeRefFunc(func, functionTypes[func]));
+ continue;
+ }
+ if (!usesExpressions) {
+ throw ParseException("expected an MVP-style $funcname in elem.");
+ }
+ auto& inner = *s[i];
+ if (elementStartsWith(inner, ITEM)) {
+ if (inner[1]->isList()) {
+ // (item (ref.func $f))
+ segment->data.push_back(parseExpression(inner[1]));
+ } else {
+ // (item ref.func $f)
+ inner.list().removeAt(0);
+ segment->data.push_back(parseExpression(inner));
+ }
+ } else {
+ segment->data.push_back(parseExpression(inner));
}
}
return wasm.addElementSegment(std::move(segment));
diff --git a/test/example/c-api-multiple-tables.c b/test/example/c-api-multiple-tables.c
index f3a9ba8dd..7cd215bf9 100644
--- a/test/example/c-api-multiple-tables.c
+++ b/test/example/c-api-multiple-tables.c
@@ -64,6 +64,7 @@ int main() {
assert(strcmp(BinaryenTableGetName(t2), "t2") == 0);
BinaryenTableSetName(t2, "table2");
+ BinaryenModuleUpdateMaps(module);
assert(strcmp(BinaryenTableGetName(t2), "table2") == 0);
BinaryenElementSegmentSetTable(elem1, "table2");
assert(strcmp(BinaryenElementSegmentGetTable(elem1), "table2") == 0);
diff --git a/test/multi-table.wast b/test/multi-table.wast
index a98c9e4b0..6d4610aad 100644
--- a/test/multi-table.wast
+++ b/test/multi-table.wast
@@ -9,6 +9,9 @@
(table $t3 4 4 funcref)
(table $textern 0 externref)
+ ;; A table with a typed function references specialized type.
+ (table $tspecial 5 5 (ref null $none_=>_none))
+
;; add to $t1
(elem (i32.const 0) $f)
@@ -25,7 +28,11 @@
(elem $empty func)
(elem $declarative declare func $h)
+ ;; This elem will be emitted as usesExpressions because of the type of the
+ ;; table.
+ (elem $especial (table $tspecial) (i32.const 0) (ref null $none_=>_none) $f $h)
+
(func $f (drop (ref.func $h)))
(func $g)
(func $h)
-) \ No newline at end of file
+)
diff --git a/test/multi-table.wast.from-wast b/test/multi-table.wast.from-wast
index 474e89c53..73a9abea3 100644
--- a/test/multi-table.wast.from-wast
+++ b/test/multi-table.wast.from-wast
@@ -6,6 +6,7 @@
(table $t2 3 3 funcref)
(table $t3 4 4 funcref)
(table $textern 0 externref)
+ (table $tspecial 5 5 (ref null $none_=>_none))
(elem $0 (table $t1) (i32.const 0) func $f)
(elem $1 (table $t2) (i32.const 0) func $f)
(elem $activeNonZeroOffset (table $t2) (i32.const 1) func $f $g)
@@ -15,7 +16,7 @@
(elem $passive-2 funcref (ref.func $f) (ref.func $g) (ref.null func))
(elem $passive-3 (ref null $none_=>_none) (ref.func $f) (ref.func $g) (ref.null $none_=>_none) (global.get $g1))
(elem $empty func)
- (elem declare func $h)
+ (elem $especial (table $tspecial) (i32.const 0) (ref null $none_=>_none) (ref.func $f) (ref.func $h))
(func $f
(drop
(ref.func $h)
diff --git a/test/multi-table.wast.fromBinary b/test/multi-table.wast.fromBinary
index 809740549..427fb44f3 100644
--- a/test/multi-table.wast.fromBinary
+++ b/test/multi-table.wast.fromBinary
@@ -6,6 +6,7 @@
(table $t2 3 3 funcref)
(table $t3 4 4 funcref)
(table $textern 0 externref)
+ (table $tspecial 5 5 (ref null $none_=>_none))
(elem $0 (table $t1) (i32.const 0) func $f)
(elem $1 (table $t2) (i32.const 0) func $f)
(elem $activeNonZeroOffset (table $t2) (i32.const 1) func $f $g)
@@ -15,7 +16,7 @@
(elem $passive-2 funcref (ref.func $f) (ref.func $g) (ref.null func))
(elem $passive-3 (ref null $none_=>_none) (ref.func $f) (ref.func $g) (ref.null $none_=>_none) (global.get $g1))
(elem $empty func)
- (elem declare func $h)
+ (elem $especial (table $tspecial) (i32.const 0) (ref null $none_=>_none) (ref.func $f) (ref.func $h))
(func $f
(drop
(ref.func $h)
diff --git a/test/multi-table.wast.fromBinary.noDebugInfo b/test/multi-table.wast.fromBinary.noDebugInfo
index 1fcd2a9be..7fc667087 100644
--- a/test/multi-table.wast.fromBinary.noDebugInfo
+++ b/test/multi-table.wast.fromBinary.noDebugInfo
@@ -6,6 +6,7 @@
(table $0 3 3 funcref)
(table $1 4 4 funcref)
(table $2 0 externref)
+ (table $3 5 5 (ref null $none_=>_none))
(elem $0 (table $timport$0) (i32.const 0) func $0)
(elem $1 (table $0) (i32.const 0) func $0)
(elem $2 (table $0) (i32.const 1) func $0 $1)
@@ -15,7 +16,7 @@
(elem $6 funcref (ref.func $0) (ref.func $1) (ref.null func))
(elem $7 (ref null $none_=>_none) (ref.func $0) (ref.func $1) (ref.null $none_=>_none) (global.get $global$0))
(elem $8 func)
- (elem declare func $2)
+ (elem $9 (table $3) (i32.const 0) (ref null $none_=>_none) (ref.func $0) (ref.func $2))
(func $0
(drop
(ref.func $2)