Skip to content

Commit e40fac1

Browse files
Add import resolver and use it for globals
1 parent 4236103 commit e40fac1

File tree

8 files changed

+230
-89
lines changed

8 files changed

+230
-89
lines changed

src/shell-interface.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
129129
wasm, [&](Table* table) { tables[table->name].resize(table->initial); });
130130
}
131131

132-
void importGlobals(std::map<Name, Literals>& globals, Module& wasm) override {
133-
ModuleUtils::iterImportedGlobals(wasm, [&](Global* import) {
134-
auto inst = getImportInstance(import);
135-
auto* exportedGlobal = inst->wasm.getExportOrNull(import->base);
136-
if (!exportedGlobal || exportedGlobal->kind != ExternalKind::Global) {
137-
Fatal() << "importGlobals: unknown import: " << import->module.str
138-
<< "." << import->name.str;
139-
}
140-
globals[import->name] = inst->globals[*exportedGlobal->getInternalName()];
141-
});
142-
}
143-
144132
Literal getImportedFunction(Function* import) override {
145133
// TODO: We should perhaps restrict the types with which the well-known
146134
// functions can be imported.

src/tools/wasm-ctor-eval.cpp

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,39 @@ bool isNullableAndMutable(Expression* ref, Index fieldIndex) {
6767
// the output.
6868
#define RECOMMENDATION "\n recommendation: "
6969

70+
class EvallingModuleRunner;
71+
72+
class EvallingImportResolver : public ImportResolver {
73+
public:
74+
EvallingImportResolver(
75+
std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances,
76+
ModuleRunnerBase<EvallingModuleRunner>::ExternalInterface*
77+
externalInterface)
78+
: externalInterface(externalInterface) {}
79+
80+
std::optional<Literals*> getGlobal(QualifiedName name, Type type) override {
81+
externalInterface->trap((std::stringstream()
82+
<< "EvallingImportResolver: unexpected getGlobal "
83+
<< name)
84+
.str());
85+
return std::nullopt;
86+
}
87+
88+
private:
89+
ModuleRunnerBase<EvallingModuleRunner>::ExternalInterface* externalInterface;
90+
};
91+
7092
class EvallingModuleRunner : public ModuleRunnerBase<EvallingModuleRunner> {
7193
public:
7294
EvallingModuleRunner(
7395
Module& wasm,
7496
ExternalInterface* externalInterface,
7597
std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances_ = {})
76-
: ModuleRunnerBase(wasm, externalInterface, linkedInstances_) {}
98+
: ModuleRunnerBase(wasm,
99+
externalInterface,
100+
std::make_shared<EvallingImportResolver>(
101+
linkedInstances_, externalInterface),
102+
linkedInstances_) {}
77103

78104
Flow visitGlobalGet(GlobalGet* curr) {
79105
// Error on reads of imported globals.
@@ -147,19 +173,6 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) {
147173
}
148174
});
149175

150-
ModuleUtils::iterImportedGlobals(wasm, [&](Global* global) {
151-
if (global->module == env->name) {
152-
auto* copied = ModuleUtils::copyGlobal(global, *env);
153-
copied->module = Name();
154-
copied->base = Name();
155-
156-
Builder builder(*env);
157-
copied->init = builder.makeConst(Literal::makeZero(global->type));
158-
env->addExport(
159-
builder.makeExport(global->base, copied->name, ExternalKind::Global));
160-
}
161-
});
162-
163176
// create an exported memory with the same initial and max size
164177
ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) {
165178
if (memory->module == env->name) {
@@ -231,26 +244,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
231244
}
232245
}
233246

