diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/binaryen-c.cpp | 4 | ||||
-rw-r--r-- | src/binaryen-c.h | 4 | ||||
-rw-r--r-- | src/ir/table-utils.cpp | 19 | ||||
-rw-r--r-- | src/ir/table-utils.h | 5 | ||||
-rw-r--r-- | src/passes/Print.cpp | 13 | ||||
-rw-r--r-- | src/wasm-binary.h | 4 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 13 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 47 | ||||
-rw-r--r-- | test/example/c-api-multiple-tables.c | 1 | ||||
-rw-r--r-- | test/multi-table.wast | 9 | ||||
-rw-r--r-- | test/multi-table.wast.from-wast | 3 | ||||
-rw-r--r-- | test/multi-table.wast.fromBinary | 3 | ||||
-rw-r--r-- | test/multi-table.wast.fromBinary.noDebugInfo | 3 |
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) |