Followups with trap to remove ExternalInterface
diff --git a/src/ir/runtime-memory.cpp b/src/ir/runtime-memory.cpp index 8c11f81..18fad75 100644 --- a/src/ir/runtime-memory.cpp +++ b/src/ir/runtime-memory.cpp
@@ -17,17 +17,18 @@ #include "ir/runtime-memory.h" #include "fp16.h" #include "interpreter/exception.h" +#include <iostream> namespace wasm { -RuntimeMemory::RuntimeMemory(Memory memory, - ExternalInterface* externalInterface) - : externalInterface(externalInterface), memoryDefinition(std::move(memory)) {} - namespace { -Address getFinalAddress(const RuntimeMemory& runtimeMemory, - Address addr, +[[noreturn]] void trap(std::string_view reason) { + std::cout << "[trap " << reason << "]\n"; + throw TrapException{}; +} + +Address getFinalAddress(Address addr, Address offset, Index bytes, Address memorySizeBytes) { @@ -36,14 +37,14 @@ msg += std::to_string(uint64_t(offset)); msg += " > "; msg += std::to_string(uint64_t(memorySizeBytes)); - runtimeMemory.trap(msg); + trap(msg); } if (addr > memorySizeBytes - offset) { std::string msg = "final > memory: "; msg += std::to_string(uint64_t(addr)); msg += " > "; msg += std::to_string(uint64_t(memorySizeBytes - offset)); - runtimeMemory.trap(msg); + trap(msg); } addr = size_t(addr) + offset; @@ -55,13 +56,12 @@ msg += std::to_string(uint64_t(bytes)); msg += " > "; msg += std::to_string(uint64_t(memorySizeBytes)); - runtimeMemory.trap(msg); + trap(msg); } return addr; } -void checkLoadAddress(const RuntimeMemory& runtimeMemory, - Address addr, +void checkLoadAddress(Address addr, Index bytes, Address memorySizeBytes) { if (addr > memorySizeBytes || bytes > memorySizeBytes - addr) { @@ -71,19 +71,18 @@ msg += std::to_string(uint64_t(bytes)); msg += " > "; msg += std::to_string(uint64_t(memorySizeBytes)); - runtimeMemory.trap(msg); + trap(msg); } } -void checkAtomicAddress(const RuntimeMemory& runtimeMemory, - Address addr, +void checkAtomicAddress(Address addr, Index bytes, Address memorySizeBytes) { - checkLoadAddress(runtimeMemory, addr, bytes, memorySizeBytes); + checkLoadAddress(addr, bytes, memorySizeBytes); // Unaligned atomics trap. if (bytes > 1) { if (addr & (bytes - 1)) { - runtimeMemory.trap("unaligned atomic operation"); + trap("unaligned atomic operation"); } } } @@ -95,9 +94,8 @@ } // namespace -RealRuntimeMemory::RealRuntimeMemory(Memory memory, - ExternalInterface* externalInterface) - : RuntimeMemory(std::move(memory), externalInterface) { +RealRuntimeMemory::RealRuntimeMemory(Memory memory) + : RuntimeMemory(std::move(memory)) { resize(memoryDefinition.initialByteSize()); } @@ -107,9 +105,9 @@ MemoryOrder order, Type type, bool signed_) const { - Address final = getFinalAddress(*this, addr, offset, byteCount, size()); + Address final = getFinalAddress(addr, offset, byteCount, size()); if (order != MemoryOrder::Unordered) { - checkAtomicAddress(*this, final, byteCount, size()); + checkAtomicAddress(final, byteCount, size()); } switch (type.getBasic()) { case Type::i32: { @@ -170,9 +168,9 @@ MemoryOrder order, Literal value, Type type) { - Address final = getFinalAddress(*this, addr, offset, byteCount, size()); + Address final = getFinalAddress(addr, offset, byteCount, size()); if (order != MemoryOrder::Unordered) { - checkAtomicAddress(*this, final, byteCount, size()); + checkAtomicAddress(final, byteCount, size()); } switch (type.getBasic()) { case Type::i32: { @@ -213,9 +211,9 @@ case Type::f32: { switch (byteCount) { case 2: - set<uint16_t>( - final, - fp16_ieee_from_fp32_value(bit_cast<float>(value.reinterpreti32()))); + set<uint16_t>(final, + fp16_ieee_from_fp32_value( + bit_cast<float>(value.reinterpreti32()))); break; case 4: set<int32_t>(final, value.reinterpreti32()); @@ -261,7 +259,7 @@ if (src > data->data.size() || byteCount > data->data.size() - src) { trap("out of bounds segment access in memory.init"); } - Address final = getFinalAddress(*this, dest, 0, byteCount, size()); + Address final = getFinalAddress(dest, 0, byteCount, size()); if (byteCount > 0) { std::memcpy(&memory[final], &data->data[src], byteCount); } @@ -271,9 +269,8 @@ Address src, Address byteCount, const RuntimeMemory* srcMemory) { - Address finalDest = getFinalAddress(*this, dest, 0, byteCount, size()); - Address finalSrc = - getFinalAddress(*srcMemory, src, 0, byteCount, srcMemory->size()); + Address finalDest = getFinalAddress(dest, 0, byteCount, size()); + Address finalSrc = getFinalAddress(src, 0, byteCount, srcMemory->size()); const std::vector<uint8_t>* srcBuffer = srcMemory->getBuffer(); if (!srcBuffer) { // If it's not a memory with a direct buffer, we might need another way to @@ -287,7 +284,7 @@ } void RealRuntimeMemory::fill(Address dest, uint8_t value, Address byteCount) { - Address final = getFinalAddress(*this, dest, 0, byteCount, size()); + Address final = getFinalAddress(dest, 0, byteCount, size()); if (byteCount > 0) { std::memset(&memory[final], value, byteCount); } @@ -300,8 +297,7 @@ size_t newAllocatedSize = std::max(minSize, newSize); if (newAllocatedSize > oldAllocatedSize) { memory.resize(newAllocatedSize); - std::memset( - &memory[oldAllocatedSize], 0, newAllocatedSize - oldAllocatedSize); + std::memset(&memory[oldAllocatedSize], 0, newAllocatedSize - oldAllocatedSize); } if (newSize < oldAllocatedSize && newSize < minSize) { std::memset(&memory[newSize], 0, minSize - newSize); @@ -347,7 +343,6 @@ template void RealRuntimeMemory::set<int64_t>(size_t, int64_t); template void RealRuntimeMemory::set<uint64_t>(size_t, uint64_t); template void -RealRuntimeMemory::set<std::array<uint8_t, 16>>(size_t, - std::array<uint8_t, 16>); +RealRuntimeMemory::set<std::array<uint8_t, 16>>(size_t, std::array<uint8_t, 16>); } // namespace wasm
diff --git a/src/ir/runtime-memory.h b/src/ir/runtime-memory.h index d57bf10..89f3515 100644 --- a/src/ir/runtime-memory.h +++ b/src/ir/runtime-memory.h
@@ -23,13 +23,7 @@ class RuntimeMemory { public: - // Forward declare to avoid circular dependency - struct ExternalInterface { - virtual ~ExternalInterface() = default; - virtual void trap(std::string_view why) = 0; - }; - - RuntimeMemory(Memory memory, ExternalInterface* externalInterface); + RuntimeMemory(Memory memory) : memoryDefinition(std::move(memory)) {} virtual ~RuntimeMemory() = default; virtual Literal load(Address addr, @@ -50,15 +44,11 @@ virtual Address size() const = 0; - virtual void init(Address dest, - Address src, - Address byteCount, - const DataSegment* data) = 0; + virtual void + init(Address dest, Address src, Address byteCount, const DataSegment* data) = 0; - virtual void copy(Address dest, - Address src, - Address byteCount, - const RuntimeMemory* srcMemory) = 0; + virtual void + copy(Address dest, Address src, Address byteCount, const RuntimeMemory* srcMemory) = 0; virtual void fill(Address dest, uint8_t value, Address byteCount) = 0; @@ -66,16 +56,14 @@ virtual const std::vector<uint8_t>* getBuffer() const { return nullptr; } - void trap(std::string_view why) const { externalInterface->trap(why); } - protected: - ExternalInterface* externalInterface; const Memory memoryDefinition; }; class RealRuntimeMemory : public RuntimeMemory { public: - RealRuntimeMemory(Memory memory, ExternalInterface* externalInterface); + RealRuntimeMemory(Memory memory); + virtual ~RealRuntimeMemory() = default; Literal load(Address addr,
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 5b76849..531b470 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp
@@ -42,6 +42,7 @@ #include "wasm-interpreter.h" #include "wasm-io.h" #include "wasm-validator.h" +#include "interpreter/exception.h" using namespace wasm; @@ -242,9 +243,8 @@ this->wasm, [this](Name name, Type type) { return makeFuncData(name, type); }); }, - [](Memory memory, ExternalInterface* externalInterface) { - return std::make_unique<CtorEvalRuntimeMemory>(memory, - externalInterface); + [](Memory memory) { + return std::make_unique<CtorEvalRuntimeMemory>(memory); }) {} Flow visitGlobalGet(GlobalGet* curr) { @@ -1117,6 +1117,12 @@ Flow flow; try { flow = instance.visit(curr); + } catch (TrapException&) { + throw FailToEvalException("trap"); + } catch (WasmException& exn) { + std::stringstream ss; + ss << "exception thrown: " << exn; + throw FailToEvalException(ss.str()); } catch (FailToEvalException& fail) { if (!quiet) { if (successes == 0) { @@ -1353,7 +1359,15 @@ // create an instance for evalling EvallingModuleRunner instance( wasm, &interface, interface.instanceInitialized, linkedInstances); - instance.instantiate(); + try { + instance.instantiate(); + } catch (TrapException&) { + throw FailToEvalException("trap"); + } catch (WasmException& exn) { + std::stringstream ss; + ss << "exception thrown: " << exn; + throw FailToEvalException(ss.str()); + } interface.instanceInitialized = true; // go one by one, in order, until we fail // TODO: if we knew priorities, we could reorder?
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 9d56cd3..dfada7c 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h
@@ -3003,7 +3003,7 @@ // ExternalInterface provides embedding-specific functionality like calling // an imported function or accessing memory. // - struct ExternalInterface : RuntimeMemory::ExternalInterface { + struct ExternalInterface { ExternalInterface( std::map<Name, std::shared_ptr<SubType>> linkedInstances = {}) {} virtual ~ExternalInterface() = default; @@ -3035,8 +3035,7 @@ std::unordered_map<Name, RuntimeMemory*> allMemories; using CreateTableFunc = std::unique_ptr<RuntimeTable>(Literal, Table); - using CreateMemoryFunc = std::unique_ptr<RuntimeMemory>(Memory, - ExternalInterface*); + using CreateMemoryFunc = std::unique_ptr<RuntimeMemory>(Memory); ModuleRunnerBase( Module& wasm, @@ -3056,13 +3055,14 @@ [](Literal initial, Table t) -> std::unique_ptr<RuntimeTable> { return std::make_unique<RealRuntimeTable>(initial, t); })), - createMemory(createMemory != nullptr - ? std::move(createMemory) - : static_cast<std::function<CreateMemoryFunc>>( - [externalInterface](Memory m, ExternalInterface* ei) - -> std::unique_ptr<RuntimeMemory> { - return std::make_unique<RealRuntimeMemory>(m, ei); - })) { + createMemory( + createMemory != nullptr + ? std::move(createMemory) + : static_cast<std::function<CreateMemoryFunc>>( + [](Memory m) -> std::unique_ptr<RuntimeMemory> { + return std::make_unique<RealRuntimeMemory>(m); + })) { + // Set up a single shared CurrContinuations for all these linked instances, // reusing one if it exists. std::shared_ptr<ContinuationStore> shared; @@ -3468,8 +3468,8 @@ // parsing/validation checked this already. assert(inserted && "Unexpected repeated memory name"); } else { - auto& runtimeMemory = definedMemories.emplace_back( - createMemory(*memory, externalInterface)); + auto& runtimeMemory = + definedMemories.emplace_back(createMemory(*memory)); [[maybe_unused]] auto [_, inserted] = allMemories.try_emplace(memory->name, runtimeMemory.get()); assert(inserted && "Unexpected repeated memory name");