234-
void importGlobals(GlobalValueSet& globals, Module& wasm_) override {
235-
ModuleUtils::iterImportedGlobals(wasm_, [&](Global* global) {
236-
auto it = linkedInstances.find(global->module);
237-
if (it != linkedInstances.end()) {
238-
auto* inst = it->second.get();
239-
auto* globalExport = inst->wasm.getExportOrNull(global->base);
240-
if (!globalExport || globalExport->kind != ExternalKind::Global) {
241-
throw FailToEvalException(std::string("importGlobals: ") +
242-
global->module.toString() + "." +
243-
global->base.toString());
244-
}
245-
globals[global->name] = inst->globals[*globalExport->getInternalName()];
246-
} else {
247-
throw FailToEvalException(std::string("importGlobals: ") +
248-
global->module.toString() + "." +
249-
global->base.toString());
250-
}
251-
});
252-
}
253-
254247
Literal getImportedFunction(Function* import) override {
255248
auto f = [import, this](const Literals& arguments) -> Flow {
256249
Name WASI("wasi_snapshot_preview1");
@@ -558,8 +551,8 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
558551
void applyGlobalsToModule() {
559552
if (!wasm->features.hasGC()) {
560553
// Without GC, we can simply serialize the globals in place as they are.
561-
for (const auto& [name, values] : instance->globals) {
562-
wasm->getGlobal(name)->init = getSerialization(values);
554+
for (const auto& [name, values] : instance->allGlobals) {
555+
wasm->getGlobal(name)->init = getSerialization(*values);
563556
}
564557
return;
565558
}
@@ -590,9 +583,9 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
590583
// for it. (If there is no value, then this is a new global we've added
591584
// during execution, for whom we've already set up a proper serialized
592585
// value when we created it.)
593-
auto iter = instance->globals.find(oldGlobal->name);
594-
if (iter != instance->globals.end()) {
595-
oldGlobal->init = getSerialization(iter->second, name);
586+
auto iter = instance->allGlobals.find(oldGlobal->name);
587+
if (iter != instance->allGlobals.end()) {
588+
oldGlobal->init = getSerialization(*iter->second, name);
596589
}
597590

598591
// Add the global back to the module.

src/tools/wasm-shell.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ struct Shell {
278278
}
279279
auto& instance = it->second;
280280
try {
281-
return instance->getExportedGlobal(get->name);
281+
return instance->getExportedGlobalOrTrap(get->name);
282282
} catch (TrapException&) {
283283
return TrapResult{};
284284
} catch (...) {

src/wasm-interpreter.h

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#define wasm_wasm_interpreter_h
3030

3131
#include <cmath>
32+
#include <iomanip>
3233
#include <limits.h>
3334
#include <sstream>
3435
#include <variant>
@@ -46,6 +47,7 @@
4647
#include "wasm-limits.h"
4748
#include "wasm-traversal.h"
4849
#include "wasm.h"
50+
#include "wasm/import-resolver.h"
4951

5052
#if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer)
5153
#include <sanitizer/lsan_interface.h>
@@ -2940,8 +2942,6 @@ class ConstantExpressionRunner : public ExpressionRunner<SubType> {
29402942
}
29412943
};
29422944

2943-
using GlobalValueSet = std::map<Name, Literals>;
2944-
29452945
//
29462946
// A runner for a module. Each runner contains the information to execute the
29472947
// module, such as the state of globals, and so forth, so it basically
@@ -2969,7 +2969,6 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
29692969
std::map<Name, std::shared_ptr<SubType>> linkedInstances = {}) {}
29702970
virtual ~ExternalInterface() = default;
29712971
virtual void init(Module& wasm, SubType& instance) {}
2972-
virtual void importGlobals(GlobalValueSet& globals, Module& wasm) = 0;
29732972
virtual Literal getImportedFunction(Function* import) = 0;
29742973
virtual bool growMemory(Name name, Address oldSize, Address newSize) = 0;
29752974
virtual bool growTable(Name name,
@@ -3174,18 +3173,21 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
31743173
// TODO: this duplicates module in ExpressionRunner, and can be removed
31753174
Module& wasm;
31763175

3177-
// Values of globals
3178-
GlobalValueSet globals;
3179-
31803176
// Multivalue ABI support (see push/pop).
31813177
std::vector<Literals> multiValues;
31823178

3179+
// keyed by internal name
3180+
std::map<Name, Literals> definedGlobals;
3181+
std::map<Name, Literals*> allGlobals;
3182+
31833183
ModuleRunnerBase(
31843184
Module& wasm,
31853185
ExternalInterface* externalInterface,
3186+
std::shared_ptr<ImportResolver> importResolver,
31863187
std::map<Name, std::shared_ptr<SubType>> linkedInstances_ = {})
31873188
: ExpressionRunner<SubType>(&wasm), wasm(wasm),
3188-
externalInterface(externalInterface), linkedInstances(linkedInstances_) {
3189+
externalInterface(externalInterface), linkedInstances(linkedInstances_),
3190+
importResolver(importResolver) {
31893191
// Set up a single shared CurrContinuations for all these linked instances,
31903192
// reusing one if it exists.
31913193
std::shared_ptr<ContinuationStore> shared;
@@ -3208,16 +3210,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
32083210
// (This is separate from the constructor so that it does not occur
32093211
// synchronously, which makes some code patterns harder to write.)
32103212
void instantiate() {
3211-
// import globals from the outside
3212-
externalInterface->importGlobals(globals, wasm);
3213-
// generate internal (non-imported) globals
3214-
ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
3215-
globals[global->name] = self()->visit(global->init).values;
3216-
});
3217-
32183213
// initialize the rest of the external interface
32193214
externalInterface->init(wasm, *self());
32203215

3216+
initializeGlobals();
3217+
32213218
initializeTableContents();
32223219
initializeMemoryContents();
32233220

@@ -3254,20 +3251,30 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
32543251
func->type);
32553252
}
32563253

3257-
// get an exported global
3258-
Literals getExportedGlobal(Name name) {
3254+
std::optional<Literals*> getExportedGlobal(Name name) {
32593255
Export* export_ = wasm.getExportOrNull(name);
32603256
if (!export_ || export_->kind != ExternalKind::Global) {
3261-
externalInterface->trap("getExport external not found");
3257+
return std::nullopt;
32623258
}
32633259
Name internalName = *export_->getInternalName();
3264-
auto iter = globals.find(internalName);
3265-
if (iter == globals.end()) {
3266-
externalInterface->trap("getExport internal not found");
3260+
auto iter = allGlobals.find(internalName);
3261+
if (iter == allGlobals.end()) {
3262+
return std::nullopt;
32673263
}
32683264
return iter->second;
32693265
}
32703266

3267+
Literals& getExportedGlobalOrTrap(Name name) {
3268+
auto global = getExportedGlobal(name);
3269+
if (!global.has_value()) {
3270+
externalInterface->trap((std::stringstream()
3271+
<< "getExportedGlobal: export " << name
3272+
<< " not found.")
3273+
.str());
3274+
}
3275+
return **global;
3276+
}
3277+
32713278
Tag* getExportedTag(Name name) {
32723279
Export* export_ = wasm.getExportOrNull(name);
32733280
if (!export_ || export_->kind != ExternalKind::Tag) {
@@ -3321,6 +3328,34 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33213328
return TableInstanceInfo{self(), name};
33223329
}
33233330

3331+
void initializeGlobals() {
3332+
for (auto& global : wasm.globals) {
3333+
if (global->imported()) {
3334+
QualifiedName name{global->module, global->base};
3335+
auto importedGlobal = importResolver->getGlobal(name, global->type);
3336+
if (!importedGlobal) {
3337+
externalInterface->trap(
3338+
(std::stringstream() << "Imported global " << name << " not found.")
3339+
.str());
3340+
}
3341+
allGlobals[global->name] = *importedGlobal;
3342+
} else {
3343+
Literals init = self()->visit(global->init).values;
3344+
auto [it, inserted] = definedGlobals.emplace(global->name, init);
3345+
3346+
// This was likely checked during parsing or validation
3347+
if (!inserted) {
3348+
externalInterface->trap(
3349+
(std::stringstream()
3350+
<< "Global: " << std::quoted(global->name.toString())
3351+
<< " was defined twice.")
3352+
.str());
3353+
}
3354+
allGlobals[global->name] = &it->second;
3355+
}
3356+
}
3357+
}
3358+
33243359
void initializeTableContents() {
33253360
for (auto& table : wasm.tables) {
33263361
if (table->type.isNullable()) {
@@ -3511,20 +3546,8 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
35113546
SmallVector<std::pair<WasmException, Name>, 4> exceptionStack;
35123547

35133548
protected:
3514-
// Returns a reference to the current value of a potentially imported global.
3515-
Literals& getGlobal(Name name) {
3516-
auto* inst = self();
3517-
auto* global = inst->wasm.getGlobal(name);
3518-
while (global->imported()) {
3519-
inst = inst->linkedInstances.at(global->module).get();
3520-
Export* globalExport = inst->wasm.getExport(global->base);
3521-
global = inst->wasm.getGlobal(*globalExport->getInternalName());
3522-
}
3523-
3524-
return inst->globals[global->name];
3525-
}
3526-
3527-
// As above, but for a function.
3549+
// Returns a reference to the current value of a potentially imported
3550+
// function.
35283551
Literal getFunction(Name name) {
35293552
auto* inst = self();
35303553
auto* func = inst->wasm.getFunction(name);
@@ -3846,13 +3869,13 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
38463869

38473870
Flow visitGlobalGet(GlobalGet* curr) {
38483871
auto name = curr->name;
3849-
return getGlobal(name);
3872+
return *allGlobals.at(name);
38503873
}
38513874
Flow visitGlobalSet(GlobalSet* curr) {
38523875
auto name = curr->name;
38533876
VISIT(flow, curr->value)
38543877

3855-
getGlobal(name) = flow.values;
3878+
*allGlobals.at(name) = flow.values;
38563879
return Flow();
38573880
}
38583881

@@ -5055,6 +5078,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
50555078

50565079
ExternalInterface* externalInterface;
50575080
std::map<Name, std::shared_ptr<SubType>> linkedInstances;
5081+
std::shared_ptr<ImportResolver> importResolver;
50585082
};
50595083

50605084
class ModuleRunner : public ModuleRunnerBase<ModuleRunner> {
@@ -5063,7 +5087,15 @@ class ModuleRunner : public ModuleRunnerBase<ModuleRunner> {
50635087
Module& wasm,
50645088
ExternalInterface* externalInterface,
50655089
std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances = {})
5066-
: ModuleRunnerBase(wasm, externalInterface, linkedInstances) {}
5090+
: ModuleRunnerBase(
5091+
wasm,
5092+
externalInterface,
5093+
std::make_shared<ChainedImportResolver>(
5094+
std::initializer_list<std::shared_ptr<ImportResolver>>{
5095+
std::make_shared<SpecTestModuleImportResolver>(),
5096+
std::make_shared<LinkedInstancesImportResolver<ModuleRunner>>(
5097+
linkedInstances)}),
5098+
linkedInstances) {}
50675099

50685100
Literal makeFuncData(Name name, Type type) {
50695101
// As the super's |makeFuncData|, but here we also provide a way to

src/wasm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
file(GLOB wasm_HEADERS ../*.h)
22
set(wasm_SOURCES
33
literal.cpp
4+
import-resolver.cpp
45
parsing.cpp
56
source-map.cpp
67
wasm.cpp

0 commit comments

Comments
 (0)