diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-04-05 09:49:37 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2016-04-05 09:49:37 -0700 |
commit | 155223a2a0dd222817881dab85fa11166cc5bbb3 (patch) | |
tree | 7f10e15b941474c2b23c741e20ee2657c54026ca /src/shell-interface.h | |
parent | b243bf42bf89bee18ece60fb0607cf1fb70ce702 (diff) | |
parent | ea448f35ada45647c200019cc34b4315cb16cdd9 (diff) | |
download | binaryen-155223a2a0dd222817881dab85fa11166cc5bbb3.tar.gz binaryen-155223a2a0dd222817881dab85fa11166cc5bbb3.tar.bz2 binaryen-155223a2a0dd222817881dab85fa11166cc5bbb3.zip |
Merge pull request #312 from WebAssembly/webidl
WebIDL bindings
Diffstat (limited to 'src/shell-interface.h')
-rw-r--r-- | src/shell-interface.h | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/shell-interface.h b/src/shell-interface.h new file mode 100644 index 000000000..daaf23501 --- /dev/null +++ b/src/shell-interface.h @@ -0,0 +1,180 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Implementation of the shell interpreter execution environment +// + +#include "shared-constants.h" +#include "wasm.h" +#include "wasm-interpreter.h" + +namespace wasm { + +struct ExitException {}; +struct TrapException {}; +struct ParseException {}; + +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 { + 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 { + 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(); + } +}; + +} + |