diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 105 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 32 |
2 files changed, 27 insertions, 110 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 6dbff0c8f..271e96037 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -53,90 +53,23 @@ struct FailToEvalException { // the output. #define RECOMMENDATION "\n recommendation: " -// We do not have access to imported globals -class EvallingGlobalManager { - // values of globals - std::map<Name, Literals> globals; - - // globals that are dangerous to modify in the module - std::set<Name> dangerousGlobals; - - // whether we are done adding new globals - bool sealed = false; - -public: - void addDangerous(Name name) { dangerousGlobals.insert(name); } - - void seal() { sealed = true; } - - Literals& operator[](Name name) { - if (dangerousGlobals.count(name) > 0) { - std::string extra; - if (name == "___dso_handle") { - extra = RECOMMENDATION - "build with -s NO_EXIT_RUNTIME=1 so that " - "calls to atexit that use ___dso_handle are not emitted"; - } - throw FailToEvalException( - std::string( - "tried to access a dangerous (import-initialized) global: ") + - name.str + extra); - } - return globals[name]; - } - - struct Iterator { - Name first; - Literals second; - bool found; - - Iterator() : found(false) {} - Iterator(Name name, Literals value) - : first(name), second(value), found(true) {} - - bool operator==(const Iterator& other) { - return first == other.first && second == other.second && - found == other.found; - } - bool operator!=(const Iterator& other) { return !(*this == other); } - }; - - Iterator find(Name name) { - if (globals.find(name) == globals.end()) { - return end(); - } - return Iterator(name, globals[name]); - } - - Iterator end() { return Iterator(); } - - // Receives a module and applies the state of globals here into the globals - // in that module. - void applyToModule(Module& wasm) { - Builder builder(wasm); - for (const auto& [name, value] : globals) { - wasm.getGlobal(name)->init = builder.makeConstantExpression(value); - } - } -}; - -class EvallingModuleRunner - : public ModuleRunnerBase<EvallingGlobalManager, EvallingModuleRunner> { +class EvallingModuleRunner : public ModuleRunnerBase<EvallingModuleRunner> { public: EvallingModuleRunner( Module& wasm, ExternalInterface* externalInterface, std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances_ = {}) - : ModuleRunnerBase(wasm, externalInterface, linkedInstances_) { - // if any global in the module has a non-const constructor, it is using a - // global import, which we don't have, and is illegal to use - ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) { - if (!global->init->is<Const>()) { - // this global is dangerously initialized by an import, so if it is - // used, we must fail - globals.addDangerous(global->name); - } - }); + : ModuleRunnerBase(wasm, externalInterface, linkedInstances_) {} + + Flow visitGlobalGet(GlobalGet* curr) { + // Error on reads of imported globals. + auto* global = wasm.getGlobal(curr->name); + if (global->imported()) { + throw FailToEvalException(std::string("read from imported global ") + + global->module.str + "." + global->base.str); + } + + return ModuleRunnerBase<EvallingModuleRunner>::visitGlobalGet(curr); } }; @@ -229,7 +162,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { applyMemoryToModule(); } - instance->globals.applyToModule(*wasm); + applyGlobalsToModule(); } void init(Module& wasm_, EvallingModuleRunner& instance_) override { @@ -237,7 +170,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { instance = &instance_; } - void importGlobals(EvallingGlobalManager& globals, Module& wasm_) override { + void importGlobals(GlobalValueSet& globals, Module& wasm_) override { ModuleUtils::iterImportedGlobals(wasm_, [&](Global* global) { auto it = linkedInstances.find(global->module); if (it != linkedInstances.end()) { @@ -487,6 +420,13 @@ private: // memory. segment.data = memory; } + + void applyGlobalsToModule() { + Builder builder(*wasm); + for (const auto& [name, value] : instance->globals) { + wasm->getGlobal(name)->init = builder.makeConstantExpression(value); + } + } }; // The outcome of evalling a ctor is one of three states: @@ -695,9 +635,6 @@ void evalCtors(Module& wasm, try { // create an instance for evalling EvallingModuleRunner instance(wasm, &interface, linkedInstances); - // we should not add new globals from here on; as a result, using - // an imported global will fail, as it is missing and so looks new - instance.globals.seal(); // go one by one, in order, until we fail // TODO: if we knew priorities, we could reorder? for (auto& ctor : ctors) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 2a8df0111..c1d2d8674 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2264,21 +2264,7 @@ public: } }; -// Execute an initializer expression of a global, data or element segment. -// see: https://webassembly.org/docs/modules/#initializer-expression -template<typename GlobalManager> -class InitializerExpressionRunner - : public ExpressionRunner<InitializerExpressionRunner<GlobalManager>> { - GlobalManager& globals; - -public: - InitializerExpressionRunner(GlobalManager& globals, Index maxDepth) - : ExpressionRunner<InitializerExpressionRunner<GlobalManager>>(nullptr, - maxDepth), - globals(globals) {} - - Flow visitGlobalGet(GlobalGet* curr) { return Flow(globals[curr->name]); } -}; +using GlobalValueSet = std::map<Name, Literals>; // // A runner for a module. Each runner contains the information to execute the @@ -2294,7 +2280,7 @@ public: // To call into the interpreter, use callExport. // -template<typename GlobalManager, typename SubType> +template<typename SubType> class ModuleRunnerBase : public ExpressionRunner<SubType> { public: // @@ -2307,7 +2293,7 @@ public: std::map<Name, std::shared_ptr<SubType>> linkedInstances = {}) {} virtual ~ExternalInterface() = default; virtual void init(Module& wasm, SubType& instance) {} - virtual void importGlobals(GlobalManager& globals, Module& wasm) = 0; + virtual void importGlobals(GlobalValueSet& globals, Module& wasm) = 0; virtual Literals callImport(Function* import, Literals& arguments) = 0; virtual Literals callTable(Name tableName, Index index, @@ -2482,7 +2468,7 @@ public: Module& wasm; // Values of globals - GlobalManager globals; + GlobalValueSet globals; // Multivalue ABI support (see push/pop). std::vector<Literals> multiValues; @@ -2499,10 +2485,7 @@ public: memorySize = wasm.memory.initial; // generate internal (non-imported) globals ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) { - globals[global->name] = - InitializerExpressionRunner<GlobalManager>(globals, maxDepth) - .visit(global->init) - .values; + globals[global->name] = self()->visit(global->init).values; }); // initialize the rest of the external interface @@ -3687,10 +3670,7 @@ protected: std::map<Name, std::shared_ptr<SubType>> linkedInstances; }; -// The default ModuleRunner uses a trivial global manager -using TrivialGlobalManager = std::map<Name, Literals>; -class ModuleRunner - : public ModuleRunnerBase<TrivialGlobalManager, ModuleRunner> { +class ModuleRunner : public ModuleRunnerBase<ModuleRunner> { public: ModuleRunner( Module& wasm, |