From 1156ba625e0f6e5b4748a7f5af1745f714a62144 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 23 Jan 2026 00:16:49 +0000 Subject: [PATCH 1/2] Fix table grow spec test --- scripts/test/shared.py | 1 - src/ir/runtime-table.h | 10 +++++++++- src/ir/table-utils.cpp | 5 ----- src/ir/table-utils.h | 3 +-- src/passes/Print.cpp | 7 +++++++ src/wasm-interpreter.h | 26 ++++++++++++++++++++------ src/wasm.h | 1 + 7 files changed, 38 insertions(+), 15 deletions(-) diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 5116fb0c1bf..fe03854e14d 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -428,7 +428,6 @@ def get_tests(test_dir, extensions=[], recursive=False): # and splitting for module instances 'instance.wast', 'table64.wast', # Requires validations for table size - 'table_grow.wast', # Incorrect table linking semantics in interpreter 'tag.wast', # Non-empty tag results allowed by stack switching 'try_table.wast', # Requires try_table interpretation 'local_init.wast', # Requires local validation to respect unnamed blocks diff --git a/src/ir/runtime-table.h b/src/ir/runtime-table.h index 54bf23f2c30..5867dc740b9 100644 --- a/src/ir/runtime-table.h +++ b/src/ir/runtime-table.h @@ -41,7 +41,15 @@ class RuntimeTable { virtual std::size_t size() const = 0; - virtual const Table* tableMeta() const { return &tableMeta_; } + // True iff this is a subtype of the definition `other`. i.e. This table can + // be imported with the definition of `other` + virtual bool isSubType(const Table& other) { + return tableMeta_.addressType == other.addressType && + Type::isSubType(tableMeta_.type, other.type) && + size() >= other.initial && tableMeta_.max <= other.max; + } + + const Table* tableMeta() const { return &tableMeta_; } protected: const Table tableMeta_; diff --git a/src/ir/table-utils.cpp b/src/ir/table-utils.cpp index 18fefb5ee36..364f7ba324a 100644 --- a/src/ir/table-utils.cpp +++ b/src/ir/table-utils.cpp @@ -21,11 +21,6 @@ namespace wasm::TableUtils { -bool isSubType(const Table& a, const Table& b) { - return a.addressType == b.addressType && Type::isSubType(a.type, b.type) && - a.initial >= b.initial && a.max <= b.max; -} - std::set getFunctionsNeedingElemDeclare(Module& wasm) { // Without reference types there are no ref.funcs or elem declare. if (!wasm.features.hasReferenceTypes()) { diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h index 6090b05a157..72c7c83eedc 100644 --- a/src/ir/table-utils.h +++ b/src/ir/table-utils.h @@ -20,14 +20,13 @@ #include "ir/element-utils.h" #include "ir/literal-utils.h" #include "ir/module-utils.h" +#include "ir/runtime-table.h" #include "support/stdckdint.h" #include "wasm-traversal.h" #include "wasm.h" namespace wasm::TableUtils { -bool isSubType(const Table& a, const Table& b); - struct FlatTable { std::vector names; bool valid; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index e54d3eebdff..87e0d3239fb 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3970,4 +3970,11 @@ std::ostream& operator<<(std::ostream& os, wasm::MemoryOrder mo) { return os; } +std::ostream& operator<<(std::ostream& o, const Table& table) { + wasm::PrintSExpression printer(o); + // TODO: printTableHeader should take a const Table* + printer.printTableHeader(const_cast(&table)); + return o; +} + } // namespace wasm diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 6563b2709cc..3b2c5d8b7ff 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3364,6 +3364,9 @@ class ModuleRunnerBase : public ExpressionRunner { // Trap if types don't match between all imports and their corresponding // exports. Imported memories and tables must also be a subtype of their // export. + // TODO: we should also *resolve* the imports here e.g. by writing to + // allGlobals / allTables etc. First finish migrating all imports here, then + // enable this code to run in all cases e.g. ctor-eval. void validateImports() { ModuleUtils::iterImportable( wasm, @@ -3374,6 +3377,8 @@ class ModuleRunnerBase : public ExpressionRunner { // These two modules are injected implicitly to tests. We won't find any // import information for them. + // TODO: remove this workaround once we have a better way of handling + // intrinsic / spec function imports. if (importable->module == "binaryen-intrinsics" || (importable->module == "spectest" && importable->base.startsWith("print")) || @@ -3399,12 +3404,21 @@ class ModuleRunnerBase : public ExpressionRunner { } } - // TODO: Use the table's runtime information when checking this. - if (auto** table = std::get_if(&import)) { - Table* exportedTable = - importedInstance->wasm.getTable(*export_->getInternalName()); - if (!TableUtils::isSubType(*exportedTable, **table)) { - trap("Imported table isn't compatible"); + if (auto** tableDecl = std::get_if(&import)) { + auto* importedTable = importResolver->getTableOrNull( + importable->importNames(), **tableDecl); + if (!importedTable) { + trap((std::stringstream() << "No imported table found for export " + << importable->importNames()) + .str()); + } + if (!importedTable->isSubType(**tableDecl)) { + trap( + (std::stringstream() + << "Imported table " << importedTable->tableMeta() + << " with size " << importedTable->size() + << " isn't compatible with import declaration: " << **tableDecl) + .str()); } } }); diff --git a/src/wasm.h b/src/wasm.h index ab6323b5f35..eaacd05fa16 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -2663,6 +2663,7 @@ std::ostream& operator<<(std::ostream& o, wasm::ModuleType pair); std::ostream& operator<<(std::ostream& o, wasm::ModuleHeapType pair); std::ostream& operator<<(std::ostream& os, wasm::MemoryOrder mo); std::ostream& operator<<(std::ostream& o, const wasm::ImportNames& importNames); +std::ostream& operator<<(std::ostream& o, const Table& table); } // namespace wasm From 54db16e6c52abe5ffcafb44468b565736aa811b8 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 23 Jan 2026 18:47:02 +0000 Subject: [PATCH 2/2] PR updates --- src/ir/runtime-table.h | 4 +++- src/ir/table-utils.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ir/runtime-table.h b/src/ir/runtime-table.h index 5867dc740b9..a8deaa4f6c6 100644 --- a/src/ir/runtime-table.h +++ b/src/ir/runtime-table.h @@ -25,7 +25,9 @@ namespace wasm { -// Traps on out of bounds access +// Runtime representation of a table for interpreting use cases e.g. +// wasm-interpreter.h. Effectively a vector of Literal. Throws TrapException on +// out-of-bounds access. class RuntimeTable { public: RuntimeTable(Table table) : tableMeta_(table) {} diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h index 72c7c83eedc..cee88fcdbc7 100644 --- a/src/ir/table-utils.h +++ b/src/ir/table-utils.h @@ -20,7 +20,6 @@ #include "ir/element-utils.h" #include "ir/literal-utils.h" #include "ir/module-utils.h" -#include "ir/runtime-table.h" #include "support/stdckdint.h" #include "wasm-traversal.h" #include "wasm.h"