summaryrefslogtreecommitdiff
path: root/src/binaryen-shell.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-04-05 09:49:37 -0700
committerAlon Zakai <alonzakai@gmail.com>2016-04-05 09:49:37 -0700
commit155223a2a0dd222817881dab85fa11166cc5bbb3 (patch)
tree7f10e15b941474c2b23c741e20ee2657c54026ca /src/binaryen-shell.cpp
parentb243bf42bf89bee18ece60fb0607cf1fb70ce702 (diff)
parentea448f35ada45647c200019cc34b4315cb16cdd9 (diff)
downloadbinaryen-155223a2a0dd222817881dab85fa11166cc5bbb3.tar.gz
binaryen-155223a2a0dd222817881dab85fa11166cc5bbb3.tar.bz2
binaryen-155223a2a0dd222817881dab85fa11166cc5bbb3.zip
Merge pull request #312 from WebAssembly/webidl
WebIDL bindings
Diffstat (limited to 'src/binaryen-shell.cpp')
-rw-r--r--src/binaryen-shell.cpp169
1 files changed, 2 insertions, 167 deletions
diff --git a/src/binaryen-shell.cpp b/src/binaryen-shell.cpp
index 8fc067562..72fad992b 100644
--- a/src/binaryen-shell.cpp
+++ b/src/binaryen-shell.cpp
@@ -23,6 +23,7 @@
#include <memory>
#include "pass.h"
+#include "shell-interface.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-interpreter.h"
@@ -37,172 +38,6 @@ using namespace wasm;
MixedArena globalAllocator;
-IString ASSERT_RETURN("assert_return"),
- ASSERT_TRAP("assert_trap"),
- ASSERT_INVALID("assert_invalid"),
- SPECTEST("spectest"),
- PRINT("print"),
- INVOKE("invoke"),
- EXIT("exit");
-
-struct ExitException {};
-struct TrapException {};
-struct ParseException {};
-
-//
-// Implementation of the shell interpreter execution environment
-//
-
-struct ShellExternalInterface : ModuleInstance::ExternalInterface {
- // The underlying memory can be accessed through unaligned pointers which
- // isn't well-behaved in C++. WebAssembly nonetheless expects it to behave
- // properly. Avoid emitting unaligned load/store by checking for alignment
- // explicitly, and performing memcpy if unaligned.
- //
- // The allocated memory tries to have the same alignment as the memory being
- // simulated.
- class Memory {
- // Use char because it doesn't run afoul of aliasing rules.
- std::vector<char> memory;
- template <typename T>
- static bool aligned(const char* address) {
- static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
- return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
- }
- Memory(Memory&) = delete;
- Memory& operator=(const Memory&) = delete;
-
- public:
- Memory() {}
- void resize(size_t newSize) {
- // Ensure the smallest allocation is large enough that most allocators
- // will provide page-aligned storage. This hopefully allows the
- // interpreter's memory to be as aligned as the memory being simulated,
- // ensuring that the performance doesn't needlessly degrade.
- //
- // The code is optimistic this will work until WG21's p0035r0 happens.
- const size_t minSize = 1 << 12;
- size_t oldSize = memory.size();
- memory.resize(std::max(minSize, newSize));
- if (newSize < oldSize && newSize < minSize) {
- std::memset(&memory[newSize], 0, minSize - newSize);
- }
- }
- template <typename T>
- void set(size_t address, T value) {
- if (aligned<T>(&memory[address])) {
- *reinterpret_cast<T*>(&memory[address]) = value;
- } else {
- std::memcpy(&memory[address], &value, sizeof(T));
- }
- }
- template <typename T>
- T get(size_t address) {
- if (aligned<T>(&memory[address])) {
- return *reinterpret_cast<T*>(&memory[address]);
- } else {
- T loaded;
- std::memcpy(&loaded, &memory[address], sizeof(T));
- return loaded;
- }
- }
- } memory;
-
- ShellExternalInterface() : memory() {}
-
- void init(Module& wasm) override {
- memory.resize(wasm.memory.initial * wasm::Memory::kPageSize);
- // apply memory segments
- for (auto segment : wasm.memory.segments) {
- assert(segment.offset + segment.size <= wasm.memory.initial * wasm::Memory::kPageSize);
- for (size_t i = 0; i != segment.size; ++i) {
- memory.set(segment.offset + i, segment.data[i]);
- }
- }
- }
-
- Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override {
- if (import->module == SPECTEST && import->base == PRINT) {
- for (auto argument : arguments) {
- std::cout << argument << '\n';
- }
- return Literal();
- } else if (import->module == ENV && import->base == EXIT) {
- // XXX hack for torture tests
- std::cout << "exit()\n";
- throw ExitException();
- }
- std::cout << "callImport " << import->name.str << "\n";
- abort();
- }
-
- Literal load(Load* load, size_t addr) override {
- // ignore align - assume we are on x86 etc. which does that
- switch (load->type) {
- case i32: {
- switch (load->bytes) {
- case 1: return load->signed_ ? Literal((int32_t)memory.get<int8_t>(addr)) : Literal((int32_t)memory.get<uint8_t>(addr));
- case 2: return load->signed_ ? Literal((int32_t)memory.get<int16_t>(addr)) : Literal((int32_t)memory.get<uint16_t>(addr));
- case 4: return load->signed_ ? Literal((int32_t)memory.get<int32_t>(addr)) : Literal((int32_t)memory.get<uint32_t>(addr));
- default: abort();
- }
- break;
- }
- case i64: {
- switch (load->bytes) {
- case 1: return load->signed_ ? Literal((int64_t)memory.get<int8_t>(addr)) : Literal((int64_t)memory.get<uint8_t>(addr));
- case 2: return load->signed_ ? Literal((int64_t)memory.get<int16_t>(addr)) : Literal((int64_t)memory.get<uint16_t>(addr));
- case 4: return load->signed_ ? Literal((int64_t)memory.get<int32_t>(addr)) : Literal((int64_t)memory.get<uint32_t>(addr));
- case 8: return load->signed_ ? Literal((int64_t)memory.get<int64_t>(addr)) : Literal((int64_t)memory.get<uint64_t>(addr));
- default: abort();
- }
- break;
- }
- case f32: return Literal(memory.get<float>(addr));
- case f64: return Literal(memory.get<double>(addr));
- default: abort();
- }
- }
-
- void store(Store* store, size_t addr, Literal value) override {
- // ignore align - assume we are on x86 etc. which does that
- switch (store->type) {
- case i32: {
- switch (store->bytes) {
- case 1: memory.set<int8_t>(addr, value.geti32()); break;
- case 2: memory.set<int16_t>(addr, value.geti32()); break;
- case 4: memory.set<int32_t>(addr, value.geti32()); break;
- default: abort();
- }
- break;
- }
- case i64: {
- switch (store->bytes) {
- case 1: memory.set<int8_t>(addr, (int8_t)value.geti64()); break;
- case 2: memory.set<int16_t>(addr, (int16_t)value.geti64()); break;
- case 4: memory.set<int32_t>(addr, (int32_t)value.geti64()); break;
- case 8: memory.set<int64_t>(addr, value.geti64()); break;
- default: abort();
- }
- break;
- }
- // write floats carefully, ensuring all bits reach memory
- case f32: memory.set<int32_t>(addr, value.reinterpreti32()); break;
- case f64: memory.set<int64_t>(addr, value.reinterpreti64()); break;
- default: abort();
- }
- }
-
- void growMemory(size_t /*oldSize*/, size_t newSize) override {
- memory.resize(newSize);
- }
-
- void trap(const char* why) override {
- std::cerr << "[trap " << why << "]\n";
- throw TrapException();
- }
-};
-
//
// An invocation into a module
//
@@ -285,7 +120,7 @@ static void run_asserts(size_t* i, bool* checked, AllocatingModule* wasm,
new SExpressionWasmBuilder(wasm, *curr[1], [&]() {
invalid = true;
throw ParseException();
- })
+ }, false)
);
} catch (const ParseException&) {
invalid = true;