From ae1b333a7166e2b8b56adabafb4f43a6bed18bd2 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Tue, 23 Dec 2025 00:30:37 +0000 Subject: [PATCH 01/12] Add import resolver and use it for globals --- src/shell-interface.h | 12 ---- src/tools/wasm-ctor-eval.cpp | 72 +++++++++++------------- src/tools/wasm-shell.cpp | 2 +- src/wasm-interpreter.h | 104 ++++++++++++++++++++++------------- src/wasm/import-resolver.h | 47 ++++++++++++++++ src/wasm/qualified-name.h | 20 +++++++ 6 files changed, 168 insertions(+), 89 deletions(-) create mode 100644 src/wasm/import-resolver.h create mode 100644 src/wasm/qualified-name.h diff --git a/src/shell-interface.h b/src/shell-interface.h index 03b4c819e73..6fa7d8af1a8 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -129,18 +129,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { wasm, [&](Table* table) { tables[table->name].resize(table->initial); }); } - void importGlobals(std::map& globals, Module& wasm) override { - ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) { - auto inst = getImportInstance(import); - auto* exportedGlobal = inst->wasm.getExportOrNull(import->base); - if (!exportedGlobal || exportedGlobal->kind != ExternalKind::Global) { - Fatal() << "importGlobals: unknown import: " << import->module.str - << "." << import->name.str; - } - globals[import->name] = inst->globals[*exportedGlobal->getInternalName()]; - }); - } - Literal getImportedFunction(Function* import) override { // TODO: We should perhaps restrict the types with which the well-known // functions can be imported. diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 455c247ccd7..765aeaa278d 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -67,13 +67,40 @@ bool isNullableAndMutable(Expression* ref, Index fieldIndex) { // the output. #define RECOMMENDATION "\n recommendation: " +class EvallingModuleRunner; + +class EvallingImportResolver : public ImportResolver { +public: + EvallingImportResolver( + std::map> linkedInstances, + ModuleRunnerBase::ExternalInterface* + externalInterface) + : externalInterface(externalInterface) {} + + std::optional getGlobal(QualifiedName name, + Type type) const override { + externalInterface->trap((std::stringstream() + << "EvallingImportResolver: unexpected getGlobal " + << name) + .str()); + return std::nullopt; + } + +private: + ModuleRunnerBase::ExternalInterface* externalInterface; +}; + class EvallingModuleRunner : public ModuleRunnerBase { public: EvallingModuleRunner( Module& wasm, ExternalInterface* externalInterface, std::map> linkedInstances_ = {}) - : ModuleRunnerBase(wasm, externalInterface, linkedInstances_) {} + : ModuleRunnerBase(wasm, + externalInterface, + std::make_shared( + linkedInstances_, externalInterface), + linkedInstances_) {} Flow visitGlobalGet(GlobalGet* curr) { // Error on reads of imported globals. @@ -147,19 +174,6 @@ std::unique_ptr buildEnvModule(Module& wasm) { } }); - ModuleUtils::iterImportedGlobals(wasm, [&](Global* global) { - if (global->module == env->name) { - auto* copied = ModuleUtils::copyGlobal(global, *env); - copied->module = Name(); - copied->base = Name(); - - Builder builder(*env); - copied->init = builder.makeConst(Literal::makeZero(global->type)); - env->addExport( - builder.makeExport(global->base, copied->name, ExternalKind::Global)); - } - }); - // create an exported memory with the same initial and max size ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) { if (memory->module == env->name) { @@ -231,26 +245,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { } } - void importGlobals(GlobalValueSet& globals, Module& wasm_) override { - ModuleUtils::iterImportedGlobals(wasm_, [&](Global* global) { - auto it = linkedInstances.find(global->module); - if (it != linkedInstances.end()) { - auto* inst = it->second.get(); - auto* globalExport = inst->wasm.getExportOrNull(global->base); - if (!globalExport || globalExport->kind != ExternalKind::Global) { - throw FailToEvalException(std::string("importGlobals: ") + - global->module.toString() + "." + - global->base.toString()); - } - globals[global->name] = inst->globals[*globalExport->getInternalName()]; - } else { - throw FailToEvalException(std::string("importGlobals: ") + - global->module.toString() + "." + - global->base.toString()); - } - }); - } - Literal getImportedFunction(Function* import) override { auto f = [import, this](const Literals& arguments) -> Flow { Name WASI("wasi_snapshot_preview1"); @@ -558,8 +552,8 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { void applyGlobalsToModule() { if (!wasm->features.hasGC()) { // Without GC, we can simply serialize the globals in place as they are. - for (const auto& [name, values] : instance->globals) { - wasm->getGlobal(name)->init = getSerialization(values); + for (const auto& [name, values] : instance->allGlobals) { + wasm->getGlobal(name)->init = getSerialization(*values); } return; } @@ -590,9 +584,9 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { // for it. (If there is no value, then this is a new global we've added // during execution, for whom we've already set up a proper serialized // value when we created it.) - auto iter = instance->globals.find(oldGlobal->name); - if (iter != instance->globals.end()) { - oldGlobal->init = getSerialization(iter->second, name); + auto iter = instance->allGlobals.find(oldGlobal->name); + if (iter != instance->allGlobals.end()) { + oldGlobal->init = getSerialization(*iter->second, name); } // Add the global back to the module. diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 154c045f249..2bdc6059861 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -278,7 +278,7 @@ struct Shell { } auto& instance = it->second; try { - return instance->getExportedGlobal(get->name); + return instance->getExportedGlobalOrTrap(get->name); } catch (TrapException&) { return TrapResult{}; } catch (...) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d46dde4d102..e44d51f0344 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -29,6 +29,7 @@ #define wasm_wasm_interpreter_h #include +#include #include #include #include @@ -46,6 +47,7 @@ #include "wasm-limits.h" #include "wasm-traversal.h" #include "wasm.h" +#include "wasm/import-resolver.h" #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) #include @@ -2940,8 +2942,6 @@ class ConstantExpressionRunner : public ExpressionRunner { } }; -using GlobalValueSet = std::map; - // // A runner for a module. Each runner contains the information to execute the // module, such as the state of globals, and so forth, so it basically @@ -2969,7 +2969,6 @@ class ModuleRunnerBase : public ExpressionRunner { std::map> linkedInstances = {}) {} virtual ~ExternalInterface() = default; virtual void init(Module& wasm, SubType& instance) {} - virtual void importGlobals(GlobalValueSet& globals, Module& wasm) = 0; virtual Literal getImportedFunction(Function* import) = 0; virtual bool growMemory(Name name, Address oldSize, Address newSize) = 0; virtual bool growTable(Name name, @@ -3174,18 +3173,22 @@ class ModuleRunnerBase : public ExpressionRunner { // TODO: this duplicates module in ExpressionRunner, and can be removed Module& wasm; - // Values of globals - GlobalValueSet globals; - // Multivalue ABI support (see push/pop). std::vector multiValues; + // keyed by internal name + std::map definedGlobals; + std::map allGlobals; + ModuleRunnerBase( Module& wasm, ExternalInterface* externalInterface, + std::shared_ptr importResolver, std::map> linkedInstances_ = {}) : ExpressionRunner(&wasm), wasm(wasm), - externalInterface(externalInterface), linkedInstances(linkedInstances_) { + externalInterface(externalInterface), + linkedInstances(std::move(linkedInstances_)), + importResolver(std::move(importResolver)) { // Set up a single shared CurrContinuations for all these linked instances, // reusing one if it exists. std::shared_ptr shared; @@ -3208,16 +3211,11 @@ class ModuleRunnerBase : public ExpressionRunner { // (This is separate from the constructor so that it does not occur // synchronously, which makes some code patterns harder to write.) void instantiate() { - // import globals from the outside - externalInterface->importGlobals(globals, wasm); - // generate internal (non-imported) globals - ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) { - globals[global->name] = self()->visit(global->init).values; - }); - // initialize the rest of the external interface externalInterface->init(wasm, *self()); + initializeGlobals(); + initializeTableContents(); initializeMemoryContents(); @@ -3254,20 +3252,30 @@ class ModuleRunnerBase : public ExpressionRunner { func->type); } - // get an exported global - Literals getExportedGlobal(Name name) { + std::optional getExportedGlobal(Name name) { Export* export_ = wasm.getExportOrNull(name); if (!export_ || export_->kind != ExternalKind::Global) { - externalInterface->trap("getExport external not found"); + return std::nullopt; } Name internalName = *export_->getInternalName(); - auto iter = globals.find(internalName); - if (iter == globals.end()) { - externalInterface->trap("getExport internal not found"); + auto iter = allGlobals.find(internalName); + if (iter == allGlobals.end()) { + return std::nullopt; } return iter->second; } + Literals& getExportedGlobalOrTrap(Name name) { + auto global = getExportedGlobal(name); + if (!global.has_value()) { + externalInterface->trap((std::stringstream() + << "getExportedGlobal: export " << name + << " not found.") + .str()); + } + return **global; + } + Tag* getExportedTag(Name name) { Export* export_ = wasm.getExportOrNull(name); if (!export_ || export_->kind != ExternalKind::Tag) { @@ -3321,6 +3329,34 @@ class ModuleRunnerBase : public ExpressionRunner { return TableInstanceInfo{self(), name}; } + void initializeGlobals() { + for (auto& global : wasm.globals) { + if (global->imported()) { + QualifiedName name{global->module, global->base}; + auto importedGlobal = importResolver->getGlobal(name, global->type); + if (!importedGlobal) { + externalInterface->trap( + (std::stringstream() << "Imported global " << name << " not found.") + .str()); + } + allGlobals[global->name] = *importedGlobal; + } else { + Literals init = self()->visit(global->init).values; + auto [it, inserted] = definedGlobals.emplace(global->name, init); + + // This was likely checked during parsing or validation + if (!inserted) { + externalInterface->trap( + (std::stringstream() + << "Global: " << std::quoted(global->name.toString()) + << " was defined twice.") + .str()); + } + allGlobals[global->name] = &it->second; + } + } + } + void initializeTableContents() { for (auto& table : wasm.tables) { if (table->type.isNullable()) { @@ -3511,20 +3547,8 @@ class ModuleRunnerBase : public ExpressionRunner { SmallVector, 4> exceptionStack; protected: - // Returns a reference to the current value of a potentially imported global. - Literals& getGlobal(Name name) { - auto* inst = self(); - auto* global = inst->wasm.getGlobal(name); - while (global->imported()) { - inst = inst->linkedInstances.at(global->module).get(); - Export* globalExport = inst->wasm.getExport(global->base); - global = inst->wasm.getGlobal(*globalExport->getInternalName()); - } - - return inst->globals[global->name]; - } - - // As above, but for a function. + // Returns a reference to the current value of a potentially imported + // function. Literal getFunction(Name name) { auto* inst = self(); auto* func = inst->wasm.getFunction(name); @@ -3846,13 +3870,13 @@ class ModuleRunnerBase : public ExpressionRunner { Flow visitGlobalGet(GlobalGet* curr) { auto name = curr->name; - return getGlobal(name); + return *allGlobals.at(name); } Flow visitGlobalSet(GlobalSet* curr) { auto name = curr->name; VISIT(flow, curr->value) - getGlobal(name) = flow.values; + *allGlobals.at(name) = flow.values; return Flow(); } @@ -5055,6 +5079,7 @@ class ModuleRunnerBase : public ExpressionRunner { ExternalInterface* externalInterface; std::map> linkedInstances; + std::shared_ptr importResolver; }; class ModuleRunner : public ModuleRunnerBase { @@ -5063,7 +5088,12 @@ class ModuleRunner : public ModuleRunnerBase { Module& wasm, ExternalInterface* externalInterface, std::map> linkedInstances = {}) - : ModuleRunnerBase(wasm, externalInterface, linkedInstances) {} + : ModuleRunnerBase( + wasm, + externalInterface, + std::make_shared>( + linkedInstances), + linkedInstances) {} Literal makeFuncData(Name name, Type type) { // As the super's |makeFuncData|, but here we also provide a way to diff --git a/src/wasm/import-resolver.h b/src/wasm/import-resolver.h new file mode 100644 index 00000000000..1c142b9a408 --- /dev/null +++ b/src/wasm/import-resolver.h @@ -0,0 +1,47 @@ +#ifndef wasm_import_resolver_h +#define wasm_import_resolver_h + +#include +#include +#include +#include + +#include "support/name.h" +#include "wasm.h" +#include "wasm/qualified-name.h" + +namespace wasm { + +class ImportResolver { +public: + virtual ~ImportResolver() = default; + + virtual std::optional getGlobal(QualifiedName name, + Type type) const = 0; +}; + +template +class LinkedInstancesImportResolver : public ImportResolver { +public: + LinkedInstancesImportResolver( + std::map> linkedInstances) + : linkedInstances(std::move(linkedInstances)) {} + + std::optional getGlobal(QualifiedName name, + Type type) const override { + auto it = linkedInstances.find(name.module); + if (it == linkedInstances.end()) { + return std::nullopt; + } + + ModuleRunnerType* instance = it->second.get(); + return instance->getExportedGlobal(name.name); + } + +private: + const std::map> linkedInstances; +}; + +} // namespace wasm + +#endif // wasm_import_resolver_h diff --git a/src/wasm/qualified-name.h b/src/wasm/qualified-name.h new file mode 100644 index 00000000000..452b1904bd8 --- /dev/null +++ b/src/wasm/qualified-name.h @@ -0,0 +1,20 @@ +#ifndef wasm_qualified_name_h +#define wasm_qualified_name_h + +#include "support/name.h" +#include + +namespace wasm { + +struct QualifiedName { + Name module; + Name name; + + friend std::ostream& operator<<(std::ostream& o, const QualifiedName& qname) { + return o << qname.module << "." << qname.name; + } +}; + +} // namespace wasm + +#endif // wasm_qualified_name_h From ab068d2d718be80e1b68eb62ed1925d2332d7d6d Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 2 Jan 2026 19:47:59 +0000 Subject: [PATCH 02/12] PR updates --- src/tools/wasm-ctor-eval.cpp | 5 +---- src/wasm-interpreter.h | 18 ++++++++---------- src/wasm/import-resolver.h | 16 ++++++++++++++++ src/wasm/qualified-name.h | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 765aeaa278d..27b2eb23ff6 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -79,10 +79,7 @@ class EvallingImportResolver : public ImportResolver { std::optional getGlobal(QualifiedName name, Type type) const override { - externalInterface->trap((std::stringstream() - << "EvallingImportResolver: unexpected getGlobal " - << name) - .str()); + externalInterface->trap("Accessed imported global"); return std::nullopt; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index e44d51f0344..57037d8cf65 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3176,8 +3176,8 @@ class ModuleRunnerBase : public ExpressionRunner { // Multivalue ABI support (see push/pop). std::vector multiValues; - // keyed by internal name - std::map definedGlobals; + // Keyed by internal name. All globals in the module, including imports. + // `definedGlobals` contains non-imported globals. std::map allGlobals; ModuleRunnerBase( @@ -3298,6 +3298,10 @@ class ModuleRunnerBase : public ExpressionRunner { } private: + // Keyed by internal name. Globals that were defined in this module and not + // from an import. `allGlobals` contains these values + imported globals. + std::map definedGlobals; + // Keep a record of call depth, to guard against excessive recursion. size_t callDepth = 0; @@ -3343,15 +3347,9 @@ class ModuleRunnerBase : public ExpressionRunner { } else { Literals init = self()->visit(global->init).values; auto [it, inserted] = definedGlobals.emplace(global->name, init); + // parsing/validation checked this already. + assert(inserted && "Unexpected repeated global"); - // This was likely checked during parsing or validation - if (!inserted) { - externalInterface->trap( - (std::stringstream() - << "Global: " << std::quoted(global->name.toString()) - << " was defined twice.") - .str()); - } allGlobals[global->name] = &it->second; } } diff --git a/src/wasm/import-resolver.h b/src/wasm/import-resolver.h index 1c142b9a408..19cbebaf378 100644 --- a/src/wasm/import-resolver.h +++ b/src/wasm/import-resolver.h @@ -1,3 +1,19 @@ +/* + * Copyright 2025 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. + */ + #ifndef wasm_import_resolver_h #define wasm_import_resolver_h diff --git a/src/wasm/qualified-name.h b/src/wasm/qualified-name.h index 452b1904bd8..8a02cb74e49 100644 --- a/src/wasm/qualified-name.h +++ b/src/wasm/qualified-name.h @@ -1,3 +1,19 @@ +/* + * Copyright 2025 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. + */ + #ifndef wasm_qualified_name_h #define wasm_qualified_name_h From 3385e24b2c7641ec54685b286e5a13130f91a5c3 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 2 Jan 2026 21:58:35 +0000 Subject: [PATCH 03/12] PR comments --- src/support/nullability.h | 39 ++++++++++++++++++++++++++++++++++++ src/tools/wasm-ctor-eval.cpp | 7 ++++--- src/wasm-interpreter.h | 14 ++++++------- src/wasm/import-resolver.h | 14 ++++++++----- 4 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 src/support/nullability.h diff --git a/src/support/nullability.h b/src/support/nullability.h new file mode 100644 index 00000000000..b9e270bde90 --- /dev/null +++ b/src/support/nullability.h @@ -0,0 +1,39 @@ +/* + * Copyright 2025 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. + */ + +// Trivial wrappers to annotate the nullability of pointers. + +#ifndef _wasm_support_nullability +#define _wasm_support_nullability + +#include +#include + +namespace wasm::nullability { + +template struct is_pointer : std::false_type {}; + +template +struct is_pointer::element_type>> + : std::true_type {}; + +template using Nullable = std::enable_if_t::value, T>; + +template using NonNull = std::enable_if_t::value, T>; + +} // namespace wasm::nullability + +#endif // _wasm_support_nullability diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 27b2eb23ff6..02c64806dfa 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -36,6 +36,7 @@ #include "support/colors.h" #include "support/file.h" #include "support/insert_ordered.h" +#include "support/nullability.h" #include "support/small_set.h" #include "support/string.h" #include "support/topological_sort.h" @@ -77,10 +78,10 @@ class EvallingImportResolver : public ImportResolver { externalInterface) : externalInterface(externalInterface) {} - std::optional getGlobal(QualifiedName name, - Type type) const override { + nullability::Nullable getGlobal(QualifiedName name, + Type type) const override { externalInterface->trap("Accessed imported global"); - return std::nullopt; + return nullptr; } private: diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index fdd8ef34c14..cf9187e538a 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3258,28 +3258,28 @@ class ModuleRunnerBase : public ExpressionRunner { func->type); } - std::optional getExportedGlobal(Name name) { + nullability::Nullable getExportedGlobal(Name name) { Export* export_ = wasm.getExportOrNull(name); if (!export_ || export_->kind != ExternalKind::Global) { - return std::nullopt; + return nullptr; } Name internalName = *export_->getInternalName(); auto iter = allGlobals.find(internalName); if (iter == allGlobals.end()) { - return std::nullopt; + return nullptr; } return iter->second; } Literals& getExportedGlobalOrTrap(Name name) { - auto global = getExportedGlobal(name); - if (!global.has_value()) { + auto* global = getExportedGlobal(name); + if (!global) { externalInterface->trap((std::stringstream() << "getExportedGlobal: export " << name << " not found.") .str()); } - return **global; + return *global; } Tag* getExportedTag(Name name) { @@ -3424,7 +3424,7 @@ class ModuleRunnerBase : public ExpressionRunner { (std::stringstream() << "Imported global " << name << " not found.") .str()); } - allGlobals[global->name] = *importedGlobal; + allGlobals[global->name] = importedGlobal; } else { Literals init = self()->visit(global->init).values; auto [it, inserted] = definedGlobals.emplace(global->name, init); diff --git a/src/wasm/import-resolver.h b/src/wasm/import-resolver.h index 19cbebaf378..90dca60bce4 100644 --- a/src/wasm/import-resolver.h +++ b/src/wasm/import-resolver.h @@ -23,6 +23,7 @@ #include #include "support/name.h" +#include "support/nullability.h" #include "wasm.h" #include "wasm/qualified-name.h" @@ -32,10 +33,13 @@ class ImportResolver { public: virtual ~ImportResolver() = default; - virtual std::optional getGlobal(QualifiedName name, - Type type) const = 0; + // Returns null if the `name` wasn't found. The returned Literals* lives as + // long as the ImportResolver instance. + virtual nullability::Nullable getGlobal(QualifiedName name, + Type type) const = 0; }; +// Looks up imports from the given `linkedInstances`. template class LinkedInstancesImportResolver : public ImportResolver { public: @@ -43,11 +47,11 @@ class LinkedInstancesImportResolver : public ImportResolver { std::map> linkedInstances) : linkedInstances(std::move(linkedInstances)) {} - std::optional getGlobal(QualifiedName name, - Type type) const override { + nullability::Nullable getGlobal(QualifiedName name, + Type type) const override { auto it = linkedInstances.find(name.module); if (it == linkedInstances.end()) { - return std::nullopt; + return nullptr; } ModuleRunnerType* instance = it->second.get(); From e8f5b5ffac3c163ce16f8b5eee5aacfeef4c41dc Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 2 Jan 2026 22:52:27 +0000 Subject: [PATCH 04/12] PR updates --- src/support/nullability.h | 2 +- src/wasm-interpreter.h | 26 ++++++++++++++++++-------- src/wasm/import-resolver.h | 2 +- src/wasm/qualified-name.h | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/support/nullability.h b/src/support/nullability.h index b9e270bde90..ed31481ab5c 100644 --- a/src/support/nullability.h +++ b/src/support/nullability.h @@ -1,5 +1,5 @@ /* - * Copyright 2025 WebAssembly Community Group participants + * Copyright 2026 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. diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index cf9187e538a..d40876e3a46 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3304,9 +3304,10 @@ class ModuleRunnerBase : public ExpressionRunner { } private: - // Keyed by internal name. Globals that were defined in this module and not - // from an import. `allGlobals` contains these values + imported globals. - std::map definedGlobals; + // Globals that were defined in this module and not from an import. + // `allGlobals` contains these values + imported globals, keyed by their + // internal name. + std::vector definedGlobals; // Keep a record of call depth, to guard against excessive recursion. size_t callDepth = 0; @@ -3415,6 +3416,11 @@ class ModuleRunnerBase : public ExpressionRunner { } void initializeGlobals() { + int definedGlobalCount = 0; + ModuleUtils::iterDefinedGlobals( + wasm, [&definedGlobalCount](auto&& _) { ++definedGlobalCount; }); + definedGlobals.reserve(definedGlobalCount); + for (auto& global : wasm.globals) { if (global->imported()) { QualifiedName name{global->module, global->base}; @@ -3424,14 +3430,18 @@ class ModuleRunnerBase : public ExpressionRunner { (std::stringstream() << "Imported global " << name << " not found.") .str()); } - allGlobals[global->name] = importedGlobal; + auto [_, inserted] = + allGlobals.try_emplace(global->name, importedGlobal); + // parsing/validation checked this already. + assert(inserted && "Unexpected repeated global name"); } else { Literals init = self()->visit(global->init).values; - auto [it, inserted] = definedGlobals.emplace(global->name, init); - // parsing/validation checked this already. - assert(inserted && "Unexpected repeated global"); + auto& definedGlobal = definedGlobals.emplace_back(init); - allGlobals[global->name] = &it->second; + auto [_, inserted] = + allGlobals.try_emplace(global->name, &definedGlobal); + // parsing/validation checked this already. + assert(inserted && "Unexpected repeated global name"); } } } diff --git a/src/wasm/import-resolver.h b/src/wasm/import-resolver.h index 90dca60bce4..ca10f858a43 100644 --- a/src/wasm/import-resolver.h +++ b/src/wasm/import-resolver.h @@ -1,5 +1,5 @@ /* - * Copyright 2025 WebAssembly Community Group participants + * Copyright 2026 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. diff --git a/src/wasm/qualified-name.h b/src/wasm/qualified-name.h index 8a02cb74e49..87b72be84ab 100644 --- a/src/wasm/qualified-name.h +++ b/src/wasm/qualified-name.h @@ -1,5 +1,5 @@ /* - * Copyright 2025 WebAssembly Community Group participants + * Copyright 2026 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. From f63f37bb80a29ff80d0feba9e03588036f42edac Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Fri, 2 Jan 2026 23:00:19 +0000 Subject: [PATCH 05/12] Fix false positive lint about unused variable --- src/wasm-interpreter.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index d40876e3a46..cf28fb55b47 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3432,6 +3432,7 @@ class ModuleRunnerBase : public ExpressionRunner { } auto [_, inserted] = allGlobals.try_emplace(global->name, importedGlobal); + (void)_; // parsing/validation checked this already. assert(inserted && "Unexpected repeated global name"); } else { @@ -3440,6 +3441,7 @@ class ModuleRunnerBase : public ExpressionRunner { auto [_, inserted] = allGlobals.try_emplace(global->name, &definedGlobal); + (void)_; // parsing/validation checked this already. assert(inserted && "Unexpected repeated global name"); } From 33c3de11a92d0b0f27fbd9a910c4ba70b3622a95 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Mon, 5 Jan 2026 22:52:41 +0000 Subject: [PATCH 06/12] PR updates --- src/ir/import-utils.h | 32 +++++++++++++++++ src/support/nullability.h | 39 --------------------- src/tools/wasm-ctor-eval.cpp | 4 +-- src/wasm-interpreter.h | 9 ++--- src/wasm/import-resolver.h | 67 ------------------------------------ 5 files changed, 38 insertions(+), 113 deletions(-) delete mode 100644 src/support/nullability.h delete mode 100644 src/wasm/import-resolver.h diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index d0b5a8042a6..93c7c838ef7 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -18,6 +18,7 @@ #define wasm_ir_import_h #include "literal.h" +#include "src/wasm/qualified-name.h" #include "wasm.h" namespace wasm { @@ -123,6 +124,37 @@ struct ImportInfo { Index getNumDefinedTags() { return wasm.tags.size() - getNumImportedTags(); } }; +class ImportResolver { +public: + virtual ~ImportResolver() = default; + + // Returns null if the `name` wasn't found. The returned Literals* lives as + // long as the ImportResolver instance. + virtual Literals* getGlobalOrNull(QualifiedName name, Type type) const = 0; +}; + +// Looks up imports from the given `linkedInstances`. +template +class LinkedInstancesImportResolver : public ImportResolver { +public: + LinkedInstancesImportResolver( + std::map> linkedInstances) + : linkedInstances(std::move(linkedInstances)) {} + + Literals* getGlobalOrNull(QualifiedName name, Type type) const override { + auto it = linkedInstances.find(name.module); + if (it == linkedInstances.end()) { + return nullptr; + } + + ModuleRunnerType* instance = it->second.get(); + return instance->getExportedGlobalOrNull(name.name); + } + +private: + const std::map> linkedInstances; +}; + } // namespace wasm #endif // wasm_ir_import_h diff --git a/src/support/nullability.h b/src/support/nullability.h deleted file mode 100644 index ed31481ab5c..00000000000 --- a/src/support/nullability.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2026 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. - */ - -// Trivial wrappers to annotate the nullability of pointers. - -#ifndef _wasm_support_nullability -#define _wasm_support_nullability - -#include -#include - -namespace wasm::nullability { - -template struct is_pointer : std::false_type {}; - -template -struct is_pointer::element_type>> - : std::true_type {}; - -template using Nullable = std::enable_if_t::value, T>; - -template using NonNull = std::enable_if_t::value, T>; - -} // namespace wasm::nullability - -#endif // _wasm_support_nullability diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 02c64806dfa..0ccaa5a9c03 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -36,7 +36,6 @@ #include "support/colors.h" #include "support/file.h" #include "support/insert_ordered.h" -#include "support/nullability.h" #include "support/small_set.h" #include "support/string.h" #include "support/topological_sort.h" @@ -78,8 +77,7 @@ class EvallingImportResolver : public ImportResolver { externalInterface) : externalInterface(externalInterface) {} - nullability::Nullable getGlobal(QualifiedName name, - Type type) const override { + Literals* getGlobalOrNull(QualifiedName name, Type type) const override { externalInterface->trap("Accessed imported global"); return nullptr; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index cf28fb55b47..a6cbf18948c 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -35,6 +35,7 @@ #include #include "fp16.h" +#include "ir/import-utils.h" #include "ir/intrinsics.h" #include "ir/iteration.h" #include "ir/memory-utils.h" @@ -49,7 +50,6 @@ #include "wasm-limits.h" #include "wasm-traversal.h" #include "wasm.h" -#include "wasm/import-resolver.h" #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) #include @@ -3258,7 +3258,7 @@ class ModuleRunnerBase : public ExpressionRunner { func->type); } - nullability::Nullable getExportedGlobal(Name name) { + Literals* getExportedGlobalOrNull(Name name) { Export* export_ = wasm.getExportOrNull(name); if (!export_ || export_->kind != ExternalKind::Global) { return nullptr; @@ -3272,7 +3272,7 @@ class ModuleRunnerBase : public ExpressionRunner { } Literals& getExportedGlobalOrTrap(Name name) { - auto* global = getExportedGlobal(name); + auto* global = getExportedGlobalOrNull(name); if (!global) { externalInterface->trap((std::stringstream() << "getExportedGlobal: export " << name @@ -3424,7 +3424,8 @@ class ModuleRunnerBase : public ExpressionRunner { for (auto& global : wasm.globals) { if (global->imported()) { QualifiedName name{global->module, global->base}; - auto importedGlobal = importResolver->getGlobal(name, global->type); + auto importedGlobal = + importResolver->getGlobalOrNull(name, global->type); if (!importedGlobal) { externalInterface->trap( (std::stringstream() << "Imported global " << name << " not found.") diff --git a/src/wasm/import-resolver.h b/src/wasm/import-resolver.h deleted file mode 100644 index ca10f858a43..00000000000 --- a/src/wasm/import-resolver.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2026 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. - */ - -#ifndef wasm_import_resolver_h -#define wasm_import_resolver_h - -#include -#include -#include -#include - -#include "support/name.h" -#include "support/nullability.h" -#include "wasm.h" -#include "wasm/qualified-name.h" - -namespace wasm { - -class ImportResolver { -public: - virtual ~ImportResolver() = default; - - // Returns null if the `name` wasn't found. The returned Literals* lives as - // long as the ImportResolver instance. - virtual nullability::Nullable getGlobal(QualifiedName name, - Type type) const = 0; -}; - -// Looks up imports from the given `linkedInstances`. -template -class LinkedInstancesImportResolver : public ImportResolver { -public: - LinkedInstancesImportResolver( - std::map> linkedInstances) - : linkedInstances(std::move(linkedInstances)) {} - - nullability::Nullable getGlobal(QualifiedName name, - Type type) const override { - auto it = linkedInstances.find(name.module); - if (it == linkedInstances.end()) { - return nullptr; - } - - ModuleRunnerType* instance = it->second.get(); - return instance->getExportedGlobal(name.name); - } - -private: - const std::map> linkedInstances; -}; - -} // namespace wasm - -#endif // wasm_import_resolver_h From d22a6f64e381cab56ee02560128da919642a95ab Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Mon, 5 Jan 2026 23:17:54 +0000 Subject: [PATCH 07/12] Fix include name --- src/ir/import-utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index 93c7c838ef7..3b2994063f1 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -18,8 +18,8 @@ #define wasm_ir_import_h #include "literal.h" -#include "src/wasm/qualified-name.h" #include "wasm.h" +#include "wasm/qualified-name.h" namespace wasm { From ee2da1e0692b1712c403e3c2d00faff330b3b4e1 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Tue, 6 Jan 2026 18:51:51 +0000 Subject: [PATCH 08/12] Rename QualifiedName to ImportName --- src/ir/import-utils.h | 6 +++--- src/tools/wasm-ctor-eval.cpp | 2 +- src/wasm-interpreter.h | 11 ++++++----- src/wasm.h | 2 ++ src/wasm/{qualified-name.h => import-name.h} | 10 +++++----- 5 files changed, 17 insertions(+), 14 deletions(-) rename src/wasm/{qualified-name.h => import-name.h} (80%) diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index 3b2994063f1..f8a55b51d45 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -19,7 +19,7 @@ #include "literal.h" #include "wasm.h" -#include "wasm/qualified-name.h" +#include "wasm/import-name.h" namespace wasm { @@ -130,7 +130,7 @@ class ImportResolver { // Returns null if the `name` wasn't found. The returned Literals* lives as // long as the ImportResolver instance. - virtual Literals* getGlobalOrNull(QualifiedName name, Type type) const = 0; + virtual Literals* getGlobalOrNull(ImportName name, Type type) const = 0; }; // Looks up imports from the given `linkedInstances`. @@ -141,7 +141,7 @@ class LinkedInstancesImportResolver : public ImportResolver { std::map> linkedInstances) : linkedInstances(std::move(linkedInstances)) {} - Literals* getGlobalOrNull(QualifiedName name, Type type) const override { + Literals* getGlobalOrNull(ImportName name, Type type) const override { auto it = linkedInstances.find(name.module); if (it == linkedInstances.end()) { return nullptr; diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 0ccaa5a9c03..4bba6a01aba 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -77,7 +77,7 @@ class EvallingImportResolver : public ImportResolver { externalInterface) : externalInterface(externalInterface) {} - Literals* getGlobalOrNull(QualifiedName name, Type type) const override { + Literals* getGlobalOrNull(ImportName name, Type type) const override { externalInterface->trap("Accessed imported global"); return nullptr; } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index a6cbf18948c..a73f2b8a843 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3423,13 +3423,14 @@ class ModuleRunnerBase : public ExpressionRunner { for (auto& global : wasm.globals) { if (global->imported()) { - QualifiedName name{global->module, global->base}; + auto importName = global->importName(); auto importedGlobal = - importResolver->getGlobalOrNull(name, global->type); + importResolver->getGlobalOrNull(importName, global->type); if (!importedGlobal) { - externalInterface->trap( - (std::stringstream() << "Imported global " << name << " not found.") - .str()); + externalInterface->trap((std::stringstream() + << "Imported global " << importName + << " not found.") + .str()); } auto [_, inserted] = allGlobals.try_emplace(global->name, importedGlobal); diff --git a/src/wasm.h b/src/wasm.h index c7677d01412..7a09e7be0a3 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -39,6 +39,7 @@ #include "support/name.h" #include "wasm-features.h" #include "wasm-type.h" +#include "wasm/import-name.h" namespace wasm { @@ -2172,6 +2173,7 @@ struct Importable : Named { Name module, base; bool imported() const { return module.is(); } + ImportName importName() const { return ImportName{module, base}; }; }; class Function; diff --git a/src/wasm/qualified-name.h b/src/wasm/import-name.h similarity index 80% rename from src/wasm/qualified-name.h rename to src/wasm/import-name.h index 87b72be84ab..280312f8e0e 100644 --- a/src/wasm/qualified-name.h +++ b/src/wasm/import-name.h @@ -14,23 +14,23 @@ * limitations under the License. */ -#ifndef wasm_qualified_name_h -#define wasm_qualified_name_h +#ifndef wasm_import_name_h +#define wasm_import_name_h #include "support/name.h" #include namespace wasm { -struct QualifiedName { +struct ImportName { Name module; Name name; - friend std::ostream& operator<<(std::ostream& o, const QualifiedName& qname) { + friend std::ostream& operator<<(std::ostream& o, const ImportName& qname) { return o << qname.module << "." << qname.name; } }; } // namespace wasm -#endif // wasm_qualified_name_h +#endif // wasm_import_name_h From fe28348bc38e50554d395e956f252da1a30362d3 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Tue, 6 Jan 2026 22:02:56 +0000 Subject: [PATCH 09/12] PR updates --- src/wasm-interpreter.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index a73f2b8a843..cc16cf6b496 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3434,16 +3434,16 @@ class ModuleRunnerBase : public ExpressionRunner { } auto [_, inserted] = allGlobals.try_emplace(global->name, importedGlobal); - (void)_; + (void)inserted; // for noassert builds // parsing/validation checked this already. assert(inserted && "Unexpected repeated global name"); } else { Literals init = self()->visit(global->init).values; - auto& definedGlobal = definedGlobals.emplace_back(init); + auto& definedGlobal = definedGlobals.emplace_back(std::move(init)); auto [_, inserted] = allGlobals.try_emplace(global->name, &definedGlobal); - (void)_; + (void)inserted; // for noassert builds // parsing/validation checked this already. assert(inserted && "Unexpected repeated global name"); } From ba23e3ec6099990b04889b4a5c7b33b5c427e318 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Tue, 6 Jan 2026 23:33:39 +0000 Subject: [PATCH 10/12] PR fixes --- src/ir/import-utils.h | 2 +- src/tools/wasm-ctor-eval.cpp | 15 +++------------ src/wasm-interpreter.h | 3 ++- src/wasm.h | 2 +- src/wasm/import-name.h | 36 ------------------------------------ 5 files changed, 7 insertions(+), 51 deletions(-) delete mode 100644 src/wasm/import-name.h diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index f8a55b51d45..c73113ad80a 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -17,9 +17,9 @@ #ifndef wasm_ir_import_h #define wasm_ir_import_h +#include "ir/import-name.h" #include "literal.h" #include "wasm.h" -#include "wasm/import-name.h" namespace wasm { diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 4bba6a01aba..1923c8a3da0 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -71,19 +71,11 @@ class EvallingModuleRunner; class EvallingImportResolver : public ImportResolver { public: - EvallingImportResolver( - std::map> linkedInstances, - ModuleRunnerBase::ExternalInterface* - externalInterface) - : externalInterface(externalInterface) {} + EvallingImportResolver() = default; Literals* getGlobalOrNull(ImportName name, Type type) const override { - externalInterface->trap("Accessed imported global"); - return nullptr; + throw FailToEvalException("Accessed imported global"); } - -private: - ModuleRunnerBase::ExternalInterface* externalInterface; }; class EvallingModuleRunner : public ModuleRunnerBase { @@ -94,8 +86,7 @@ class EvallingModuleRunner : public ModuleRunnerBase { std::map> linkedInstances_ = {}) : ModuleRunnerBase(wasm, externalInterface, - std::make_shared( - linkedInstances_, externalInterface), + std::make_shared(), linkedInstances_) {} Flow visitGlobalGet(GlobalGet* curr) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index cc16cf6b496..f44d02650af 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3179,7 +3179,8 @@ class ModuleRunnerBase : public ExpressionRunner { std::vector multiValues; // Keyed by internal name. All globals in the module, including imports. - // `definedGlobals` contains non-imported globals. + // `definedGlobals` contains non-imported globals. Points to `definedGlobals` + // of this instance and other instances. std::map allGlobals; ModuleRunnerBase( diff --git a/src/wasm.h b/src/wasm.h index 7a09e7be0a3..d332b7ebce1 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -33,13 +33,13 @@ #include #include +#include "ir/import-name.h" #include "literal.h" #include "mixed_arena.h" #include "support/index.h" #include "support/name.h" #include "wasm-features.h" #include "wasm-type.h" -#include "wasm/import-name.h" namespace wasm { diff --git a/src/wasm/import-name.h b/src/wasm/import-name.h deleted file mode 100644 index 280312f8e0e..00000000000 --- a/src/wasm/import-name.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2026 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. - */ - -#ifndef wasm_import_name_h -#define wasm_import_name_h - -#include "support/name.h" -#include - -namespace wasm { - -struct ImportName { - Name module; - Name name; - - friend std::ostream& operator<<(std::ostream& o, const ImportName& qname) { - return o << qname.module << "." << qname.name; - } -}; - -} // namespace wasm - -#endif // wasm_import_name_h From a6cbc53c129c2eb3bc7c94bde65e4f4b5e9d042b Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Tue, 6 Jan 2026 23:35:09 +0000 Subject: [PATCH 11/12] Forgot to add new file --- src/ir/import-name.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/ir/import-name.h diff --git a/src/ir/import-name.h b/src/ir/import-name.h new file mode 100644 index 00000000000..b743ddd61bb --- /dev/null +++ b/src/ir/import-name.h @@ -0,0 +1,37 @@ +/* + * Copyright 2026 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. + */ + +#ifndef wasm_ir_import_name_h +#define wasm_ir_import_name_h + +#include + +#include "support/name.h" + +namespace wasm { + +struct ImportName { + Name module; + Name name; + + friend std::ostream& operator<<(std::ostream& o, const ImportName& qname) { + return o << qname.module << "." << qname.name; + } +}; + +} // namespace wasm + +#endif // wasm_ir_import_name_h From a879862b0c16617736f6c406f048bacf03929763 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Wed, 7 Jan 2026 05:07:54 +0000 Subject: [PATCH 12/12] PR fixes --- src/ir/import-name.h | 6 +----- src/ir/import-utils.h | 4 ++-- src/passes/Print.cpp | 5 +++++ src/tools/wasm-ctor-eval.cpp | 2 +- src/wasm-interpreter.h | 6 +++--- src/wasm.h | 3 ++- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ir/import-name.h b/src/ir/import-name.h index b743ddd61bb..81fd0a3e768 100644 --- a/src/ir/import-name.h +++ b/src/ir/import-name.h @@ -23,13 +23,9 @@ namespace wasm { -struct ImportName { +struct ImportNames { Name module; Name name; - - friend std::ostream& operator<<(std::ostream& o, const ImportName& qname) { - return o << qname.module << "." << qname.name; - } }; } // namespace wasm diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index c73113ad80a..0c75704d609 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -130,7 +130,7 @@ class ImportResolver { // Returns null if the `name` wasn't found. The returned Literals* lives as // long as the ImportResolver instance. - virtual Literals* getGlobalOrNull(ImportName name, Type type) const = 0; + virtual Literals* getGlobalOrNull(ImportNames name, Type type) const = 0; }; // Looks up imports from the given `linkedInstances`. @@ -141,7 +141,7 @@ class LinkedInstancesImportResolver : public ImportResolver { std::map> linkedInstances) : linkedInstances(std::move(linkedInstances)) {} - Literals* getGlobalOrNull(ImportName name, Type type) const override { + Literals* getGlobalOrNull(ImportNames name, Type type) const override { auto it = linkedInstances.find(name.module); if (it == linkedInstances.end()) { return nullptr; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 96fd3c3051f..414e199cd78 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -3944,4 +3944,9 @@ std::ostream& operator<<(std::ostream& o, wasm::ModuleHeapType pair) { return o << "(unnamed)"; } +std::ostream& operator<<(std::ostream& o, + const wasm::ImportNames& importNames) { + return o << importNames.module << "." << importNames.name; +} + } // namespace std diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 1923c8a3da0..4839577225a 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -73,7 +73,7 @@ class EvallingImportResolver : public ImportResolver { public: EvallingImportResolver() = default; - Literals* getGlobalOrNull(ImportName name, Type type) const override { + Literals* getGlobalOrNull(ImportNames name, Type type) const override { throw FailToEvalException("Accessed imported global"); } }; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index f44d02650af..43f0e3c1d80 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -3424,12 +3424,12 @@ class ModuleRunnerBase : public ExpressionRunner { for (auto& global : wasm.globals) { if (global->imported()) { - auto importName = global->importName(); + auto importNames = global->importNames(); auto importedGlobal = - importResolver->getGlobalOrNull(importName, global->type); + importResolver->getGlobalOrNull(importNames, global->type); if (!importedGlobal) { externalInterface->trap((std::stringstream() - << "Imported global " << importName + << "Imported global " << importNames << " not found.") .str()); } diff --git a/src/wasm.h b/src/wasm.h index d332b7ebce1..085c14415f4 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -2173,7 +2173,7 @@ struct Importable : Named { Name module, base; bool imported() const { return module.is(); } - ImportName importName() const { return ImportName{module, base}; }; + ImportNames importNames() const { return ImportNames{module, base}; }; }; class Function; @@ -2666,6 +2666,7 @@ std::ostream& operator<<(std::ostream& o, wasm::ModuleExpression pair); std::ostream& operator<<(std::ostream& o, wasm::ShallowExpression expression); std::ostream& operator<<(std::ostream& o, wasm::ModuleType pair); std::ostream& operator<<(std::ostream& o, wasm::ModuleHeapType pair); +std::ostream& operator<<(std::ostream& o, const wasm::ImportNames& importNames); } // namespace std