diff options
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r-- | src/wasm-interpreter.h | 136 |
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; } |