Skip to content

Commit ae1b333

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

File tree

6 files changed

+168
-89
lines changed

6 files changed

+168
-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: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,40 @@ 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,
81+
Type type) const override {
82+
externalInterface->trap((std::stringstream()
83+
<< "EvallingImportResolver: unexpected getGlobal "
84+
<< name)
85+
.str());
86+
return std::nullopt;
87+
}
88+
89+
private:
90+
ModuleRunnerBase<EvallingModuleRunner>::ExternalInterface* externalInterface;
91+
};
92+
7093
class EvallingModuleRunner : public ModuleRunnerBase<EvallingModuleRunner> {
7194
public:
7295
EvallingModuleRunner(
7396
Module& wasm,
7497
ExternalInterface* externalInterface,
7598
std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances_ = {})
76-
: ModuleRunnerBase(wasm, externalInterface, linkedInstances_) {}
99+
: ModuleRunnerBase(wasm,
100+
externalInterface,
101+
std::make_shared<EvallingImportResolver>(
102+
linkedInstances_, externalInterface),
103+
linkedInstances_) {}
77104

78105
Flow visitGlobalGet(GlobalGet* curr) {
79106
// Error on reads of imported globals.
@@ -147,19 +174,6 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) {
147174
}
148175
});
149176

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-
163177
// create an exported memory with the same initial and max size
164178
ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) {
165179
if (memory->module == env->name) {
@@ -231,26 +245,6 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
231245
}
232246
}
233247

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-
254248
Literal getImportedFunction(Function* import) override {
255249
auto f = [import, this](const Literals& arguments) -> Flow {
256250
Name WASI("wasi_snapshot_preview1");
@@ -558,8 +552,8 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
558552
void applyGlobalsToModule() {
559553
if (!wasm->features.hasGC()) {
560554
// 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);
555+
for (const auto& [name, values] : instance->allGlobals) {
556+
wasm->getGlobal(name)->init = getSerialization(*values);
563557
}
564558
return;
565559
}
@@ -590,9 +584,9 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
590584
// for it. (If there is no value, then this is a new global we've added
591585
// during execution, for whom we've already set up a proper serialized
592586
// 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);
587+
auto iter = instance->allGlobals.find(oldGlobal->name);
588+
if (iter != instance->allGlobals.end()) {
589+
oldGlobal->init = getSerialization(*iter->second, name);
596590
}
597591

598592
// 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: 67 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,22 @@ 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),
3190+
linkedInstances(std::move(linkedInstances_)),
3191+
importResolver(std::move(importResolver)) {
31893192
// Set up a single shared CurrContinuations for all these linked instances,
31903193
// reusing one if it exists.
31913194
std::shared_ptr<ContinuationStore> shared;
@@ -3208,16 +3211,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
32083211
// (This is separate from the constructor so that it does not occur
32093212
// synchronously, which makes some code patterns harder to write.)
32103213
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-
32183214
// initialize the rest of the external interface
32193215
externalInterface->init(wasm, *self());
32203216

3217+
initializeGlobals();
3218+
32213219
initializeTableContents();
32223220
initializeMemoryContents();
32233221

@@ -3254,20 +3252,30 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
32543252
func->type);
32553253
}
32563254

3257-
// get an exported global
3258-
Literals getExportedGlobal(Name name) {
3255+
std::optional<Literals*> getExportedGlobal(Name name) {
32593256
Export* export_ = wasm.getExportOrNull(name);
32603257
if (!export_ || export_->kind != ExternalKind::Global) {
3261-
externalInterface->trap("getExport external not found");
3258+
return std::nullopt;
32623259
}
32633260
Name internalName = *export_->getInternalName();
3264-
auto iter = globals.find(internalName);
3265-
if (iter == globals.end()) {
3266-
externalInterface->trap("getExport internal not found");
3261+
auto iter = allGlobals.find(internalName);
3262+
if (iter == allGlobals.end()) {
3263+
return std::nullopt;
32673264
}
32683265
return iter->second;
32693266
}
32703267

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

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

35133549
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.
3550+
// Returns a reference to the current value of a potentially imported
3551+
// function.
35283552
Literal getFunction(Name name) {
35293553
auto* inst = self();
35303554
auto* func = inst->wasm.getFunction(name);
@@ -3846,13 +3870,13 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
38463870

38473871
Flow visitGlobalGet(GlobalGet* curr) {
38483872
auto name = curr->name;
3849-
return getGlobal(name);
3873+
return *allGlobals.at(name);
38503874
}
38513875
Flow visitGlobalSet(GlobalSet* curr) {
38523876
auto name = curr->name;
38533877
VISIT(flow, curr->value)
38543878

3855-
getGlobal(name) = flow.values;
3879+
*allGlobals.at(name) = flow.values;
38563880
return Flow();
38573881
}
38583882

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

50565080
ExternalInterface* externalInterface;
50575081
std::map<Name, std::shared_ptr<SubType>> linkedInstances;
5082+
std::shared_ptr<ImportResolver> importResolver;
50585083
};
50595084

50605085
class ModuleRunner : public ModuleRunnerBase<ModuleRunner> {
@@ -5063,7 +5088,12 @@ class ModuleRunner : public ModuleRunnerBase<ModuleRunner> {
50635088
Module& wasm,
50645089
ExternalInterface* externalInterface,
50655090
std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances = {})
5066-
: ModuleRunnerBase(wasm, externalInterface, linkedInstances) {}
5091+
: ModuleRunnerBase(
5092+
wasm,
5093+
externalInterface,
5094+
std::make_shared<LinkedInstancesImportResolver<ModuleRunner>>(
5095+
linkedInstances),
5096+
linkedInstances) {}
50675097

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

0 commit comments

Comments
 (0)