summaryrefslogtreecommitdiff
path: root/src/tools/wasm-ctor-eval.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/wasm-ctor-eval.cpp')
-rw-r--r--src/tools/wasm-ctor-eval.cpp207
1 files changed, 119 insertions, 88 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 420ec06ad..2050b3ebc 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -24,19 +24,19 @@
#include <memory>
+#include "ir/global-utils.h"
+#include "ir/import-utils.h"
+#include "ir/literal-utils.h"
+#include "ir/memory-utils.h"
+#include "ir/module-utils.h"
#include "pass.h"
-#include "support/file.h"
#include "support/colors.h"
+#include "support/file.h"
#include "tool-options.h"
-#include "wasm-io.h"
-#include "wasm-interpreter.h"
#include "wasm-builder.h"
+#include "wasm-interpreter.h"
+#include "wasm-io.h"
#include "wasm-validator.h"
-#include "ir/memory-utils.h"
-#include "ir/global-utils.h"
-#include "ir/import-utils.h"
-#include "ir/literal-utils.h"
-#include "ir/module-utils.h"
using namespace wasm;
@@ -57,13 +57,9 @@ class EvallingGlobalManager {
bool sealed = false;
public:
- void addDangerous(Name name) {
- dangerousGlobals.insert(name);
- }
+ void addDangerous(Name name) { dangerousGlobals.insert(name); }
- void seal() {
- sealed = true;
- }
+ void seal() { sealed = true; }
// for equality purposes, we just care about the globals
// and whether they have changed
@@ -78,9 +74,13 @@ public:
if (dangerousGlobals.count(name) > 0) {
std::string extra;
if (name == "___dso_handle") {
- extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls to atexit that use ___dso_handle are not emitted";
+ extra = "\nrecommendation: 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);
+ throw FailToEvalException(
+ std::string(
+ "tried to access a dangerous (import-initialized) global: ") +
+ name.str + extra);
}
return globals[name];
}
@@ -91,14 +91,14 @@ public:
bool found;
Iterator() : found(false) {}
- Iterator(Name name, Literal value) : first(name), second(value), found(true) {}
+ Iterator(Name name, Literal 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);
+ return first == other.first && second == other.second &&
+ found == other.found;
}
+ bool operator!=(const Iterator& other) { return !(*this == other); }
};
Iterator find(Name name) {
@@ -108,9 +108,7 @@ public:
return Iterator(name, globals[name]);
}
- Iterator end() {
- return Iterator();
- }
+ Iterator end() { return Iterator(); }
};
// Use a ridiculously large stack size.
@@ -125,25 +123,28 @@ static Index STACK_START = 1024 * 1024 * 1024 + STACK_SIZE;
static Index STACK_LOWER_LIMIT = STACK_START - STACK_SIZE;
static Index STACK_UPPER_LIMIT = STACK_START + STACK_SIZE;
-class EvallingModuleInstance : public ModuleInstanceBase<EvallingGlobalManager, EvallingModuleInstance> {
+class EvallingModuleInstance
+ : public ModuleInstanceBase<EvallingGlobalManager, EvallingModuleInstance> {
public:
- EvallingModuleInstance(Module& wasm, ExternalInterface* externalInterface) : ModuleInstanceBase(wasm, externalInterface) {
- // 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
+ EvallingModuleInstance(Module& wasm, ExternalInterface* externalInterface)
+ : ModuleInstanceBase(wasm, externalInterface) {
+ // 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>()) {
// some constants are ok to use
if (auto* get = global->init->dynCast<GetGlobal>()) {
auto name = get->name;
auto* import = wasm.getGlobal(name);
- if (import->module == Name(ENV) && (
- import->base == STACKTOP || // stack constants are special, we handle them
- import->base == STACK_MAX
- )) {
+ if (import->module == Name(ENV) &&
+ (import->base ==
+ STACKTOP || // stack constants are special, we handle them
+ import->base == STACK_MAX)) {
return; // this is fine
}
}
- // this global is dangerously initialized by an import, so if it is used, we must fail
+ // this global is dangerously initialized by an import, so if it is
+ // used, we must fail
globals.addDangerous(global->name);
}
});
@@ -177,13 +178,15 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
ImportInfo imports(wasm_);
if (auto* stackTop = imports.getImportedGlobal(ENV, STACKTOP)) {
globals[stackTop->name] = Literal(int32_t(STACK_START));
- if (auto* stackTop = GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACKTOP)) {
+ if (auto* stackTop =
+ GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACKTOP)) {
globals[stackTop->name] = Literal(int32_t(STACK_START));
}
}
if (auto* stackMax = imports.getImportedGlobal(ENV, STACK_MAX)) {
globals[stackMax->name] = Literal(int32_t(STACK_START));
- if (auto* stackMax = GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACK_MAX)) {
+ if (auto* stackMax =
+ GlobalUtils::getGlobalInitializedToImport(wasm_, ENV, STACK_MAX)) {
globals[stackMax->name] = Literal(int32_t(STACK_START));
}
}
@@ -203,19 +206,26 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
Literal callImport(Function* import, LiteralList& arguments) override {
std::string extra;
if (import->module == ENV && import->base == "___cxa_atexit") {
- extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls to atexit are not emitted";
+ extra = "\nrecommendation: build with -s NO_EXIT_RUNTIME=1 so that calls "
+ "to atexit are not emitted";
}
- throw FailToEvalException(std::string("call import: ") + import->module.str + "." + import->base.str + extra);
+ throw FailToEvalException(std::string("call import: ") +
+ import->module.str + "." + import->base.str +
+ extra);
}
- Literal callTable(Index index, LiteralList& arguments, Type result, EvallingModuleInstance& instance) override {
+ Literal callTable(Index index,
+ LiteralList& arguments,
+ Type result,
+ EvallingModuleInstance& instance) override {
// we assume the table is not modified (hmm)
// look through the segments, try to find the function
for (auto& segment : wasm->table.segments) {
Index start;
- // look for the index in this segment. if it has a constant offset, we look in
- // the proper range. if it instead gets a global, we rely on the fact that when
- // not dynamically linking then the table is loaded at offset 0.
+ // look for the index in this segment. if it has a constant offset, we
+ // look in the proper range. if it instead gets a global, we rely on the
+ // fact that when not dynamically linking then the table is loaded at
+ // offset 0.
if (auto* c = segment.offset->dynCast<Const>()) {
start = c->value.getInteger();
} else if (segment.offset->is<GetGlobal>()) {
@@ -226,16 +236,20 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
auto end = start + segment.data.size();
if (start <= index && index < end) {
auto name = segment.data[index - start];
- // if this is one of our functions, we can call it; if it was imported, fail
+ // if this is one of our functions, we can call it; if it was imported,
+ // fail
auto* func = wasm->getFunction(name);
if (!func->imported()) {
return instance.callFunctionInternal(name, arguments);
} else {
- throw FailToEvalException(std::string("callTable on imported function: ") + name.str);
+ throw FailToEvalException(
+ std::string("callTable on imported function: ") + name.str);
}
}
}
- throw FailToEvalException(std::string("callTable on index not found in static segments: ") + std::to_string(index));
+ throw FailToEvalException(
+ std::string("callTable on index not found in static segments: ") +
+ std::to_string(index));
}
int8_t load8s(Address addr) override { return doLoad<int8_t>(addr); }
@@ -247,13 +261,21 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
int64_t load64s(Address addr) override { return doLoad<int64_t>(addr); }
uint64_t load64u(Address addr) override { return doLoad<uint64_t>(addr); }
- void store8(Address addr, int8_t value) override { doStore<int8_t>(addr, value); }
- void store16(Address addr, int16_t value) override { doStore<int16_t>(addr, value); }
- void store32(Address addr, int32_t value) override { doStore<int32_t>(addr, value); }
- void store64(Address addr, int64_t value) override { doStore<int64_t>(addr, value); }
+ void store8(Address addr, int8_t value) override {
+ doStore<int8_t>(addr, value);
+ }
+ void store16(Address addr, int16_t value) override {
+ doStore<int16_t>(addr, value);
+ }
+ void store32(Address addr, int32_t value) override {
+ doStore<int32_t>(addr, value);
+ }
+ void store64(Address addr, int64_t value) override {
+ doStore<int64_t>(addr, value);
+ }
// called during initialization, but we don't keep track of a table
- void tableStore(Address addr, Name value) override { }
+ void tableStore(Address addr, Name value) override {}
void growMemory(Address /*oldSize*/, Address newSize) override {
throw FailToEvalException("grow memory");
@@ -266,8 +288,7 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
private:
// TODO: handle unaligned too, see shell-interface
- template<typename T>
- T* getMemory(Address address) {
+ template<typename T> T* getMemory(Address address) {
// if memory is on the stack, use the stack
if (address >= STACK_LOWER_LIMIT) {
if (address >= STACK_UPPER_LIMIT) {
@@ -283,14 +304,11 @@ private:
std::vector<char> temp;
Builder builder(*wasm);
wasm->memory.segments.push_back(
- Memory::Segment(
- builder.makeConst(Literal(int32_t(0))),
- temp
- )
- );
+ Memory::Segment(builder.makeConst(Literal(int32_t(0))), temp));
}
// memory should already have been flattened
- assert(wasm->memory.segments[0].offset->cast<Const>()->value.getInteger() == 0);
+ assert(wasm->memory.segments[0].offset->cast<Const>()->value.getInteger() ==
+ 0);
auto max = address + sizeof(T);
auto& data = wasm->memory.segments[0].data;
if (max > data.size()) {
@@ -299,14 +317,12 @@ private:
return (T*)(&data[address]);
}
- template<typename T>
- void doStore(Address address, T value) {
+ template<typename T> void doStore(Address address, T value) {
// do a memcpy to avoid undefined behavior if unaligned
memcpy(getMemory<T>(address), &value, sizeof(T));
}
- template<typename T>
- T doLoad(Address address) {
+ template<typename T> T doLoad(Address address) {
// do a memcpy to avoid undefined behavior if unaligned
T ret;
memcpy(&ret, getMemory<T>(address), sizeof(T));
@@ -337,7 +353,7 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
// snapshot globals (note that STACKTOP might be modified, but should
// be returned, so that works out)
auto globalsBefore = instance.globals;
- Export *ex = wasm.getExportOrNull(ctor);
+ Export* ex = wasm.getExportOrNull(ctor);
if (!ex) {
Fatal() << "export not found: " << ctor;
}
@@ -366,7 +382,8 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
}
} catch (FailToEvalException& fail) {
// that's it, we failed to even create the instance
- std::cerr << " ...stopping since could not create module instance: " << fail.why << "\n";
+ std::cerr << " ...stopping since could not create module instance: "
+ << fail.why << "\n";
return;
}
}
@@ -382,37 +399,50 @@ int main(int argc, const char* argv[]) {
bool debugInfo = false;
std::string ctorsString;
- ToolOptions options("wasm-ctor-eval", "Execute C++ global constructors ahead of time");
+ ToolOptions options("wasm-ctor-eval",
+ "Execute C++ global constructors ahead of time");
options
- .add("--output", "-o", "Output file (stdout if not specified)",
- Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["output"] = argument;
- Colors::disable();
- })
- .add("--emit-text", "-S", "Emit text instead of binary for the output file",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& argument) { emitBinary = false; })
- .add("--debuginfo", "-g", "Emit names section and debug info",
- Options::Arguments::Zero,
- [&](Options *o, const std::string& arguments) { debugInfo = true; })
- .add("--ctors", "-c", "Comma-separated list of global constructor functions to evaluate",
- Options::Arguments::One,
- [&](Options* o, const std::string& argument) {
- ctorsString = argument;
- })
- .add_positional("INFILE", Options::Arguments::One,
- [](Options* o, const std::string& argument) {
- o->extra["infile"] = argument;
- });
+ .add("--output",
+ "-o",
+ "Output file (stdout if not specified)",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["output"] = argument;
+ Colors::disable();
+ })
+ .add("--emit-text",
+ "-S",
+ "Emit text instead of binary for the output file",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& argument) { emitBinary = false; })
+ .add("--debuginfo",
+ "-g",
+ "Emit names section and debug info",
+ Options::Arguments::Zero,
+ [&](Options* o, const std::string& arguments) { debugInfo = true; })
+ .add(
+ "--ctors",
+ "-c",
+ "Comma-separated list of global constructor functions to evaluate",
+ Options::Arguments::One,
+ [&](Options* o, const std::string& argument) { ctorsString = argument; })
+ .add_positional("INFILE",
+ Options::Arguments::One,
+ [](Options* o, const std::string& argument) {
+ o->extra["infile"] = argument;
+ });
options.parse(argc, argv);
- auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));
+ auto input(
+ read_file<std::string>(options.extra["infile"],
+ Flags::Text,
+ options.debug ? Flags::Debug : Flags::Release));
Module wasm;
{
- if (options.debug) std::cerr << "reading...\n";
+ if (options.debug)
+ std::cerr << "reading...\n";
ModuleReader reader;
reader.setDebug(options.debug);
@@ -453,7 +483,8 @@ int main(int argc, const char* argv[]) {
}
if (options.extra.count("output") > 0) {
- if (options.debug) std::cerr << "writing..." << std::endl;
+ if (options.debug)
+ std::cerr << "writing..." << std::endl;
ModuleWriter writer;
writer.setDebug(options.debug);
writer.setBinary(emitBinary);