summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r--src/wasm-interpreter.h164
1 files changed, 150 insertions, 14 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 0b01fb1d3..b3fa3f265 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -32,6 +32,7 @@
#include "wasm.h"
#include "wasm-traversal.h"
+
#ifdef WASM_INTERPRETER_DEBUG
#include "wasm-printing.h"
#endif
@@ -118,7 +119,16 @@ template<typename SubType>
class ExpressionRunner : public Visitor<SubType, Flow> {
public:
Flow visit(Expression *curr) {
- return Visitor<SubType, Flow>::visit(curr);
+ auto ret = Visitor<SubType, Flow>::visit(curr);
+ if (!ret.breaking() && (isConcreteWasmType(curr->type) || isConcreteWasmType(ret.value.type))) {
+#if 1 // def WASM_INTERPRETER_DEBUG
+ if (ret.value.type != curr->type) {
+ std::cerr << "expected " << printWasmType(curr->type) << ", seeing " << printWasmType(ret.value.type) << " from\n" << curr << '\n';
+ }
+#endif
+ assert(ret.value.type == curr->type);
+ }
+ return ret;
}
Flow visitBlock(Block *curr) {
@@ -461,7 +471,7 @@ public:
Flow visitUnreachable(Unreachable *curr) {
NOTE_ENTER("Unreachable");
trap("unreachable");
- return Flow();
+ WASM_UNREACHABLE();
}
Literal truncSFloat(Unary* curr, Literal value) {
@@ -522,7 +532,9 @@ public:
Flow visitCallIndirect(CallIndirect* curr) { WASM_UNREACHABLE(); }
Flow visitGetLocal(GetLocal *curr) { WASM_UNREACHABLE(); }
Flow visitSetLocal(SetLocal *curr) { WASM_UNREACHABLE(); }
- Flow visitGetGlobal(GetGlobal *curr) { return Flow(globals[curr->name]); }
+ Flow visitGetGlobal(GetGlobal *curr) {
+ return Flow(globals[curr->name]);
+ }
Flow visitSetGlobal(SetGlobal *curr) { WASM_UNREACHABLE(); }
Flow visitLoad(Load *curr) { WASM_UNREACHABLE(); }
Flow visitStore(Store *curr) { WASM_UNREACHABLE(); }
@@ -563,7 +575,7 @@ public:
switch (load->bytes) {
case 1: return load->signed_ ? Literal((int32_t)load8s(addr)) : Literal((int32_t)load8u(addr));
case 2: return load->signed_ ? Literal((int32_t)load16s(addr)) : Literal((int32_t)load16u(addr));
- case 4: return load->signed_ ? Literal((int32_t)load32s(addr)) : Literal((int32_t)load32u(addr));
+ case 4: return Literal((int32_t)load32s(addr));
default: WASM_UNREACHABLE();
}
break;
@@ -573,7 +585,7 @@ public:
case 1: return load->signed_ ? Literal((int64_t)load8s(addr)) : Literal((int64_t)load8u(addr));
case 2: return load->signed_ ? Literal((int64_t)load16s(addr)) : Literal((int64_t)load16u(addr));
case 4: return load->signed_ ? Literal((int64_t)load32s(addr)) : Literal((int64_t)load32u(addr));
- case 8: return load->signed_ ? Literal((int64_t)load64s(addr)) : Literal((int64_t)load64u(addr));
+ case 8: return Literal((int64_t)load64s(addr));
default: WASM_UNREACHABLE();
}
break;
@@ -810,8 +822,8 @@ public:
NOTE_ENTER("GetGlobal");
auto name = curr->name;
NOTE_EVAL1(name);
- NOTE_EVAL1(instance.globals[name]);
assert(instance.globals.find(name) != instance.globals.end());
+ NOTE_EVAL1(instance.globals[name]);
return instance.globals[name];
}
Flow visitSetGlobal(SetGlobal *curr) {
@@ -849,6 +861,85 @@ public:
return Flow();
}
+ Flow visitAtomicRMW(AtomicRMW *curr) {
+ NOTE_ENTER("AtomicRMW");
+ Flow ptr = this->visit(curr->ptr);
+ if (ptr.breaking()) return ptr;
+ auto value = this->visit(curr->value);
+ if (value.breaking()) return value;
+ NOTE_EVAL1(ptr);
+ auto addr = instance.getFinalAddress(curr, ptr.value);
+ NOTE_EVAL1(addr);
+ NOTE_EVAL1(value);
+ auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type);
+ NOTE_EVAL1(loaded);
+ auto computed = value.value;
+ switch (curr->op) {
+ case Add: computed = computed.add(value.value); break;
+ case Sub: computed = computed.sub(value.value); break;
+ case And: computed = computed.and_(value.value); break;
+ case Or: computed = computed.or_(value.value); break;
+ case Xor: computed = computed.xor_(value.value); break;
+ case Xchg: computed = value.value; break;
+ default: WASM_UNREACHABLE();
+ }
+ instance.doAtomicStore(addr, curr->bytes, computed);
+ return loaded;
+ }
+ Flow visitAtomicCmpxchg(AtomicCmpxchg *curr) {
+ NOTE_ENTER("AtomicCmpxchg");
+ Flow ptr = this->visit(curr->ptr);
+ if (ptr.breaking()) return ptr;
+ NOTE_EVAL1(ptr);
+ auto expected = this->visit(curr->expected);
+ if (expected.breaking()) return expected;
+ auto replacement = this->visit(curr->replacement);
+ if (replacement.breaking()) return replacement;
+ auto addr = instance.getFinalAddress(curr, ptr.value);
+ NOTE_EVAL1(addr);
+ NOTE_EVAL1(expected);
+ NOTE_EVAL1(replacement);
+ auto loaded = instance.doAtomicLoad(addr, curr->bytes, curr->type);
+ NOTE_EVAL1(loaded);
+ if (loaded == expected.value) {
+ instance.doAtomicStore(addr, curr->bytes, replacement.value);
+ }
+ return loaded;
+ }
+ Flow visitAtomicWait(AtomicWait *curr) {
+ NOTE_ENTER("AtomicWait");
+ Flow ptr = this->visit(curr->ptr);
+ if (ptr.breaking()) return ptr;
+ NOTE_EVAL1(ptr);
+ auto expected = this->visit(curr->expected);
+ NOTE_EVAL1(expected);
+ if (expected.breaking()) return expected;
+ auto timeout = this->visit(curr->timeout);
+ NOTE_EVAL1(timeout);
+ if (timeout.breaking()) return timeout;
+ auto bytes = getWasmTypeSize(curr->expectedType);
+ auto addr = instance.getFinalAddress(ptr.value, bytes);
+ auto loaded = instance.doAtomicLoad(addr, bytes, curr->expectedType);
+ NOTE_EVAL1(loaded);
+ if (loaded != expected.value) {
+ return Literal(int32_t(1)); // not equal
+ }
+ // TODO: add threads support!
+ // for now, just assume we are woken up
+ return Literal(int32_t(0)); // woken up
+ }
+ Flow visitAtomicWake(AtomicWake *curr) {
+ NOTE_ENTER("AtomicWake");
+ Flow ptr = this->visit(curr->ptr);
+ if (ptr.breaking()) return ptr;
+ NOTE_EVAL1(ptr);
+ auto count = this->visit(curr->wakeCount);
+ NOTE_EVAL1(count);
+ if (count.breaking()) return count;
+ // TODO: add threads support!
+ return Literal(int32_t(0)); // none woken up
+ }
+
Flow visitHost(Host *curr) {
NOTE_ENTER("Host");
switch (curr->op) {
@@ -922,25 +1013,70 @@ protected:
Address memorySize; // in pages
+ void trapIfGt(uint64_t lhs, uint64_t rhs, const char* msg) {
+ if (lhs > rhs) {
+ std::stringstream ss;
+ ss << msg << ": " << lhs << " > " << rhs;
+ externalInterface->trap(ss.str().c_str());
+ }
+ }
+
template <class LS>
Address getFinalAddress(LS* curr, Literal ptr) {
- auto trapIfGt = [this](uint64_t lhs, uint64_t rhs, const char* msg) {
- if (lhs > rhs) {
- std::stringstream ss;
- ss << msg << ": " << lhs << " > " << rhs;
- externalInterface->trap(ss.str().c_str());
- }
- };
Address memorySizeBytes = memorySize * Memory::kPageSize;
uint64_t addr = ptr.type == i32 ? ptr.geti32() : ptr.geti64();
trapIfGt(curr->offset, memorySizeBytes, "offset > memory");
trapIfGt(addr, memorySizeBytes - curr->offset, "final > memory");
addr += curr->offset;
trapIfGt(curr->bytes, memorySizeBytes, "bytes > memory");
- trapIfGt(addr, memorySizeBytes - curr->bytes, "highest > memory");
+ checkLoadAddress(addr, curr->bytes);
return addr;
}
+ Address getFinalAddress(Literal ptr, Index bytes) {
+ Address memorySizeBytes = memorySize * Memory::kPageSize;
+ uint64_t addr = ptr.type == i32 ? ptr.geti32() : ptr.geti64();
+ trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
+ return addr;
+ }
+
+ void checkLoadAddress(Address addr, Index bytes) {
+ Address memorySizeBytes = memorySize * Memory::kPageSize;
+ trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
+ }
+
+ Literal doAtomicLoad(Address addr, Index bytes, WasmType type) {
+ checkLoadAddress(addr, bytes);
+ Const ptr;
+ ptr.value = Literal(int32_t(addr));
+ ptr.type = i32;
+ Load load;
+ load.bytes = bytes;
+ load.signed_ = true;
+ load.align = bytes;
+ load.isAtomic = true; // understatement
+ load.ptr = &ptr;
+ load.type = type;
+ return externalInterface->load(&load, addr);
+ }
+
+ void doAtomicStore(Address addr, Index bytes, Literal toStore) {
+ Const ptr;
+ ptr.value = Literal(int32_t(addr));
+ ptr.type = i32;
+ Const value;
+ value.value = toStore;
+ value.type = toStore.type;
+ Store store;
+ store.bytes = bytes;
+ store.align = bytes;
+ store.isAtomic = true; // understatement
+ store.ptr = &ptr;
+ store.value = &value;
+ store.valueType = value.type;
+ return externalInterface->store(&store, addr, toStore);
+ }
+
ExternalInterface* externalInterface;
};