summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-01-06 14:33:04 -0800
committerGitHub <noreply@github.com>2022-01-06 14:33:04 -0800
commit5049f077ae2d21166dc8ee4c3057bdc48cb3d94c (patch)
tree8adebb5f32a3ff4cd8901a843ef66d1f7a4ad00f /src
parent5e3a53bb8306e732d1b40cd09fe1853645cdfbfa (diff)
downloadbinaryen-5049f077ae2d21166dc8ee4c3057bdc48cb3d94c.tar.gz
binaryen-5049f077ae2d21166dc8ee4c3057bdc48cb3d94c.tar.bz2
binaryen-5049f077ae2d21166dc8ee4c3057bdc48cb3d94c.zip
[ctor-eval] Refactor an applyToModule() method instead of hacks [NFC] (#4425)
Previously this would hackishly apply all execution changes to the memory all the time, and then "undo" it by saving the state before and copying that in. Instead, this PR makes execution write into a side buffer, and now there is a clear method for when we want to actually apply the results to the module.
Diffstat (limited to 'src')
-rw-r--r--src/tools/wasm-ctor-eval.cpp57
1 files changed, 38 insertions, 19 deletions
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index f03bbec1d..b0a1c0551 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -199,12 +199,24 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
EvallingModuleInstance* instance;
std::map<Name, std::shared_ptr<EvallingModuleInstance>> linkedInstances;
+ // A representation of the contents of wasm memory as we execute.
+ std::vector<char> memory;
+
CtorEvalExternalInterface(
std::map<Name, std::shared_ptr<EvallingModuleInstance>> linkedInstances_ =
{}) {
linkedInstances.swap(linkedInstances_);
}
+ // Called when we want to apply the current state of execution to the Module.
+ // Until this is called the Module is never changed.
+ void applyToModule() {
+ // If nothing was ever written to memory then there is nothing to update.
+ if (!memory.empty()) {
+ applyMemoryToModule();
+ }
+ }
+
void init(Module& wasm_, EvallingModuleInstance& instance_) override {
wasm = &wasm_;
instance = &instance_;
@@ -365,22 +377,12 @@ private:
// TODO: handle unaligned too, see shell-interface
template<typename T> T* getMemory(Address address) {
- // this must be in the singleton segment. resize as needed
- if (wasm->memory.segments.size() == 0) {
- std::vector<char> temp;
- Builder builder(*wasm);
- wasm->memory.segments.push_back(
- Memory::Segment(builder.makeConst(int32_t(0)), temp));
- }
- // memory should already have been flattened
- assert(wasm->memory.segments[0].offset->cast<Const>()->value.getInteger() ==
- 0);
+ // resize the memory buffer as needed.
auto max = address + sizeof(T);
- auto& data = wasm->memory.segments[0].data;
- if (max > data.size()) {
- data.resize(max);
+ if (max > memory.size()) {
+ memory.resize(max);
}
- return (T*)(&data[address]);
+ return (T*)(&memory[address]);
}
template<typename T> void doStore(Address address, T value) {
@@ -394,6 +396,23 @@ private:
memcpy(&ret, getMemory<T>(address), sizeof(T));
return ret;
}
+
+ void applyMemoryToModule() {
+ // Memory must have already been flattened into the standard form: one
+ // segment at offset 0, or none.
+ if (wasm->memory.segments.empty()) {
+ Builder builder(*wasm);
+ std::vector<char> empty;
+ wasm->memory.segments.push_back(
+ Memory::Segment(builder.makeConst(int32_t(0)), empty));
+ }
+ auto& segment = wasm->memory.segments[0];
+ assert(segment.offset->cast<Const>()->value.getInteger() == 0);
+
+ // Copy the current memory contents after execution into the Module's
+ // memory.
+ segment.data = memory;
+ }
};
void evalCtors(Module& wasm, std::vector<std::string> ctors) {
@@ -422,8 +441,6 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
// TODO: if we knew priorities, we could reorder?
for (auto& ctor : ctors) {
std::cerr << "trying to eval " << ctor << '\n';
- // snapshot memory, as either the entire function is done, or none
- auto memoryBefore = wasm.memory;
// snapshot globals (note that STACKTOP might be modified, but should
// be returned, so that works out)
auto globalsBefore = instance.globals;
@@ -437,16 +454,18 @@ void evalCtors(Module& wasm, std::vector<std::string> ctors) {
// that's it, we failed, so stop here, cleaning up partial
// memory changes first
std::cerr << " ...stopping since could not eval: " << fail.why << "\n";
- wasm.memory = memoryBefore;
return;
}
if (instance.globals != globalsBefore) {
std::cerr << " ...stopping since globals modified\n";
- wasm.memory = memoryBefore;
return;
}
std::cerr << " ...success on " << ctor << ".\n";
- // success, the entire function was evalled!
+
+ // Success, the entire function was evalled! Apply the results of
+ // execution to the module.
+ interface.applyToModule();
+
// we can nop the function (which may be used elsewhere)
// and remove the export
auto* exp = wasm.getExport(ctor);