diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp index 2a66c3e28b19..dc6d62d5a785 100644 --- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -2820,7 +2820,7 @@ class MOZ_STACK_CLASS FunctionValidator MOZ_WARN_UNUSED_RESULT bool writeInt32Lit(int32_t i32) { return encoder().writeExpr(Expr::I32Const) && - encoder().writeVarU32(i32); + encoder().writeVarS32(i32); } MOZ_WARN_UNUSED_RESULT bool writeConstExpr(NumLit lit) { switch (lit.which()) { diff --git a/js/src/asmjs/Wasm.cpp b/js/src/asmjs/Wasm.cpp index b6991425ad01..6863704dbab8 100644 --- a/js/src/asmjs/Wasm.cpp +++ b/js/src/asmjs/Wasm.cpp @@ -247,8 +247,8 @@ DecodeCallIndirect(FunctionDecoder& f, ExprType* type) static bool DecodeConstI32(FunctionDecoder& f, ExprType* type) { - uint32_t _; - if (!f.d().readVarU32(&_)) + int32_t _; + if (!f.d().readVarS32(&_)) return f.fail("unable to read i32.const immediate"); *type = ExprType::I32; @@ -258,8 +258,8 @@ DecodeConstI32(FunctionDecoder& f, ExprType* type) static bool DecodeConstI64(FunctionDecoder& f, ExprType* type) { - uint64_t _; - if (!f.d().readVarU64(&_)) + int64_t _; + if (!f.d().readVarS64(&_)) return f.fail("unable to read i64.const immediate"); *type = ExprType::I64; diff --git a/js/src/asmjs/WasmBinary.h b/js/src/asmjs/WasmBinary.h index 84e83b0609c5..27911c7e64c8 100644 --- a/js/src/asmjs/WasmBinary.h +++ b/js/src/asmjs/WasmBinary.h @@ -342,13 +342,28 @@ class Encoder template MOZ_WARN_UNUSED_RESULT bool writeVarU(UInt i) { do { - uint8_t byte = i & 0x7F; + uint8_t byte = i & 0x7f; i >>= 7; if (i != 0) byte |= 0x80; if (!bytes_.append(byte)) return false; - } while(i != 0); + } while (i != 0); + return true; + } + + template + MOZ_WARN_UNUSED_RESULT bool writeVarS(SInt i) { + bool done; + do { + uint8_t byte = i & 0x7f; + i >>= 7; + done = ((i == 0) && !(byte & 0x40)) || ((i == -1) && (byte & 0x40)); + if (!done) + byte |= 0x80; + if (!bytes_.append(byte)) + return false; + } while (!done); return true; } @@ -428,9 +443,15 @@ class Encoder MOZ_WARN_UNUSED_RESULT bool writeVarU32(uint32_t i) { return writeVarU(i); } + MOZ_WARN_UNUSED_RESULT bool writeVarS32(int32_t i) { + return writeVarS(i); + } MOZ_WARN_UNUSED_RESULT bool writeVarU64(uint64_t i) { return writeVarU(i); } + MOZ_WARN_UNUSED_RESULT bool writeVarS64(int64_t i) { + return writeVarS(i); + } MOZ_WARN_UNUSED_RESULT bool writeExpr(Expr expr) { return writeEnum(expr); } @@ -573,7 +594,36 @@ class Decoder } while (shift != numBitsInSevens); if (!readFixedU8(&byte) || (byte & (unsigned(-1) << remainderBits))) return false; - *out = u | UInt(byte) << numBitsInSevens; + *out = u | (UInt(byte) << numBitsInSevens); + return true; + } + + template + MOZ_WARN_UNUSED_RESULT bool readVarS(SInt* out) { + const unsigned numBits = sizeof(SInt) * CHAR_BIT; + const unsigned remainderBits = numBits % 7; + const unsigned numBitsInSevens = numBits - remainderBits; + SInt s = 0; + uint8_t byte; + unsigned shift = 0; + do { + if (!readFixedU8(&byte)) + return false; + s |= SInt(byte & 0x7f) << shift; + shift += 7; + if (!(byte & 0x80)) { + if (byte & 0x40) + s |= SInt(-1) << shift; + *out = s; + return true; + } + } while (shift < numBitsInSevens); + if (!remainderBits || !readFixedU8(&byte) || (byte & 0x80)) + return false; + uint8_t mask = 0x7f & (-1 << remainderBits); + if ((byte & mask) != ((byte & (1 << (remainderBits - 1))) ? mask : 0)) + return false; + *out = s | SInt(byte) << shift; return true; } @@ -631,9 +681,15 @@ class Decoder MOZ_WARN_UNUSED_RESULT bool readVarU32(uint32_t* out) { return readVarU(out); } + MOZ_WARN_UNUSED_RESULT bool readVarS32(int32_t* out) { + return readVarS(out); + } MOZ_WARN_UNUSED_RESULT bool readVarU64(uint64_t* out) { return readVarU(out); } + MOZ_WARN_UNUSED_RESULT bool readVarS64(int64_t* out) { + return readVarS(out); + } MOZ_WARN_UNUSED_RESULT bool readExpr(Expr* expr) { return readEnum(expr); } @@ -752,9 +808,19 @@ class Decoder uint32_t uncheckedReadVarU32() { return uncheckedReadVarU(); } + int32_t uncheckedReadVarS32() { + int32_t i32; + MOZ_ALWAYS_TRUE(readVarS32(&i32)); + return i32; + } uint64_t uncheckedReadVarU64() { return uncheckedReadVarU(); } + int64_t uncheckedReadVarS64() { + int64_t i64; + MOZ_ALWAYS_TRUE(readVarS64(&i64)); + return i64; + } Expr uncheckedReadExpr() { return uncheckedReadEnum(); } diff --git a/js/src/asmjs/WasmIonCompile.cpp b/js/src/asmjs/WasmIonCompile.cpp index c41eab8eacf6..ae4f6a928f80 100644 --- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -1254,8 +1254,10 @@ class FunctionCompiler /************************************************************ DECODING ***/ uint8_t readU8() { return decoder_.uncheckedReadFixedU8(); } + uint32_t readVarS32() { return decoder_.uncheckedReadVarS32(); } uint32_t readVarU32() { return decoder_.uncheckedReadVarU32(); } uint64_t readVarU64() { return decoder_.uncheckedReadVarU64(); } + uint64_t readVarS64() { return decoder_.uncheckedReadVarS64(); } float readF32() { return decoder_.uncheckedReadFixedF32(); } double readF64() { return decoder_.uncheckedReadFixedF64(); } Expr readExpr() { return decoder_.uncheckedReadExpr(); } @@ -1342,12 +1344,12 @@ EmitLiteral(FunctionCompiler& f, ValType type, MDefinition** def) { switch (type) { case ValType::I32: { - int32_t val = f.readVarU32(); + int32_t val = f.readVarS32(); *def = f.constant(Int32Value(val), MIRType_Int32); return true; } case ValType::I64: { - int64_t val = f.readVarU64(); + int64_t val = f.readVarS64(); *def = f.constant(val); return true; } diff --git a/js/src/asmjs/WasmText.cpp b/js/src/asmjs/WasmText.cpp index 6340f17e52d9..63bfb77a18f3 100644 --- a/js/src/asmjs/WasmText.cpp +++ b/js/src/asmjs/WasmText.cpp @@ -3582,10 +3582,10 @@ EncodeConst(Encoder& e, WasmAstConst& c) switch (c.val().type()) { case ValType::I32: return e.writeExpr(Expr::I32Const) && - e.writeVarU32(c.val().i32()); + e.writeVarS32(c.val().i32()); case ValType::I64: return e.writeExpr(Expr::I64Const) && - e.writeVarU64(c.val().i64()); + e.writeVarS64(c.val().i64()); case ValType::F32: return e.writeExpr(Expr::F32Const) && e.writeFixedF32(c.val().f32());