Source code
Revision control
Copy as Markdown
Other Tools
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#include "jit/Recover.h"
#include "mozilla/Casting.h"
#include "jsmath.h"
#include "builtin/Object.h"
#include "builtin/RegExp.h"
#include "builtin/String.h"
#include "jit/AtomicOperations.h"
#include "jit/Bailouts.h"
#include "jit/CompileInfo.h"
#include "jit/Ion.h"
#include "jit/JitSpewer.h"
#include "jit/JSJitFrameIter.h"
#include "jit/MIR-wasm.h"
#include "jit/MIR.h"
#include "jit/MIRGraph.h"
#include "jit/VMFunctions.h"
#include "js/ScalarType.h"
#include "util/DifferentialTesting.h"
#include "vm/BigIntType.h"
#include "vm/EqualityOperations.h"
#include "vm/Interpreter.h"
#include "vm/Iteration.h"
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/StringType.h"
#include "vm/Watchtower.h"
#include "vm/Interpreter-inl.h"
using namespace js;
using namespace js::jit;
bool MNode::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_CRASH("This instruction is not serializable");
}
void RInstruction::readRecoverData(CompactBufferReader& reader,
RInstructionStorage* raw) {
uint32_t op = reader.readUnsigned();
switch (Opcode(op)) {
#define MATCH_OPCODES_(op) \
case Recover_##op: \
static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
"storage space must be big enough to store R" #op); \
static_assert(alignof(R##op) <= alignof(RInstructionStorage), \
"storage space must be aligned adequate to store R" #op); \
new (raw->addr()) R##op(reader); \
break;
RECOVER_OPCODE_LIST(MATCH_OPCODES_)
#undef MATCH_OPCODES_
case Recover_Invalid:
default:
MOZ_CRASH("Bad decoding of the previous instruction?");
}
}
bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const {
writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
MBasicBlock* bb = block();
bool hasFun = bb->info().hasFunMaybeLazy();
uint32_t nargs = bb->info().nargs();
JSScript* script = bb->info().script();
uint32_t exprStack = stackDepth() - bb->info().ninvoke();
#ifdef DEBUG
// Ensure that all snapshot which are encoded can safely be used for
// bailouts.
uint32_t numIntermediate = NumIntermediateValues(mode());
if (JSContext* cx = GetJitContext()->cx) {
if (!AssertBailoutStackDepth(cx, script, pc(), mode(),
exprStack - numIntermediate)) {
return false;
}
}
#endif
uint32_t formalArgs = CountArgSlots(script, hasFun, nargs);
// Test if we honor the maximum of arguments at all times. This is a sanity
// check and not an algorithm limit. So check might be a bit too loose. +4
// to account for scope chain, return value, this value and maybe
// arguments_object.
MOZ_ASSERT(formalArgs < SNAPSHOT_MAX_NARGS + 4);
#ifdef JS_JITSPEW
uint32_t implicit = StartArgSlot(script);
#endif
uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
JitSpew(JitSpew_IonSnapshots,
"Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
implicit, formalArgs - implicit, script->nfixed(), exprStack);
uint32_t pcOff = script->pcToOffset(pc());
JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, mode %s, nslots %u",
pcOff, ResumeModeToString(mode()), nallocs);
uint32_t pcOffAndMode =
(pcOff << RResumePoint::PCOffsetShift) | uint32_t(mode());
MOZ_RELEASE_ASSERT((pcOffAndMode >> RResumePoint::PCOffsetShift) == pcOff,
"pcOff doesn't fit in pcOffAndMode");
writer.writeUnsigned(pcOffAndMode);
writer.writeUnsigned(nallocs);
return true;
}
RResumePoint::RResumePoint(CompactBufferReader& reader) {
pcOffsetAndMode_ = reader.readUnsigned();
numOperands_ = reader.readUnsigned();
JitSpew(JitSpew_IonSnapshots,
"Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
ResumeModeToString(mode()), numOperands_);
}
bool RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const {
MOZ_CRASH("This instruction is not recoverable.");
}
bool MBitNot::writeRecoverData(CompactBufferWriter& writer) const {
// 64-bit int bitnots exist only when compiling wasm; they exist neither for
// JS nor asm.js. So we don't expect them here.
MOZ_ASSERT(type() != MIRType::Int64);
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot));
return true;
}
RBitNot::RBitNot(CompactBufferReader& reader) {}
bool RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue operand(cx, iter.read());
RootedValue result(cx);
if (!js::BitNot(cx, &operand, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd));
return true;
}
RBitAnd::RBitAnd(CompactBufferReader& reader) {}
bool RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitAnd(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MBitOr::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr));
return true;
}
RBitOr::RBitOr(CompactBufferReader& reader) {}
bool RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitOr(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MBitXor::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor));
return true;
}
RBitXor::RBitXor(CompactBufferReader& reader) {}
bool RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
if (!js::BitXor(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MLsh::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh));
return true;
}
RLsh::RLsh(CompactBufferReader& reader) {}
bool RLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitLsh(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MRsh::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh));
return true;
}
RRsh::RRsh(CompactBufferReader& reader) {}
bool RRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitRsh(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MUrsh::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh));
return true;
}
RUrsh::RUrsh(CompactBufferReader& reader) {}
bool RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
RootedValue result(cx);
if (!js::UrshValues(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32));
MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
writer.writeByte(uint8_t(mode_));
return true;
}
RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader) {
mode_ = reader.readByte();
}
bool RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue operand(cx, iter.read());
int32_t i;
if (!ToInt32(cx, operand, &i)) {
return false;
}
int32_t result;
switch (MSignExtendInt32::Mode(mode_)) {
case MSignExtendInt32::Byte:
result = static_cast<int8_t>(i);
break;
case MSignExtendInt32::Half:
result = static_cast<int16_t>(i);
break;
}
iter.storeInstructionResult(JS::Int32Value(result));
return true;
}
bool MAdd::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));
writer.writeByte(type() == MIRType::Float32);
return true;
}
RAdd::RAdd(CompactBufferReader& reader) {
isFloatOperation_ = reader.readByte();
}
bool RAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::AddValues(cx, &lhs, &rhs, &result)) {
return false;
}
// MIRType::Float32 is a specialization embedding the fact that the result is
// rounded to a Float32.
if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MSub::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));
writer.writeByte(type() == MIRType::Float32);
return true;
}
RSub::RSub(CompactBufferReader& reader) {
isFloatOperation_ = reader.readByte();
}
bool RSub::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::SubValues(cx, &lhs, &rhs, &result)) {
return false;
}
// MIRType::Float32 is a specialization embedding the fact that the result is
// rounded to a Float32.
if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MMul::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));
writer.writeByte(type() == MIRType::Float32);
MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
writer.writeByte(uint8_t(mode_));
return true;
}
RMul::RMul(CompactBufferReader& reader) {
isFloatOperation_ = reader.readByte();
mode_ = reader.readByte();
}
bool RMul::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
if (MMul::Mode(mode_) == MMul::Normal) {
if (!js::MulValues(cx, &lhs, &rhs, &result)) {
return false;
}
// MIRType::Float32 is a specialization embedding the fact that the
// result is rounded to a Float32.
if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
return false;
}
} else {
MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer);
if (!js::math_imul_handle(cx, lhs, rhs, &result)) {
return false;
}
}
iter.storeInstructionResult(result);
return true;
}
bool MDiv::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Div));
writer.writeByte(type() == MIRType::Float32);
return true;
}
RDiv::RDiv(CompactBufferReader& reader) {
isFloatOperation_ = reader.readByte();
}
bool RDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
if (!js::DivValues(cx, &lhs, &rhs, &result)) {
return false;
}
// MIRType::Float32 is a specialization embedding the fact that the result is
// rounded to a Float32.
if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MMod::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));
return true;
}
RMod::RMod(CompactBufferReader& reader) {}
bool RMod::recover(JSContext* cx, SnapshotIterator& iter) const {
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::ModValues(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
}
bool MNot::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Not));
return true;
}
RNot::RNot(CompactBufferReader& reader) {}
bool RNot::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<Value> value(cx);
if (!iter.readMaybeUnpackedBigInt(cx, &value)) {
return false;
}
bool result = !ToBoolean(value);
iter.storeInstructionResult(BooleanValue(result));
return true;
}
bool MBigIntAdd::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd));
return true;
}
RBigIntAdd::RBigIntAdd(CompactBufferReader& reader) {}
bool RBigIntAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::add(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntSub::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub));
return true;
}
RBigIntSub::RBigIntSub(CompactBufferReader& reader) {}
bool RBigIntSub::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::sub(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntMul::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul));
return true;
}
RBigIntMul::RBigIntMul(CompactBufferReader& reader) {}
bool RBigIntMul::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::mul(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntDiv::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv));
return true;
}
RBigIntDiv::RBigIntDiv(CompactBufferReader& reader) {}
bool RBigIntDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
MOZ_ASSERT(!rhs->isZero(),
"division by zero throws and therefore can't be recovered");
BigInt* result = BigInt::div(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntMod::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod));
return true;
}
RBigIntMod::RBigIntMod(CompactBufferReader& reader) {}
bool RBigIntMod::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
MOZ_ASSERT(!rhs->isZero(),
"division by zero throws and therefore can't be recovered");
BigInt* result = BigInt::mod(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntPow::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow));
return true;
}
RBigIntPow::RBigIntPow(CompactBufferReader& reader) {}
bool RBigIntPow::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
MOZ_ASSERT(!rhs->isNegative(),
"negative exponent throws and therefore can't be recovered");
BigInt* result = BigInt::pow(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd));
return true;
}
RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader& reader) {}
bool RBigIntBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::bitAnd(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntBitOr::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr));
return true;
}
RBigIntBitOr::RBigIntBitOr(CompactBufferReader& reader) {}
bool RBigIntBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::bitOr(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntBitXor::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor));
return true;
}
RBigIntBitXor::RBigIntBitXor(CompactBufferReader& reader) {}
bool RBigIntBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::bitXor(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntLsh::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh));
return true;
}
RBigIntLsh::RBigIntLsh(CompactBufferReader& reader) {}
bool RBigIntLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::lsh(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntRsh::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh));
return true;
}
RBigIntRsh::RBigIntRsh(CompactBufferReader& reader) {}
bool RBigIntRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> lhs(cx, iter.readBigInt());
Rooted<BigInt*> rhs(cx, iter.readBigInt());
BigInt* result = BigInt::rsh(cx, lhs, rhs);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntIncrement::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement));
return true;
}
RBigIntIncrement::RBigIntIncrement(CompactBufferReader& reader) {}
bool RBigIntIncrement::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> operand(cx, iter.readBigInt());
BigInt* result = BigInt::inc(cx, operand);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntDecrement::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement));
return true;
}
RBigIntDecrement::RBigIntDecrement(CompactBufferReader& reader) {}
bool RBigIntDecrement::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> operand(cx, iter.readBigInt());
BigInt* result = BigInt::dec(cx, operand);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntNegate::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate));
return true;
}
RBigIntNegate::RBigIntNegate(CompactBufferReader& reader) {}
bool RBigIntNegate::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> operand(cx, iter.readBigInt());
BigInt* result = BigInt::neg(cx, operand);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntBitNot::writeRecoverData(CompactBufferWriter& writer) const {
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot));
return true;
}
RBigIntBitNot::RBigIntBitNot(CompactBufferReader& reader) {}
bool RBigIntBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
Rooted<BigInt*> operand(cx, iter.readBigInt());
BigInt* result = BigInt::bitNot(cx, operand);
if (!result) {
return false;
}
iter.storeInstructionResult(BigIntValue(result));
return true;
}
bool MBigIntToIntPtr::writeRecoverData(CompactBufferWriter& writer) const {