From 95e05c042cde62a6383dd7da401963b6ec8b5354 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Thu, 29 Jan 2026 23:11:20 +0000 Subject: [PATCH 1/3] Start on tag imports --- src/ir/import-utils.h | 12 ++++ src/shell-interface.h | 4 -- src/tools/wasm-ctor-eval.cpp | 8 +++ src/wasm-interpreter.h | 112 ++++++++++++++++++++++++++--------- 4 files changed, 103 insertions(+), 33 deletions(-) diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h index 481d62af7f1..9d6b4cacbeb 100644 --- a/src/ir/import-utils.h +++ b/src/ir/import-utils.h @@ -137,6 +137,8 @@ class ImportResolver { // as long as the ImportResolver instance. virtual RuntimeTable* getTableOrNull(ImportNames name, const Table& type) const = 0; + + virtual Tag* getTagOrNull(ImportNames name, const Signature& type) const = 0; }; // Looks up imports from the given `linkedInstances`. @@ -168,6 +170,16 @@ class LinkedInstancesImportResolver : public ImportResolver { return instance->getExportedTableOrNull(name.name); } + Tag* getTagOrNull(ImportNames name, const Signature& type) const override { + auto it = linkedInstances.find(name.module); + if (it == linkedInstances.end()) { + return nullptr; + } + + ModuleRunnerType* instance = it->second.get(); + return instance->getExportedTagOrNull(name.name); + } + private: const std::map> linkedInstances; }; diff --git a/src/shell-interface.h b/src/shell-interface.h index d35bc9bb65e..615000a7fba 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -151,10 +151,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { return Literal::makeFunc(import->name, import->type); } - Tag* getImportedTag(Tag* tag) override { - WASM_UNREACHABLE("missing imported tag"); - } - int8_t load8s(Address addr, Name memoryName) override { auto it = memories.find(memoryName); assert(it != memories.end()); diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index fb57865999d..09a1552e9a3 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -84,6 +84,13 @@ class EvallingImportResolver : public ImportResolver { throw FailToEvalException{"Imported table access."}; } + Tag* getTagOrNull(ImportNames name, + const Signature& signature) const override { + Fatal() << "TODO"; + WASM_UNREACHABLE("TODO"); + return nullptr; + } + private: mutable Literals stubLiteral; }; @@ -393,6 +400,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { import->type); } + // TODO Tag* getImportedTag(Tag* tag) override { WASM_UNREACHABLE("missing imported tag"); } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index cf51b3d8f72..97be2af8063 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2979,7 +2979,9 @@ class ModuleRunnerBase : public ExpressionRunner { virtual void throwException(const WasmException& exn) = 0; // Get the Tag instance for a tag implemented in the host, that is, not // among the linked ModuleRunner instances, but imported from the host. - virtual Tag* getImportedTag(Tag* tag) = 0; + virtual Tag* getImportedTag(Tag* tag) { + WASM_UNREACHABLE("TODO remove this"); + } // the default impls for load and store switch on the sizes. you can either // customize load/store, or the sub-functions which they call @@ -3173,6 +3175,8 @@ class ModuleRunnerBase : public ExpressionRunner { // Like `allGlobals`. Keyed by internal name. All tables including imports. std::unordered_map allTables; + std::unordered_map allTags; + using CreateTableFunc = std::unique_ptr(Literal, Table); ModuleRunnerBase( @@ -3223,6 +3227,7 @@ class ModuleRunnerBase : public ExpressionRunner { initializeGlobals(); initializeTables(); + initializeTags(); initializeMemoryContents(); @@ -3296,16 +3301,28 @@ class ModuleRunnerBase : public ExpressionRunner { return *global; } - Tag* getExportedTag(Name name) { + Tag* getExportedTagOrNull(Name name) { Export* export_ = wasm.getExportOrNull(name); if (!export_ || export_->kind != ExternalKind::Tag) { - externalInterface->trap("exported tag not found"); + return nullptr; } - auto* tag = wasm.getTag(*export_->getInternalName()); - if (tag->imported()) { - tag = externalInterface->getImportedTag(tag); + Name internalName = *export_->getInternalName(); + auto it = allTags.find(internalName); + if (it == allTags.end()) { + return nullptr; + } + return it->second; + } + + Tag& getExportedTagOrTrap(Name name) { + auto* tag = getExportedTagOrNull(name); + if (!tag) { + externalInterface->trap((std::stringstream() << "getExportedTag: export " + << name << " not found.") + .str()); } - return tag; + + return *tag; } std::string printFunctionStack() { @@ -3323,6 +3340,7 @@ class ModuleRunnerBase : public ExpressionRunner { // internal name. std::vector definedGlobals; std::vector> definedTables; + std::vector definedTags; // Keep a record of call depth, to guard against excessive recursion. size_t callDepth = 0; @@ -3459,6 +3477,42 @@ class ModuleRunnerBase : public ExpressionRunner { } } + void initializeTags() { + int definedTagCount = 0; + ModuleUtils::iterDefinedTags( + wasm, [&definedTagCount](auto&& _) { ++definedTagCount; }); + definedTags.reserve(definedTagCount); + + for (auto& tag : wasm.tags) { + if (tag->imported()) { + auto importNames = tag->importNames(); + // TODO is getSignature correct here? + auto importedTag = + importResolver->getTagOrNull(importNames, tag->type.getSignature()); + if (!importedTag) { + externalInterface->trap((std::stringstream() + << "Imported tag " << importNames + << " not found.") + .str()); + } + auto [_, inserted] = allTags.try_emplace(tag->name, importedTag); + (void)inserted; // for noassert builds + // parsing/validation checked this already. + assert(inserted && "Unexpected repeated tag name"); + } else { + // Tags in Wasm generally represent exception types/events + // rather than literal initialized values, but keeping the + // structure consistent with your snippet: + auto& definedTag = definedTags.emplace_back(*tag); + + auto [_, inserted] = allTags.try_emplace(tag->name, &definedTag); + (void)inserted; // for noassert builds + // parsing/validation checked this already. + assert(inserted && "Unexpected repeated tag name"); + } + } + } + void initializeTables() { int definedTableCount = 0; ModuleUtils::iterDefinedTables( @@ -3706,19 +3760,19 @@ class ModuleRunnerBase : public ExpressionRunner { // the name of the tag in the current module, and finds the actual canonical // Tag* object for it: the Tag in this module, if not imported, and if // imported, the Tag in the originating module. - Tag* getCanonicalTag(Name name) { - auto* inst = self(); - auto* tag = inst->wasm.getTag(name); - if (!tag->imported()) { - return tag; - } - auto iter = inst->linkedInstances.find(tag->module); - if (iter == inst->linkedInstances.end()) { - return externalInterface->getImportedTag(tag); - } - inst = iter->second.get(); - return inst->getExportedTag(tag->base); - } + // Tag* getCanonicalTag(Name name) { + // auto* inst = self(); + // auto* tag = inst->wasm.getTag(name); + // if (!tag->imported()) { + // return tag; + // } + // auto iter = inst->linkedInstances.find(tag->module); + // if (iter == inst->linkedInstances.end()) { + // return externalInterface->getImportedTag(tag); + // } + // inst = iter->second.get(); + // return inst->getExportedTag(tag->base); + // } public: Flow visitCall(Call* curr) { @@ -4608,7 +4662,7 @@ class ModuleRunnerBase : public ExpressionRunner { auto exnData = e.exn.getExnData(); for (size_t i = 0; i < curr->catchTags.size(); i++) { - auto* tag = self()->getCanonicalTag(curr->catchTags[i]); + auto* tag = allTags[curr->catchTags[i]]; if (tag == exnData->tag) { multiValues.push_back(exnData->payload); return processCatchBody(curr->catchBodies[i]); @@ -4631,8 +4685,7 @@ class ModuleRunnerBase : public ExpressionRunner { auto exnData = e.exn.getExnData(); for (size_t i = 0; i < curr->catchTags.size(); i++) { auto catchTag = curr->catchTags[i]; - if (!catchTag.is() || - self()->getCanonicalTag(catchTag) == exnData->tag) { + if (!catchTag.is() || allTags[catchTag] == exnData->tag) { Flow ret; ret.breakTo = curr->catchDests[i]; if (catchTag.is()) { @@ -4653,8 +4706,8 @@ class ModuleRunnerBase : public ExpressionRunner { Flow visitThrow(Throw* curr) { Literals arguments; VISIT_ARGUMENTS(flow, curr->operands, arguments); - throwException(WasmException{ - self()->makeExnData(self()->getCanonicalTag(curr->tag), arguments)}); + throwException( + WasmException{self()->makeExnData(allTags[curr->tag], arguments)}); WASM_UNREACHABLE("throw"); } Flow visitRethrow(Rethrow* curr) { @@ -4749,7 +4802,7 @@ class ModuleRunnerBase : public ExpressionRunner { // old one may exist, in which case we still emit a continuation, but it is // meaningless (it will error when it reaches the host). auto old = self()->getCurrContinuationOrNull(); - auto* tag = self()->getCanonicalTag(curr->tag); + auto* tag = allTags[curr->tag]; if (!old) { return Flow(SUSPEND_FLOW, tag, std::move(arguments)); } @@ -4804,8 +4857,9 @@ class ModuleRunnerBase : public ExpressionRunner { if (auto* resumeThrow = curr->template dynCast()) { if (resumeThrow->tag) { // resume_throw - contData->exceptionTag = - self()->getModule()->getTag(resumeThrow->tag); + // this seems wrong + contData->exceptionTag = allTags[resumeThrow->tag]; + // self()->getModule()->getTag(resumeThrow->tag); } else { // resume_throw_ref contData->exception = arguments[0]; @@ -4835,7 +4889,7 @@ class ModuleRunnerBase : public ExpressionRunner { } else { // We are suspending. See if a suspension arrived that we support. for (size_t i = 0; i < curr->handlerTags.size(); i++) { - auto* handlerTag = self()->getCanonicalTag(curr->handlerTags[i]); + auto* handlerTag = allTags[curr->handlerTags[i]]; if (handlerTag == ret.suspendTag) { // Switch the flow from suspending to branching. ret.suspendTag = nullptr; From f3936d64d6341fac9c57bb0f5b7f9f1e6f7e0cae Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Thu, 29 Jan 2026 23:45:00 +0000 Subject: [PATCH 2/3] ??? not compiling --- src/tools/execution-results.h | 9 --------- src/wasm-interpreter.h | 23 ----------------------- 2 files changed, 32 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index bec95777bae..7f234f3ac50 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -78,15 +78,6 @@ struct LoggingExternalInterface : public ShellExternalInterface { jsTag.type = Signature(Type(HeapType::ext, Nullable), Type::none); } - Tag* getImportedTag(Tag* tag) override { - for (auto* imported : {&wasmTag, &jsTag}) { - if (imported->module == tag->module && imported->base == tag->base) { - return imported; - } - } - Fatal() << "missing host tag " << tag->module << '.' << tag->base; - } - Literal getImportedFunction(Function* import) override { if (linkedInstances.count(import->module)) { return getImportInstance(import)->getExportedFunction(import->base); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 97be2af8063..c04c3eea399 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2977,11 +2977,6 @@ class ModuleRunnerBase : public ExpressionRunner { virtual void trap(std::string_view why) = 0; virtual void hostLimit(std::string_view why) = 0; virtual void throwException(const WasmException& exn) = 0; - // Get the Tag instance for a tag implemented in the host, that is, not - // among the linked ModuleRunner instances, but imported from the host. - virtual Tag* getImportedTag(Tag* tag) { - WASM_UNREACHABLE("TODO remove this"); - } // the default impls for load and store switch on the sizes. you can either // customize load/store, or the sub-functions which they call @@ -3756,24 +3751,6 @@ class ModuleRunnerBase : public ExpressionRunner { return inst->getExportedFunction(func->base); } - // Get a tag object while looking through imports, i.e., this uses the name as - // the name of the tag in the current module, and finds the actual canonical - // Tag* object for it: the Tag in this module, if not imported, and if - // imported, the Tag in the originating module. - // Tag* getCanonicalTag(Name name) { - // auto* inst = self(); - // auto* tag = inst->wasm.getTag(name); - // if (!tag->imported()) { - // return tag; - // } - // auto iter = inst->linkedInstances.find(tag->module); - // if (iter == inst->linkedInstances.end()) { - // return externalInterface->getImportedTag(tag); - // } - // inst = iter->second.get(); - // return inst->getExportedTag(tag->base); - // } - public: Flow visitCall(Call* curr) { Name target = curr->target; From f67ef573b6d0c365a4995c692f1a2b78b5f6d8cf Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Thu, 29 Jan 2026 23:59:20 +0000 Subject: [PATCH 3/3] compiling now --- src/tools/wasm-ctor-eval.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 09a1552e9a3..215f9a3b6d5 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -400,11 +400,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { import->type); } - // TODO - Tag* getImportedTag(Tag* tag) override { - WASM_UNREACHABLE("missing imported tag"); - } - int8_t load8s(Address addr, Name memoryName) override { return doLoad(addr, memoryName); }