diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index 2dce7c22509..a67ee5a91d3 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -20,6 +20,7 @@ set(ir_SOURCES public-type-validator.cpp ReFinalize.cpp return-utils.cpp + runtime-table.cpp stack-utils.cpp table-utils.cpp type-updating.cpp diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index 0c75704d609..2e32120d752 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -18,6 +18,7 @@ #define wasm_ir_import_h #include "ir/import-name.h" +#include "ir/runtime-table.h" #include "literal.h" #include "wasm.h" @@ -131,6 +132,10 @@ class ImportResolver { // Returns null if the `name` wasn't found. The returned Literals* lives as // long as the ImportResolver instance. virtual Literals* getGlobalOrNull(ImportNames name, Type type) const = 0; + + // TODO: new type for TableType or just re-use the existing one? + virtual RuntimeTable* getTableOrNull(ImportNames name, + const Table& type) const = 0; }; // Looks up imports from the given `linkedInstances`. @@ -151,6 +156,17 @@ class LinkedInstancesImportResolver : public ImportResolver { return instance->getExportedGlobalOrNull(name.name); } + RuntimeTable* getTableOrNull(ImportNames name, + const Table& type) const override { + auto it = linkedInstances.find(name.module); + if (it == linkedInstances.end()) { + return nullptr; + } + + ModuleRunnerType* instance = it->second.get(); + return instance->getExportedTableOrNull(name.name); + } + private: const std::map> linkedInstances; }; diff --git a/src/ir/runtime-table.cpp b/src/ir/runtime-table.cpp new file mode 100644 index 00000000000..91b3a7cc6ec --- /dev/null +++ b/src/ir/runtime-table.cpp @@ -0,0 +1,41 @@ +#include "ir/runtime-table.h" +#include "support/stdckdint.h" +#include "wasm-limits.h" + +namespace wasm { + +void RuntimeTable::set(std::size_t i, Literal l) { + if (i >= table.size()) { + trap("RuntimeTable::set out of bounds"); + WASM_UNREACHABLE("trapped"); + } + + table[i] = std::move(l); +} + +Literal RuntimeTable::get(std::size_t i) const { + if (i >= table.size()) { + trap("out of bounds table access"); + WASM_UNREACHABLE("trapped"); + } + + return table[i]; +} + +std::optional RuntimeTable::grow(std::size_t delta, Literal fill) { + std::size_t newSize; + if (std::ckd_add(&newSize, table.size(), delta)) { + return std::nullopt; + } + + // TODO: this size is different than in wasm-interpreter.h + if (newSize > WebLimitations::MaxTableSize || newSize > tableMeta_.max) { + return std::nullopt; + } + + std::size_t oldSize = table.size(); + table.resize(newSize, fill); + return oldSize; +} + +} // namespace wasm diff --git a/src/ir/runtime-table.h b/src/ir/runtime-table.h new file mode 100644 index 00000000000..0ad2b535d67 --- /dev/null +++ b/src/ir/runtime-table.h @@ -0,0 +1,39 @@ +#ifndef wasm_ir_runtime_table_h +#define wasm_ir_runtime_table_h + +#include +#include + +#include "literal.h" +#include "wasm.h" + +namespace wasm { + +// Traps on out of bounds access +class RuntimeTable { +public: + // TODO: constructor for initial contents? + RuntimeTable(Table table_, std::function trap_) + : tableMeta_(table_), trap(trap_) {} + + void set(std::size_t i, Literal l); + + Literal get(std::size_t i) const; + + // Returns nullopt if the table grew beyond the max possible size. + [[nodiscard]] std::optional grow(std::size_t delta, + Literal fill); + + std::size_t size() const { return table.size(); } + + const Table* tableMeta() const { return &tableMeta_; } + +private: + const Table tableMeta_; + std::vector table; + std::function trap; +}; + +} // namespace wasm + +#endif // wasm_ir_runtime_table_h diff --git a/src/shell-interface.h b/src/shell-interface.h index 6fa7d8af1a8..4a08506fad3 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -93,7 +93,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { }; std::map memories; - std::unordered_map> tables; std::map> linkedInstances; ShellExternalInterface( @@ -125,8 +124,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { shellMemory.resize(memory->initial * wasm::Memory::kPageSize); memories[memory->name] = shellMemory; }); - ModuleUtils::iterDefinedTables( - wasm, [&](Table* table) { tables[table->name].resize(table->initial); }); } Literal getImportedFunction(Function* import) override { @@ -255,35 +252,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { auto& memory = it->second; memory.set>(addr, value); } - - Index tableSize(Name tableName) override { - return (Index)tables[tableName].size(); - } - - void - tableStore(Name tableName, Address index, const Literal& entry) override { - auto& table = tables[tableName]; - if (index >= table.size()) { - trap("out of bounds table access"); - } else { - table[index] = entry; - } - } - - Literal tableLoad(Name tableName, Address index) override { - auto it = tables.find(tableName); - if (it == tables.end()) { - trap("tableGet on non-existing table"); - } - - auto& table = it->second; - if (index >= table.size()) { - trap("out of bounds table access"); - } - - return table[index]; - } - bool growMemory(Name memoryName, Address /*oldSize*/, Address newSize) override { // Apply a reasonable limit on memory size, 1GB, to avoid DOS on the @@ -299,20 +267,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { memory.resize(newSize); return true; } - - bool growTable(Name name, - const Literal& value, - Index /*oldSize*/, - Index newSize) override { - // Apply a reasonable limit on table size, 1GB, to avoid DOS on the - // interpreter. - if (newSize > 1024 * 1024 * 1024) { - return false; - } - tables[name].resize(newSize, value); - return true; - } - void trap(std::string_view why) override { std::cout << "[trap " << why << "]\n"; throw TrapException(); diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 83f861ab7d4..bec95777bae 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -142,19 +142,21 @@ struct LoggingExternalInterface : public ShellExternalInterface { throwJSException(); } auto index = arguments[0].getUnsigned(); - if (index >= tables[exportedTable].size()) { + auto* table = instance->allTables[exportedTable]; + if (index >= table->size()) { throwJSException(); } - return {tableLoad(exportedTable, index)}; + return table->get(index); } else if (import->base == "table-set") { if (!exportedTable) { throwJSException(); } auto index = arguments[0].getUnsigned(); - if (index >= tables[exportedTable].size()) { + auto* table = instance->allTables[exportedTable]; + if (index >= table->size()) { throwJSException(); } - tableStore(exportedTable, index, arguments[1]); + table->set(index, arguments[1]); return {}; } else if (import->base == "call-export") { callExportAsJS(arguments[0].geti32()); diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 1407682faf9..dd2bbc4f12d 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -33,6 +33,7 @@ #include "ir/memory-utils.h" #include "ir/names.h" #include "pass.h" +#include "shell-interface.h" #include "support/colors.h" #include "support/file.h" #include "support/insert_ordered.h" @@ -80,6 +81,11 @@ class EvallingImportResolver : public ImportResolver { return &stubLiteral; } + RuntimeTable* getTableOrNull(ImportNames name, + const Table& type) const override { + throw FailToEvalException{"Imported table access."}; + } + private: mutable Literals stubLiteral; }; @@ -156,17 +162,6 @@ std::unique_ptr buildEnvModule(Module& wasm) { } }); - // create tables with similar initial and max values - ModuleUtils::iterImportedTables(wasm, [&](Table* table) { - if (table->module == env->name) { - auto* copied = ModuleUtils::copyTable(table, *env); - copied->module = Name(); - copied->base = Name(); - env->addExport(Builder(*env).makeExport( - table->base, copied->name, ExternalKind::Table)); - } - }); - // create an exported memory with the same initial and max size ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) { if (memory->module == env->name) { @@ -315,70 +310,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { WASM_UNREACHABLE("missing imported tag"); } - // We assume the table is not modified FIXME - Literal tableLoad(Name tableName, Address index) override { - auto* table = wasm->getTableOrNull(tableName); - if (!table) { - throw FailToEvalException("tableLoad on non-existing table"); - } - - // Look through the segments and find the value. Segments can overlap, - // so we want the last one. - Expression* value = nullptr; - for (auto& segment : wasm->elementSegments) { - if (segment->table != tableName) { - continue; - } - - Index start; - // look for the index in this segment. if it has a constant offset, we - // look in the proper range. if it instead gets a global, we rely on the - // fact that when not dynamically linking then the table is loaded at - // offset 0. - if (auto* c = segment->offset->dynCast()) { - start = c->value.getInteger(); - } else if (segment->offset->is()) { - start = 0; - } else { - // wasm spec only allows const and global.get there - WASM_UNREACHABLE("invalid expr type"); - } - auto end = start + segment->data.size(); - if (start <= index && index < end) { - value = segment->data[index - start]; - } - } - - if (!value) { - // No segment had a value for this. - return Literal::makeNull(HeapTypes::func); - } - if (!Properties::isConstantExpression(value)) { - throw FailToEvalException("tableLoad of non-literal"); - } - if (auto* r = value->dynCast()) { - return instance->makeFuncData(r->func, r->type); - } - return Properties::getLiteral(value); - } - - Index tableSize(Name tableName) override { - // See tableLoad above, we assume the table is not modified FIXME - return wasm->getTableOrNull(tableName)->initial; - } - - // called during initialization - void - tableStore(Name tableName, Address index, const Literal& value) override { - // We allow stores to the table during initialization, but not after, as we - // assume the table does not change at runtime. - // TODO: Allow table changes by updating the table later like we do with the - // memory, by tracking and serializing them. - if (instanceInitialized) { - throw FailToEvalException("tableStore after init: TODO"); - } - } - int8_t load8s(Address addr, Name memoryName) override { return doLoad(addr, memoryName); } @@ -431,13 +362,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { throw FailToEvalException("grow memory"); } - bool growTable(Name /*name*/, - const Literal& /*value*/, - Index /*oldSize*/, - Index /*newSize*/) override { - throw FailToEvalException("grow table"); - } - void trap(std::string_view why) override { throw FailToEvalException(std::string("trap: ") + std::string(why)); } @@ -1145,6 +1069,9 @@ EvalCtorOutcome evalCtor(EvallingModuleRunner& instance, std::cout << " ...stopping due to non-constant func\n"; } break; + } catch (TrapException trap) { + std::cout << " ...stopping due to trap"; + break; } if (flow.breakTo == NONCONSTANT_FLOW) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 89b767af2aa..6eb180cd2d9 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -41,6 +41,7 @@ #include "ir/memory-utils.h" #include "ir/module-utils.h" #include "ir/properties.h" +#include "ir/runtime-table.h" #include "ir/table-utils.h" #include "support/bits.h" #include "support/safe_integer.h" @@ -2973,10 +2974,6 @@ class ModuleRunnerBase : public ExpressionRunner { virtual void init(Module& wasm, SubType& instance) {} virtual Literal getImportedFunction(Function* import) = 0; virtual bool growMemory(Name name, Address oldSize, Address newSize) = 0; - virtual bool growTable(Name name, - const Literal& value, - Index oldSize, - Index newSize) = 0; virtual void trap(std::string_view why) = 0; virtual void hostLimit(std::string_view why) = 0; virtual void throwException(const WasmException& exn) = 0; @@ -3158,16 +3155,6 @@ class ModuleRunnerBase : public ExpressionRunner { store128(Address addr, const std::array&, Name memoryName) { WASM_UNREACHABLE("unimp"); } - - virtual Index tableSize(Name tableName) = 0; - - virtual void - tableStore(Name tableName, Address index, const Literal& entry) { - WASM_UNREACHABLE("unimp"); - } - virtual Literal tableLoad(Name tableName, Address index) { - WASM_UNREACHABLE("unimp"); - } }; SubType* self() { return static_cast(this); } @@ -3183,6 +3170,8 @@ class ModuleRunnerBase : public ExpressionRunner { // of this instance and other instances. std::map allGlobals; + std::map allTables; + ModuleRunnerBase( Module& wasm, ExternalInterface* externalInterface, @@ -3217,13 +3206,13 @@ class ModuleRunnerBase : public ExpressionRunner { // initialize the rest of the external interface externalInterface->init(wasm, *self()); - initializeGlobals(); - if (validateImports_) { validateImports(); } - initializeTableContents(); + initializeGlobals(); + initializeTables(); + initializeMemoryContents(); // run start, if present @@ -3272,6 +3261,19 @@ class ModuleRunnerBase : public ExpressionRunner { return iter->second; } + RuntimeTable* getExportedTableOrNull(Name name) { + Export* export_ = wasm.getExportOrNull(name); + if (!export_ || export_->kind != ExternalKind::Table) { + return nullptr; + } + Name internalName = *export_->getInternalName(); + auto iter = allTables.find(internalName); + if (iter == allTables.end()) { + return nullptr; + } + return iter->second; + } + Literals& getExportedGlobalOrTrap(Name name) { auto* global = getExportedGlobalOrNull(name); if (!global) { @@ -3309,6 +3311,7 @@ class ModuleRunnerBase : public ExpressionRunner { // `allGlobals` contains these values + imported globals, keyed by their // internal name. std::vector definedGlobals; + std::vector definedTables; // Keep a record of call depth, to guard against excessive recursion. size_t callDepth = 0; @@ -3320,15 +3323,6 @@ class ModuleRunnerBase : public ExpressionRunner { std::unordered_set droppedDataSegments; std::unordered_set droppedElementSegments; - struct TableInstanceInfo { - // The ModuleRunner instance in which the memory is defined. - SubType* instance; - // The external interface in which the table is defined - ExternalInterface* interface() { return instance->externalInterface; } - // The name the table has in that interface. - Name name; - }; - // Validates that the export that provides `importable` exists and has the // same kind that the import expects (`kind`). void validateImportKindMatches(ExternalKind kind, @@ -3394,6 +3388,7 @@ 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()); @@ -3404,18 +3399,6 @@ class ModuleRunnerBase : public ExpressionRunner { }); } - TableInstanceInfo getTableInstanceInfo(Name name) { - auto* table = wasm.getTable(name); - if (table->imported()) { - auto& importedInstance = linkedInstances.at(table->module); - auto* tableExport = importedInstance->wasm.getExport(table->base); - return importedInstance->getTableInstanceInfo( - *tableExport->getInternalName()); - } - - return TableInstanceInfo{self(), name}; - } - void initializeGlobals() { int definedGlobalCount = 0; ModuleUtils::iterDefinedGlobals( @@ -3451,14 +3434,41 @@ class ModuleRunnerBase : public ExpressionRunner { } } - void initializeTableContents() { + void initializeTables() { + int definedTableCount = 0; + ModuleUtils::iterDefinedTables( + wasm, [&definedTableCount](auto&& _) { ++definedTableCount; }); + definedTables.reserve(definedTableCount); + for (auto& table : wasm.tables) { - if (table->type.isNullable()) { - // Initial with nulls in a nullable table. - auto info = getTableInstanceInfo(table->name); - auto null = Literal::makeNull(table->type.getHeapType()); - for (Address i = 0; i < table->initial; i++) { - info.interface()->tableStore(info.name, i, null); + if (table->imported()) { + auto importNames = table->importNames(); + auto* importedTable = + importResolver->getTableOrNull(importNames, *table); + if (!importedTable) { + externalInterface->trap((std::stringstream() + << "Imported table " << importNames + << " not found.") + .str()); + } + auto [_, inserted] = allTables.try_emplace(table->name, importedTable); + (void)inserted; // for noassert builds + // parsing/validation checked this already. + assert(inserted && "Unexpected repeated table name"); + } else { + auto& runtimeTable = definedTables.emplace_back( + *table, [this](std::string_view s) { externalInterface->trap(s); }); + auto [_, inserted] = allTables.try_emplace(table->name, &runtimeTable); + (void)inserted; // for noassert builds + assert(inserted && "Unexpected repeated table name"); + + if (table->type.isNullable()) { + // Initial with nulls in a nullable table. + auto null = Literal::makeNull(table->type.getHeapType()); + // TODO? + if (!runtimeTable.grow(table->initial, null)) { + externalInterface->trap("Failed to create initial table"); + } } } } @@ -3728,11 +3738,10 @@ class ModuleRunnerBase : public ExpressionRunner { VISIT(target, curr->target) auto index = target.getSingleValue().getUnsigned(); - auto info = getTableInstanceInfo(curr->table); Literal funcref; if (!self()->isResuming()) { // Normal execution: Load from the table. - funcref = info.interface()->tableLoad(info.name, index); + funcref = allTables[curr->table]->get(index); } else { // Use the stashed funcref (see below). auto entry = self()->popResumeEntry("call_indirect"); @@ -3812,70 +3821,54 @@ class ModuleRunnerBase : public ExpressionRunner { Flow visitTableGet(TableGet* curr) { VISIT(index, curr->index) - auto info = getTableInstanceInfo(curr->table); auto address = index.getSingleValue().getUnsigned(); - return info.interface()->tableLoad(info.name, address); + return allTables[curr->table]->get(address); } Flow visitTableSet(TableSet* curr) { VISIT(index, curr->index) VISIT(value, curr->value) - auto info = getTableInstanceInfo(curr->table); auto address = index.getSingleValue().getUnsigned(); - info.interface()->tableStore(info.name, address, value.getSingleValue()); + + allTables[curr->table]->set(address, value.getSingleValue()); + return Flow(); } Flow visitTableSize(TableSize* curr) { - auto info = getTableInstanceInfo(curr->table); - auto* table = info.instance->wasm.getTable(info.name); - Index tableSize = info.interface()->tableSize(curr->table); - return Literal::makeFromInt64(tableSize, table->addressType); + auto* table = allTables[curr->table]; + return Literal::makeFromInt64(static_cast(table->size()), + table->tableMeta()->addressType); } Flow visitTableGrow(TableGrow* curr) { VISIT(valueFlow, curr->value) VISIT(deltaFlow, curr->delta) - auto info = getTableInstanceInfo(curr->table); - - uint64_t tableSize = info.interface()->tableSize(info.name); - auto* table = info.instance->wasm.getTable(info.name); - Flow ret = Literal::makeFromInt64(tableSize, table->addressType); - Flow fail = Literal::makeFromInt64(-1, table->addressType); - uint64_t delta = deltaFlow.getSingleValue().getUnsigned(); - uint64_t newSize; - if (std::ckd_add(&newSize, tableSize, delta)) { - return fail; - } - if (newSize > table->max || newSize > WebLimitations::MaxTableSize) { - return fail; + auto* table = allTables[curr->table]; + if (auto newSize = table->grow(deltaFlow.getSingleValue().getUnsigned(), + valueFlow.getSingleValue())) { + return Literal::makeFromInt64(*newSize, table->tableMeta()->addressType); } - if (!info.interface()->growTable( - info.name, valueFlow.getSingleValue(), tableSize, newSize)) { - // We failed to grow the table in practice, even though it was valid - // to try to do so. - return fail; - } - return ret; + + return Literal::makeFromInt64(-1, table->tableMeta()->addressType); } Flow visitTableFill(TableFill* curr) { VISIT(destFlow, curr->dest) VISIT(valueFlow, curr->value) VISIT(sizeFlow, curr->size) - auto info = getTableInstanceInfo(curr->table); auto dest = destFlow.getSingleValue().getUnsigned(); Literal value = valueFlow.getSingleValue(); auto size = sizeFlow.getSingleValue().getUnsigned(); - auto tableSize = info.interface()->tableSize(info.name); - if (dest + size > tableSize) { + auto* table = allTables[curr->table]; + if (dest + size > table->size()) { trap("out of bounds table access"); } for (uint64_t i = 0; i < size; i++) { - info.interface()->tableStore(info.name, dest + i, value); + table->set(dest + i, value); } return Flow(); } @@ -3888,12 +3881,10 @@ class ModuleRunnerBase : public ExpressionRunner { Address sourceVal(source.getSingleValue().getUnsigned()); Address sizeVal(size.getSingleValue().getUnsigned()); - auto destInfo = getTableInstanceInfo(curr->destTable); - auto sourceInfo = getTableInstanceInfo(curr->sourceTable); - auto destTableSize = destInfo.interface()->tableSize(destInfo.name); - auto sourceTableSize = sourceInfo.interface()->tableSize(sourceInfo.name); - if (sourceVal + sizeVal > sourceTableSize || - destVal + sizeVal > destTableSize || + auto* destTable = allTables[curr->destTable]; + auto* sourceTable = allTables[curr->sourceTable]; + if (sourceVal + sizeVal > sourceTable->size() || + destVal + sizeVal > destTable->size() || // FIXME: better/cheaper way to detect wrapping? sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal || destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) { @@ -3910,10 +3901,7 @@ class ModuleRunnerBase : public ExpressionRunner { step = -1; } for (int64_t i = start; i != end; i += step) { - destInfo.interface()->tableStore( - destInfo.name, - destVal + i, - sourceInfo.interface()->tableLoad(sourceInfo.name, sourceVal + i)); + destTable->set(destVal + i, sourceTable->get(sourceVal + i)); } return {}; } @@ -3936,9 +3924,9 @@ class ModuleRunnerBase : public ExpressionRunner { if (offsetVal + sizeVal > segment->data.size()) { trap("out of bounds segment access in table.init"); } - auto info = getTableInstanceInfo(curr->table); - auto tableSize = info.interface()->tableSize(info.name); - if (destVal + sizeVal > tableSize) { + + auto* table = allTables[curr->table]; + if (destVal + sizeVal > table->size()) { trap("out of bounds table access in table.init"); } for (size_t i = 0; i < sizeVal; ++i) { @@ -3947,8 +3935,9 @@ class ModuleRunnerBase : public ExpressionRunner { // and then read here as needed. For example, if we had a // struct.new here then we should not allocate a new struct each // time we table.init that data. - auto value = self()->visit(segment->data[offsetVal + i]).getSingleValue(); - info.interface()->tableStore(info.name, destVal + i, value); + Literal value = + self()->visit(segment->data[offsetVal + i]).getSingleValue(); + table->set(destVal + i, value); } return {}; } diff --git a/test/lit/ctor-eval/table.init.wat b/test/lit/ctor-eval/table.init.wat index 7af2a09c6e1..f6d7b63dcec 100644 --- a/test/lit/ctor-eval/table.init.wat +++ b/test/lit/ctor-eval/table.init.wat @@ -11,7 +11,6 @@ ;; CHECK: (elem $init (i32.const 0) $nop) (elem $init (i32.const 0) $nop) - ;; CHECK: (elem $later func $trap) (elem $later $trap) (export "run" (func $run)) @@ -43,19 +42,11 @@ (nop) ) - ;; CHECK: (func $trap (type $none_=>_none) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) (func $trap (type $none_=>_none) (unreachable) ) ) ;; CHECK: (func $run_3 (type $none_=>_none) -;; CHECK-NEXT: (table.init $table $later -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: (i32.const 1) -;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_indirect $table (type $none_=>_none) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) diff --git a/test/lit/ctor-eval/table.wat b/test/lit/ctor-eval/table.wat index 0954faeea7d..ab74d38eead 100644 --- a/test/lit/ctor-eval/table.wat +++ b/test/lit/ctor-eval/table.wat @@ -32,8 +32,6 @@ ;; CHECK: (elem $0 (i32.const 0) $nop) - ;; CHECK: (elem declare func $trap) - ;; CHECK: (export "run" (func $run_3)) ;; CHECK: (func $nop (type $none_=>_none) @@ -43,18 +41,11 @@ (nop) ) - ;; CHECK: (func $trap (type $none_=>_none) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) (func $trap (type $none_=>_none) (unreachable) ) ) ;; CHECK: (func $run_3 (type $none_=>_none) -;; CHECK-NEXT: (table.set $0 -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: (ref.func $trap) -;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_indirect $0 (type $none_=>_none) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: )