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.h136
1 files changed, 68 insertions, 68 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index e0006f37b..022dd04bc 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -24,6 +24,7 @@
#define wasm_wasm_interpreter_h
#include <limits.h>
+#include <sstream>
#include "support/bits.h"
#include "wasm.h"
@@ -378,13 +379,7 @@ private:
case Clz: return Literal((int32_t)CountLeadingZeroes(v));
case Ctz: return Literal((int32_t)CountTrailingZeroes(v));
case Popcnt: return Literal((int32_t)PopCount(v));
- case ReinterpretInt: {
- float v = value.reinterpretf32();
- if (isnan(v)) {
- return Literal(Literal(value.geti32() | 0x7f800000).reinterpretf32());
- }
- return Literal(value.reinterpretf32());
- }
+ case ReinterpretInt: return value.castToF32();
case ExtendSInt32: return Literal(int64_t(value.geti32()));
case ExtendUInt32: return Literal(uint64_t((uint32_t)value.geti32()));
case ConvertUInt32: return curr->type == f32 ? Literal(float(uint32_t(value.geti32()))) : Literal(double(uint32_t(value.geti32())));
@@ -399,9 +394,7 @@ private:
case Ctz: return Literal((int64_t)CountTrailingZeroes(v));
case Popcnt: return Literal((int64_t)PopCount(v));
case WrapInt64: return Literal(int32_t(value.geti64()));
- case ReinterpretInt: {
- return Literal(value.reinterpretf64());
- }
+ case ReinterpretInt: return value.castToF64();
case ConvertUInt64: return curr->type == f32 ? Literal(float((uint64_t)value.geti64())) : Literal(double((uint64_t)value.geti64()));
case ConvertSInt64: return curr->type == f32 ? Literal(float(value.geti64())) : Literal(double(value.geti64()));
default: abort();
@@ -411,8 +404,9 @@ private:
float v = value.getf32();
float ret;
switch (curr->op) {
- case Neg: ret = -v; break;
- case Abs: ret = std::abs(v); break;
+ // operate on bits directly, to avoid signalling bit being set on a float
+ case Neg: return Literal(value.reinterpreti32() ^ 0x80000000).castToF32(); break;
+ case Abs: return Literal(value.reinterpreti32() & 0x7fffffff).castToF32(); break;
case Ceil: ret = std::ceil(v); break;
case Floor: ret = std::floor(v); break;
case Trunc: ret = std::trunc(v); break;
@@ -430,8 +424,9 @@ private:
double v = value.getf64();
double ret;
switch (curr->op) {
- case Neg: ret = -v; break;
- case Abs: ret = std::abs(v); break;
+ // operate on bits directly, to avoid signalling bit being set on a float
+ case Neg: return Literal(uint64_t((value.reinterpreti64() ^ 0x8000000000000000ULL))).castToF64(); break;
+ case Abs: return Literal(uint64_t(value.reinterpreti64() & 0x7fffffffffffffffULL)).castToF64(); break;
case Ceil: ret = std::ceil(v); break;
case Floor: ret = std::floor(v); break;
case Trunc: ret = std::trunc(v); break;
@@ -459,28 +454,29 @@ private:
assert(left.type == curr->left->type);
assert(right.type == curr->right->type);
if (left.type == i32) {
- int32_t l = left.geti32(), r = right.geti32();
+ uint32_t l = left.geti32(), r = right.geti32();
+ int32_t l_signed = l, r_signed = r;
switch (curr->op) {
case Add: return Literal(l + r);
case Sub: return Literal(l - r);
case Mul: return Literal(l * r);
case DivS: {
- if (r == 0) trap("i32.div_s by 0");
- if (l == INT32_MIN && r == -1) trap("i32.div_s overflow"); // signed division overflow
- return Literal(l / r);
+ if (r_signed == 0) trap("i32.div_s by 0");
+ if (l_signed == INT32_MIN && r_signed == -1) trap("i32.div_s overflow"); // signed division overflow
+ return Literal(l_signed / r_signed);
}
case DivU: {
if (r == 0) trap("i32.div_u by 0");
- return Literal(int32_t(uint32_t(l) / uint32_t(r)));
+ return Literal(l / r);
}
case RemS: {
- if (r == 0) trap("i32.rem_s by 0");
- if (l == INT32_MIN && r == -1) return Literal(int32_t(0));
- return Literal(l % r);
+ if (r_signed == 0) trap("i32.rem_s by 0");
+ if (l_signed == INT32_MIN && r_signed == -1) return Literal(int32_t(0));
+ return Literal(l_signed % r_signed);
}
case RemU: {
if (r == 0) trap("i32.rem_u by 0");
- return Literal(int32_t(uint32_t(l) % uint32_t(r)));
+ return Literal(l % r);
}
case And: return Literal(l & r);
case Or: return Literal(l | r);
@@ -491,47 +487,48 @@ private:
}
case ShrU: {
r = r & 31;
- return Literal(int32_t(uint32_t(l) >> uint32_t(r)));
+ return Literal(l >> r);
}
case ShrS: {
- r = r & 31;
- return Literal(l >> r);
+ r_signed = r_signed & 31;
+ return Literal(l_signed >> r_signed);
}
case Eq: return Literal(l == r);
case Ne: return Literal(l != r);
- case LtS: return Literal(l < r);
- case LtU: return Literal(uint32_t(l) < uint32_t(r));
- case LeS: return Literal(l <= r);
- case LeU: return Literal(uint32_t(l) <= uint32_t(r));
- case GtS: return Literal(l > r);
- case GtU: return Literal(uint32_t(l) > uint32_t(r));
- case GeS: return Literal(l >= r);
- case GeU: return Literal(uint32_t(l) >= uint32_t(r));
+ case LtS: return Literal(l_signed < r_signed);
+ case LtU: return Literal(l < r);
+ case LeS: return Literal(l_signed <= r_signed);
+ case LeU: return Literal(l <= r);
+ case GtS: return Literal(l_signed > r_signed);
+ case GtU: return Literal(l > r);
+ case GeS: return Literal(l_signed >= r_signed);
+ case GeU: return Literal(l >= r);
default: abort();
}
} else if (left.type == i64) {
- int64_t l = left.geti64(), r = right.geti64();
+ uint64_t l = left.geti64(), r = right.geti64();
+ int64_t l_signed = l, r_signed = r;
switch (curr->op) {
case Add: return Literal(l + r);
case Sub: return Literal(l - r);
case Mul: return Literal(l * r);
case DivS: {
- if (r == 0) trap("i64.div_s by 0");
- if (l == LLONG_MIN && r == -1) trap("i64.div_s overflow"); // signed division overflow
- return Literal(l / r);
+ if (r_signed == 0) trap("i64.div_s by 0");
+ if (l_signed == LLONG_MIN && r_signed == -1LL) trap("i64.div_s overflow"); // signed division overflow
+ return Literal(l_signed / r_signed);
}
case DivU: {
if (r == 0) trap("i64.div_u by 0");
- return Literal(int64_t(uint64_t(l) / uint64_t(r)));
+ return Literal(l / r);
}
case RemS: {
- if (r == 0) trap("i64.rem_s by 0");
- if (l == LLONG_MIN && r == -1) return Literal(int64_t(0));
- return Literal(l % r);
+ if (r_signed == 0) trap("i64.rem_s by 0");
+ if (l_signed == LLONG_MIN && r_signed == -1LL) return Literal(int64_t(0));
+ return Literal(l_signed % r_signed);
}
case RemU: {
if (r == 0) trap("i64.rem_u by 0");
- return Literal(int64_t(uint64_t(l) % uint64_t(r)));
+ return Literal(l % r);
}
case And: return Literal(l & r);
case Or: return Literal(l | r);
@@ -542,22 +539,22 @@ private:
}
case ShrU: {
r = r & 63;
- return Literal(int64_t(uint64_t(l) >> uint64_t(r)));
+ return Literal(l >> r);
}
case ShrS: {
- r = r & 63;
- return Literal(l >> r);
+ r_signed = r_signed & 63;
+ return Literal(l_signed >> r_signed);
}
case Eq: return Literal(l == r);
case Ne: return Literal(l != r);
- case LtS: return Literal(l < r);
- case LtU: return Literal(uint64_t(l) < uint64_t(r));
- case LeS: return Literal(l <= r);
- case LeU: return Literal(uint64_t(l) <= uint64_t(r));
- case GtS: return Literal(l > r);
- case GtU: return Literal(uint64_t(l) > uint64_t(r));
- case GeS: return Literal(l >= r);
- case GeU: return Literal(uint64_t(l) >= uint64_t(r));
+ case LtS: return Literal(l_signed < r_signed);
+ case LtU: return Literal(l < r);
+ case LeS: return Literal(l_signed <= r_signed);
+ case LeU: return Literal(l <= r);
+ case GtS: return Literal(l_signed > r_signed);
+ case GtU: return Literal(l > r);
+ case GeS: return Literal(l_signed >= r_signed);
+ case GeU: return Literal(l >= r);
default: abort();
}
} else if (left.type == f32) {
@@ -568,10 +565,8 @@ private:
case Sub: ret = l - r; break;
case Mul: ret = l * r; break;
case Div: ret = l / r; break;
- case CopySign: {
- ret = std::copysign(l, r);
- return Literal(ret);
- }
+ // operate on bits directly, to avoid signalling bit being set on a float
+ case CopySign: return Literal((left.reinterpreti32() & 0x7fffffff) | (right.reinterpreti32() & 0x80000000)).castToF32(); break;
case Min: {
if (l == r && l == 0) ret = 1/l < 0 ? l : r;
else ret = std::min(l, r);
@@ -599,10 +594,8 @@ private:
case Sub: ret = l - r; break;
case Mul: ret = l * r; break;
case Div: ret = l / r; break;
- case CopySign: {
- ret = std::copysign(l, r);
- return Literal(ret);
- }
+ // operate on bits directly, to avoid signalling bit being set on a float
+ case CopySign: return Literal((left.reinterpreti64() & 0x7fffffffffffffffUL) | (right.reinterpreti64() & 0x8000000000000000UL)).castToF64(); break;
case Min: {
if (l == r && l == 0) ret = 1/l < 0 ? l : r;
else ret = std::min(l, r);
@@ -775,14 +768,21 @@ private:
size_t memorySize;
- template<class LS>
- size_t getFinalAddress(LS *curr, Literal ptr) {
+ template <class LS>
+ size_t getFinalAddress(LS* curr, Literal ptr) {
+ auto trapIfGt = [this](size_t lhs, size_t rhs, const char* msg) {
+ if (lhs > rhs) {
+ std::stringstream ss;
+ ss << msg << ": " << lhs << " > " << rhs;
+ externalInterface->trap(ss.str().c_str());
+ }
+ };
uint64_t addr = ptr.type == i32 ? ptr.geti32() : ptr.geti64();
- if (memorySize < curr->offset) externalInterface->trap("offset > memory");
- if (addr > memorySize - curr->offset) externalInterface->trap("final > memory");
+ trapIfGt(curr->offset, memorySize, "offset > memory");
+ trapIfGt(addr, memorySize - curr->offset, "final > memory");
addr += curr->offset;
- if (curr->bytes > memorySize) externalInterface->trap("bytes > memory");
- if (addr > memorySize - curr->bytes) externalInterface->trap("highest > memory");
+ trapIfGt(curr->bytes, memorySize, "bytes > memory");
+ trapIfGt(addr, memorySize - curr->bytes, "highest > memory");
return addr;
}