tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Recover.cpp (75611B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "jit/Recover.h"
      8 
      9 #include "mozilla/Casting.h"
     10 
     11 #include "jsmath.h"
     12 
     13 #include "builtin/Object.h"
     14 #include "builtin/String.h"
     15 #include "jit/AtomicOperations.h"
     16 #include "jit/Bailouts.h"
     17 #include "jit/CompileInfo.h"
     18 #include "jit/Ion.h"
     19 #include "jit/JitSpewer.h"
     20 #include "jit/JSJitFrameIter.h"
     21 #include "jit/MIR-wasm.h"
     22 #include "jit/MIR.h"
     23 #include "jit/MIRGraph.h"
     24 #include "jit/VMFunctions.h"
     25 #include "js/ScalarType.h"
     26 #include "util/DifferentialTesting.h"
     27 #include "vm/BigIntType.h"
     28 #include "vm/EqualityOperations.h"
     29 #include "vm/Interpreter.h"
     30 #include "vm/Iteration.h"
     31 #include "vm/JSContext.h"
     32 #include "vm/JSObject.h"
     33 #include "vm/PlainObject.h"  // js::PlainObject
     34 #include "vm/StringType.h"
     35 #include "vm/Watchtower.h"
     36 
     37 #include "vm/Interpreter-inl.h"
     38 
     39 using namespace js;
     40 using namespace js::jit;
     41 
     42 bool MNode::writeRecoverData(CompactBufferWriter& writer) const {
     43  MOZ_CRASH("This instruction is not serializable");
     44 }
     45 
     46 void RInstruction::readRecoverData(CompactBufferReader& reader,
     47                                   RInstructionStorage* raw) {
     48  uint32_t op = reader.readUnsigned();
     49  switch (Opcode(op)) {
     50 #define MATCH_OPCODES_(op)                                                  \
     51  case Recover_##op:                                                        \
     52    static_assert(sizeof(R##op) <= sizeof(RInstructionStorage),             \
     53                  "storage space must be big enough to store R" #op);       \
     54    static_assert(alignof(R##op) <= alignof(RInstructionStorage),           \
     55                  "storage space must be aligned adequate to store R" #op); \
     56    new (raw->addr()) R##op(reader);                                        \
     57    break;
     58 
     59    RECOVER_OPCODE_LIST(MATCH_OPCODES_)
     60 #undef MATCH_OPCODES_
     61 
     62    case Recover_Invalid:
     63    default:
     64      MOZ_CRASH("Bad decoding of the previous instruction?");
     65  }
     66 }
     67 
     68 bool MResumePoint::writeRecoverData(CompactBufferWriter& writer) const {
     69  writer.writeUnsigned(uint32_t(RInstruction::Recover_ResumePoint));
     70 
     71  MBasicBlock* bb = block();
     72  bool hasFun = bb->info().hasFunMaybeLazy();
     73  uint32_t nargs = bb->info().nargs();
     74  JSScript* script = bb->info().script();
     75  uint32_t exprStack = stackDepth() - bb->info().ninvoke();
     76 
     77 #ifdef DEBUG
     78  // Ensure that all snapshot which are encoded can safely be used for
     79  // bailouts.
     80  uint32_t numIntermediate = NumIntermediateValues(mode());
     81  if (JSContext* cx = GetJitContext()->cx) {
     82    if (!AssertBailoutStackDepth(cx, script, pc(), mode(),
     83                                 exprStack - numIntermediate)) {
     84      return false;
     85    }
     86  }
     87 #endif
     88 
     89  uint32_t formalArgs = CountArgSlots(script, hasFun, nargs);
     90 
     91  // Test if we honor the maximum of arguments at all times.  This is a sanity
     92  // check and not an algorithm limit. So check might be a bit too loose.  +4
     93  // to account for scope chain, return value, this value and maybe
     94  // arguments_object.
     95  MOZ_ASSERT(formalArgs < SNAPSHOT_MAX_NARGS + 4);
     96 
     97 #ifdef JS_JITSPEW
     98  uint32_t implicit = StartArgSlot(script);
     99 #endif
    100  uint32_t nallocs = formalArgs + script->nfixed() + exprStack;
    101 
    102  JitSpew(JitSpew_IonSnapshots,
    103          "Starting frame; implicit %u, formals %u, fixed %zu, exprs %u",
    104          implicit, formalArgs - implicit, script->nfixed(), exprStack);
    105 
    106  uint32_t pcOff = script->pcToOffset(pc());
    107  JitSpew(JitSpew_IonSnapshots, "Writing pc offset %u, mode %s, nslots %u",
    108          pcOff, ResumeModeToString(mode()), nallocs);
    109 
    110  uint32_t pcOffAndMode =
    111      (pcOff << RResumePoint::PCOffsetShift) | uint32_t(mode());
    112  MOZ_RELEASE_ASSERT((pcOffAndMode >> RResumePoint::PCOffsetShift) == pcOff,
    113                     "pcOff doesn't fit in pcOffAndMode");
    114  writer.writeUnsigned(pcOffAndMode);
    115 
    116  writer.writeUnsigned(nallocs);
    117  return true;
    118 }
    119 
    120 RResumePoint::RResumePoint(CompactBufferReader& reader) {
    121  pcOffsetAndMode_ = reader.readUnsigned();
    122  numOperands_ = reader.readUnsigned();
    123  JitSpew(JitSpew_IonSnapshots,
    124          "Read RResumePoint (pc offset %u, mode %s, nslots %u)", pcOffset(),
    125          ResumeModeToString(mode()), numOperands_);
    126 }
    127 
    128 bool RResumePoint::recover(JSContext* cx, SnapshotIterator& iter) const {
    129  MOZ_CRASH("This instruction is not recoverable.");
    130 }
    131 
    132 bool MBitNot::writeRecoverData(CompactBufferWriter& writer) const {
    133  // 64-bit int bitnots exist only when compiling wasm; they exist neither for
    134  // JS nor asm.js.  So we don't expect them here.
    135  MOZ_ASSERT(type() != MIRType::Int64);
    136  MOZ_ASSERT(canRecoverOnBailout());
    137  writer.writeUnsigned(uint32_t(RInstruction::Recover_BitNot));
    138  return true;
    139 }
    140 
    141 RBitNot::RBitNot(CompactBufferReader& reader) {}
    142 
    143 bool RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
    144  RootedValue operand(cx, iter.read());
    145  RootedValue result(cx);
    146 
    147  if (!js::BitNot(cx, &operand, &result)) {
    148    return false;
    149  }
    150 
    151  iter.storeInstructionResult(result);
    152  return true;
    153 }
    154 
    155 bool MBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
    156  MOZ_ASSERT(canRecoverOnBailout());
    157  writer.writeUnsigned(uint32_t(RInstruction::Recover_BitAnd));
    158  return true;
    159 }
    160 
    161 RBitAnd::RBitAnd(CompactBufferReader& reader) {}
    162 
    163 bool RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
    164  RootedValue lhs(cx, iter.read());
    165  RootedValue rhs(cx, iter.read());
    166  RootedValue result(cx);
    167  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    168 
    169  if (!js::BitAnd(cx, &lhs, &rhs, &result)) {
    170    return false;
    171  }
    172 
    173  iter.storeInstructionResult(result);
    174  return true;
    175 }
    176 
    177 bool MBitOr::writeRecoverData(CompactBufferWriter& writer) const {
    178  MOZ_ASSERT(canRecoverOnBailout());
    179  writer.writeUnsigned(uint32_t(RInstruction::Recover_BitOr));
    180  return true;
    181 }
    182 
    183 RBitOr::RBitOr(CompactBufferReader& reader) {}
    184 
    185 bool RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
    186  RootedValue lhs(cx, iter.read());
    187  RootedValue rhs(cx, iter.read());
    188  RootedValue result(cx);
    189  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    190 
    191  if (!js::BitOr(cx, &lhs, &rhs, &result)) {
    192    return false;
    193  }
    194 
    195  iter.storeInstructionResult(result);
    196  return true;
    197 }
    198 
    199 bool MBitXor::writeRecoverData(CompactBufferWriter& writer) const {
    200  MOZ_ASSERT(canRecoverOnBailout());
    201  writer.writeUnsigned(uint32_t(RInstruction::Recover_BitXor));
    202  return true;
    203 }
    204 
    205 RBitXor::RBitXor(CompactBufferReader& reader) {}
    206 
    207 bool RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
    208  RootedValue lhs(cx, iter.read());
    209  RootedValue rhs(cx, iter.read());
    210  RootedValue result(cx);
    211 
    212  if (!js::BitXor(cx, &lhs, &rhs, &result)) {
    213    return false;
    214  }
    215 
    216  iter.storeInstructionResult(result);
    217  return true;
    218 }
    219 
    220 bool MLsh::writeRecoverData(CompactBufferWriter& writer) const {
    221  MOZ_ASSERT(canRecoverOnBailout());
    222  writer.writeUnsigned(uint32_t(RInstruction::Recover_Lsh));
    223  return true;
    224 }
    225 
    226 RLsh::RLsh(CompactBufferReader& reader) {}
    227 
    228 bool RLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
    229  RootedValue lhs(cx, iter.read());
    230  RootedValue rhs(cx, iter.read());
    231  RootedValue result(cx);
    232  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    233 
    234  if (!js::BitLsh(cx, &lhs, &rhs, &result)) {
    235    return false;
    236  }
    237 
    238  iter.storeInstructionResult(result);
    239  return true;
    240 }
    241 
    242 bool MRsh::writeRecoverData(CompactBufferWriter& writer) const {
    243  MOZ_ASSERT(canRecoverOnBailout());
    244  writer.writeUnsigned(uint32_t(RInstruction::Recover_Rsh));
    245  return true;
    246 }
    247 
    248 RRsh::RRsh(CompactBufferReader& reader) {}
    249 
    250 bool RRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
    251  RootedValue lhs(cx, iter.read());
    252  RootedValue rhs(cx, iter.read());
    253  RootedValue result(cx);
    254  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    255 
    256  if (!js::BitRsh(cx, &lhs, &rhs, &result)) {
    257    return false;
    258  }
    259 
    260  iter.storeInstructionResult(result);
    261  return true;
    262 }
    263 
    264 bool MUrsh::writeRecoverData(CompactBufferWriter& writer) const {
    265  MOZ_ASSERT(canRecoverOnBailout());
    266  writer.writeUnsigned(uint32_t(RInstruction::Recover_Ursh));
    267  return true;
    268 }
    269 
    270 RUrsh::RUrsh(CompactBufferReader& reader) {}
    271 
    272 bool RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const {
    273  RootedValue lhs(cx, iter.read());
    274  RootedValue rhs(cx, iter.read());
    275  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    276 
    277  RootedValue result(cx);
    278  if (!js::UrshValues(cx, &lhs, &rhs, &result)) {
    279    return false;
    280  }
    281 
    282  iter.storeInstructionResult(result);
    283  return true;
    284 }
    285 
    286 bool MSignExtendInt32::writeRecoverData(CompactBufferWriter& writer) const {
    287  MOZ_ASSERT(canRecoverOnBailout());
    288  writer.writeUnsigned(uint32_t(RInstruction::Recover_SignExtendInt32));
    289  MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
    290  writer.writeByte(uint8_t(mode_));
    291  return true;
    292 }
    293 
    294 RSignExtendInt32::RSignExtendInt32(CompactBufferReader& reader) {
    295  mode_ = reader.readByte();
    296 }
    297 
    298 bool RSignExtendInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
    299  RootedValue operand(cx, iter.read());
    300 
    301  int32_t i;
    302  if (!ToInt32(cx, operand, &i)) {
    303    return false;
    304  }
    305 
    306  int32_t result;
    307  switch (MSignExtendInt32::Mode(mode_)) {
    308    case MSignExtendInt32::Byte:
    309      result = static_cast<int8_t>(i);
    310      break;
    311    case MSignExtendInt32::Half:
    312      result = static_cast<int16_t>(i);
    313      break;
    314  }
    315 
    316  iter.storeInstructionResult(JS::Int32Value(result));
    317  return true;
    318 }
    319 
    320 bool MAdd::writeRecoverData(CompactBufferWriter& writer) const {
    321  MOZ_ASSERT(canRecoverOnBailout());
    322  writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));
    323  writer.writeByte(type() == MIRType::Float32);
    324  return true;
    325 }
    326 
    327 RAdd::RAdd(CompactBufferReader& reader) {
    328  isFloatOperation_ = reader.readByte();
    329 }
    330 
    331 bool RAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
    332  RootedValue lhs(cx, iter.read());
    333  RootedValue rhs(cx, iter.read());
    334  RootedValue result(cx);
    335 
    336  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    337  if (!js::AddValues(cx, &lhs, &rhs, &result)) {
    338    return false;
    339  }
    340 
    341  // MIRType::Float32 is a specialization embedding the fact that the result is
    342  // rounded to a Float32.
    343  if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
    344    return false;
    345  }
    346 
    347  iter.storeInstructionResult(result);
    348  return true;
    349 }
    350 
    351 bool MSub::writeRecoverData(CompactBufferWriter& writer) const {
    352  MOZ_ASSERT(canRecoverOnBailout());
    353  writer.writeUnsigned(uint32_t(RInstruction::Recover_Sub));
    354  writer.writeByte(type() == MIRType::Float32);
    355  return true;
    356 }
    357 
    358 RSub::RSub(CompactBufferReader& reader) {
    359  isFloatOperation_ = reader.readByte();
    360 }
    361 
    362 bool RSub::recover(JSContext* cx, SnapshotIterator& iter) const {
    363  RootedValue lhs(cx, iter.read());
    364  RootedValue rhs(cx, iter.read());
    365  RootedValue result(cx);
    366 
    367  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    368  if (!js::SubValues(cx, &lhs, &rhs, &result)) {
    369    return false;
    370  }
    371 
    372  // MIRType::Float32 is a specialization embedding the fact that the result is
    373  // rounded to a Float32.
    374  if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
    375    return false;
    376  }
    377 
    378  iter.storeInstructionResult(result);
    379  return true;
    380 }
    381 
    382 bool MMul::writeRecoverData(CompactBufferWriter& writer) const {
    383  MOZ_ASSERT(canRecoverOnBailout());
    384  writer.writeUnsigned(uint32_t(RInstruction::Recover_Mul));
    385  writer.writeByte(type() == MIRType::Float32);
    386  MOZ_ASSERT(Mode(uint8_t(mode_)) == mode_);
    387  writer.writeByte(uint8_t(mode_));
    388  return true;
    389 }
    390 
    391 RMul::RMul(CompactBufferReader& reader) {
    392  isFloatOperation_ = reader.readByte();
    393  mode_ = reader.readByte();
    394 }
    395 
    396 bool RMul::recover(JSContext* cx, SnapshotIterator& iter) const {
    397  RootedValue lhs(cx, iter.read());
    398  RootedValue rhs(cx, iter.read());
    399  RootedValue result(cx);
    400 
    401  if (MMul::Mode(mode_) == MMul::Normal) {
    402    if (!js::MulValues(cx, &lhs, &rhs, &result)) {
    403      return false;
    404    }
    405 
    406    // MIRType::Float32 is a specialization embedding the fact that the
    407    // result is rounded to a Float32.
    408    if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
    409      return false;
    410    }
    411  } else {
    412    MOZ_ASSERT(MMul::Mode(mode_) == MMul::Integer);
    413    if (!js::math_imul_handle(cx, lhs, rhs, &result)) {
    414      return false;
    415    }
    416  }
    417 
    418  iter.storeInstructionResult(result);
    419  return true;
    420 }
    421 
    422 bool MDiv::writeRecoverData(CompactBufferWriter& writer) const {
    423  MOZ_ASSERT(canRecoverOnBailout());
    424  writer.writeUnsigned(uint32_t(RInstruction::Recover_Div));
    425  writer.writeByte(type() == MIRType::Float32);
    426  return true;
    427 }
    428 
    429 RDiv::RDiv(CompactBufferReader& reader) {
    430  isFloatOperation_ = reader.readByte();
    431 }
    432 
    433 bool RDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
    434  RootedValue lhs(cx, iter.read());
    435  RootedValue rhs(cx, iter.read());
    436  RootedValue result(cx);
    437 
    438  if (!js::DivValues(cx, &lhs, &rhs, &result)) {
    439    return false;
    440  }
    441 
    442  // MIRType::Float32 is a specialization embedding the fact that the result is
    443  // rounded to a Float32.
    444  if (isFloatOperation_ && !RoundFloat32(cx, result, &result)) {
    445    return false;
    446  }
    447 
    448  iter.storeInstructionResult(result);
    449  return true;
    450 }
    451 
    452 bool MMod::writeRecoverData(CompactBufferWriter& writer) const {
    453  MOZ_ASSERT(canRecoverOnBailout());
    454  writer.writeUnsigned(uint32_t(RInstruction::Recover_Mod));
    455  return true;
    456 }
    457 
    458 RMod::RMod(CompactBufferReader& reader) {}
    459 
    460 bool RMod::recover(JSContext* cx, SnapshotIterator& iter) const {
    461  RootedValue lhs(cx, iter.read());
    462  RootedValue rhs(cx, iter.read());
    463  RootedValue result(cx);
    464 
    465  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
    466  if (!js::ModValues(cx, &lhs, &rhs, &result)) {
    467    return false;
    468  }
    469 
    470  iter.storeInstructionResult(result);
    471  return true;
    472 }
    473 
    474 bool MNot::writeRecoverData(CompactBufferWriter& writer) const {
    475  MOZ_ASSERT(canRecoverOnBailout());
    476  writer.writeUnsigned(uint32_t(RInstruction::Recover_Not));
    477  return true;
    478 }
    479 
    480 RNot::RNot(CompactBufferReader& reader) {}
    481 
    482 bool RNot::recover(JSContext* cx, SnapshotIterator& iter) const {
    483  Rooted<Value> value(cx);
    484  if (!iter.readMaybeUnpackedBigInt(cx, &value)) {
    485    return false;
    486  }
    487 
    488  bool result = !ToBoolean(value);
    489  iter.storeInstructionResult(BooleanValue(result));
    490  return true;
    491 }
    492 
    493 bool MBigIntAdd::writeRecoverData(CompactBufferWriter& writer) const {
    494  MOZ_ASSERT(canRecoverOnBailout());
    495  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAdd));
    496  return true;
    497 }
    498 
    499 RBigIntAdd::RBigIntAdd(CompactBufferReader& reader) {}
    500 
    501 bool RBigIntAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
    502  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    503  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    504 
    505  BigInt* result = BigInt::add(cx, lhs, rhs);
    506  if (!result) {
    507    return false;
    508  }
    509 
    510  iter.storeInstructionResult(BigIntValue(result));
    511  return true;
    512 }
    513 
    514 bool MBigIntSub::writeRecoverData(CompactBufferWriter& writer) const {
    515  MOZ_ASSERT(canRecoverOnBailout());
    516  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntSub));
    517  return true;
    518 }
    519 
    520 RBigIntSub::RBigIntSub(CompactBufferReader& reader) {}
    521 
    522 bool RBigIntSub::recover(JSContext* cx, SnapshotIterator& iter) const {
    523  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    524  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    525 
    526  BigInt* result = BigInt::sub(cx, lhs, rhs);
    527  if (!result) {
    528    return false;
    529  }
    530 
    531  iter.storeInstructionResult(BigIntValue(result));
    532  return true;
    533 }
    534 
    535 bool MBigIntMul::writeRecoverData(CompactBufferWriter& writer) const {
    536  MOZ_ASSERT(canRecoverOnBailout());
    537  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMul));
    538  return true;
    539 }
    540 
    541 RBigIntMul::RBigIntMul(CompactBufferReader& reader) {}
    542 
    543 bool RBigIntMul::recover(JSContext* cx, SnapshotIterator& iter) const {
    544  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    545  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    546 
    547  BigInt* result = BigInt::mul(cx, lhs, rhs);
    548  if (!result) {
    549    return false;
    550  }
    551 
    552  iter.storeInstructionResult(BigIntValue(result));
    553  return true;
    554 }
    555 
    556 bool MBigIntDiv::writeRecoverData(CompactBufferWriter& writer) const {
    557  MOZ_ASSERT(canRecoverOnBailout());
    558  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDiv));
    559  return true;
    560 }
    561 
    562 RBigIntDiv::RBigIntDiv(CompactBufferReader& reader) {}
    563 
    564 bool RBigIntDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
    565  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    566  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    567  MOZ_ASSERT(!rhs->isZero(),
    568             "division by zero throws and therefore can't be recovered");
    569 
    570  BigInt* result = BigInt::div(cx, lhs, rhs);
    571  if (!result) {
    572    return false;
    573  }
    574 
    575  iter.storeInstructionResult(BigIntValue(result));
    576  return true;
    577 }
    578 
    579 bool MBigIntMod::writeRecoverData(CompactBufferWriter& writer) const {
    580  MOZ_ASSERT(canRecoverOnBailout());
    581  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntMod));
    582  return true;
    583 }
    584 
    585 RBigIntMod::RBigIntMod(CompactBufferReader& reader) {}
    586 
    587 bool RBigIntMod::recover(JSContext* cx, SnapshotIterator& iter) const {
    588  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    589  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    590  MOZ_ASSERT(!rhs->isZero(),
    591             "division by zero throws and therefore can't be recovered");
    592 
    593  BigInt* result = BigInt::mod(cx, lhs, rhs);
    594  if (!result) {
    595    return false;
    596  }
    597 
    598  iter.storeInstructionResult(BigIntValue(result));
    599  return true;
    600 }
    601 
    602 bool MBigIntPow::writeRecoverData(CompactBufferWriter& writer) const {
    603  MOZ_ASSERT(canRecoverOnBailout());
    604  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPow));
    605  return true;
    606 }
    607 
    608 RBigIntPow::RBigIntPow(CompactBufferReader& reader) {}
    609 
    610 bool RBigIntPow::recover(JSContext* cx, SnapshotIterator& iter) const {
    611  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    612  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    613  MOZ_ASSERT(!rhs->isNegative(),
    614             "negative exponent throws and therefore can't be recovered");
    615 
    616  BigInt* result = BigInt::pow(cx, lhs, rhs);
    617  if (!result) {
    618    return false;
    619  }
    620 
    621  iter.storeInstructionResult(BigIntValue(result));
    622  return true;
    623 }
    624 
    625 bool MBigIntBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
    626  MOZ_ASSERT(canRecoverOnBailout());
    627  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitAnd));
    628  return true;
    629 }
    630 
    631 RBigIntBitAnd::RBigIntBitAnd(CompactBufferReader& reader) {}
    632 
    633 bool RBigIntBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
    634  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    635  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    636 
    637  BigInt* result = BigInt::bitAnd(cx, lhs, rhs);
    638  if (!result) {
    639    return false;
    640  }
    641 
    642  iter.storeInstructionResult(BigIntValue(result));
    643  return true;
    644 }
    645 
    646 bool MBigIntBitOr::writeRecoverData(CompactBufferWriter& writer) const {
    647  MOZ_ASSERT(canRecoverOnBailout());
    648  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitOr));
    649  return true;
    650 }
    651 
    652 RBigIntBitOr::RBigIntBitOr(CompactBufferReader& reader) {}
    653 
    654 bool RBigIntBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
    655  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    656  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    657 
    658  BigInt* result = BigInt::bitOr(cx, lhs, rhs);
    659  if (!result) {
    660    return false;
    661  }
    662 
    663  iter.storeInstructionResult(BigIntValue(result));
    664  return true;
    665 }
    666 
    667 bool MBigIntBitXor::writeRecoverData(CompactBufferWriter& writer) const {
    668  MOZ_ASSERT(canRecoverOnBailout());
    669  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitXor));
    670  return true;
    671 }
    672 
    673 RBigIntBitXor::RBigIntBitXor(CompactBufferReader& reader) {}
    674 
    675 bool RBigIntBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
    676  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    677  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    678 
    679  BigInt* result = BigInt::bitXor(cx, lhs, rhs);
    680  if (!result) {
    681    return false;
    682  }
    683 
    684  iter.storeInstructionResult(BigIntValue(result));
    685  return true;
    686 }
    687 
    688 bool MBigIntLsh::writeRecoverData(CompactBufferWriter& writer) const {
    689  MOZ_ASSERT(canRecoverOnBailout());
    690  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntLsh));
    691  return true;
    692 }
    693 
    694 RBigIntLsh::RBigIntLsh(CompactBufferReader& reader) {}
    695 
    696 bool RBigIntLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
    697  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    698  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    699 
    700  BigInt* result = BigInt::lsh(cx, lhs, rhs);
    701  if (!result) {
    702    return false;
    703  }
    704 
    705  iter.storeInstructionResult(BigIntValue(result));
    706  return true;
    707 }
    708 
    709 bool MBigIntRsh::writeRecoverData(CompactBufferWriter& writer) const {
    710  MOZ_ASSERT(canRecoverOnBailout());
    711  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntRsh));
    712  return true;
    713 }
    714 
    715 RBigIntRsh::RBigIntRsh(CompactBufferReader& reader) {}
    716 
    717 bool RBigIntRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
    718  Rooted<BigInt*> lhs(cx, iter.readBigInt());
    719  Rooted<BigInt*> rhs(cx, iter.readBigInt());
    720 
    721  BigInt* result = BigInt::rsh(cx, lhs, rhs);
    722  if (!result) {
    723    return false;
    724  }
    725 
    726  iter.storeInstructionResult(BigIntValue(result));
    727  return true;
    728 }
    729 
    730 bool MBigIntIncrement::writeRecoverData(CompactBufferWriter& writer) const {
    731  MOZ_ASSERT(canRecoverOnBailout());
    732  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntIncrement));
    733  return true;
    734 }
    735 
    736 RBigIntIncrement::RBigIntIncrement(CompactBufferReader& reader) {}
    737 
    738 bool RBigIntIncrement::recover(JSContext* cx, SnapshotIterator& iter) const {
    739  Rooted<BigInt*> operand(cx, iter.readBigInt());
    740 
    741  BigInt* result = BigInt::inc(cx, operand);
    742  if (!result) {
    743    return false;
    744  }
    745 
    746  iter.storeInstructionResult(BigIntValue(result));
    747  return true;
    748 }
    749 
    750 bool MBigIntDecrement::writeRecoverData(CompactBufferWriter& writer) const {
    751  MOZ_ASSERT(canRecoverOnBailout());
    752  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntDecrement));
    753  return true;
    754 }
    755 
    756 RBigIntDecrement::RBigIntDecrement(CompactBufferReader& reader) {}
    757 
    758 bool RBigIntDecrement::recover(JSContext* cx, SnapshotIterator& iter) const {
    759  Rooted<BigInt*> operand(cx, iter.readBigInt());
    760 
    761  BigInt* result = BigInt::dec(cx, operand);
    762  if (!result) {
    763    return false;
    764  }
    765 
    766  iter.storeInstructionResult(BigIntValue(result));
    767  return true;
    768 }
    769 
    770 bool MBigIntNegate::writeRecoverData(CompactBufferWriter& writer) const {
    771  MOZ_ASSERT(canRecoverOnBailout());
    772  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntNegate));
    773  return true;
    774 }
    775 
    776 RBigIntNegate::RBigIntNegate(CompactBufferReader& reader) {}
    777 
    778 bool RBigIntNegate::recover(JSContext* cx, SnapshotIterator& iter) const {
    779  Rooted<BigInt*> operand(cx, iter.readBigInt());
    780 
    781  BigInt* result = BigInt::neg(cx, operand);
    782  if (!result) {
    783    return false;
    784  }
    785 
    786  iter.storeInstructionResult(BigIntValue(result));
    787  return true;
    788 }
    789 
    790 bool MBigIntBitNot::writeRecoverData(CompactBufferWriter& writer) const {
    791  MOZ_ASSERT(canRecoverOnBailout());
    792  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntBitNot));
    793  return true;
    794 }
    795 
    796 RBigIntBitNot::RBigIntBitNot(CompactBufferReader& reader) {}
    797 
    798 bool RBigIntBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
    799  Rooted<BigInt*> operand(cx, iter.readBigInt());
    800 
    801  BigInt* result = BigInt::bitNot(cx, operand);
    802  if (!result) {
    803    return false;
    804  }
    805 
    806  iter.storeInstructionResult(BigIntValue(result));
    807  return true;
    808 }
    809 
    810 bool MBigIntToIntPtr::writeRecoverData(CompactBufferWriter& writer) const {
    811  MOZ_ASSERT(canRecoverOnBailout());
    812  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntToIntPtr));
    813  return true;
    814 }
    815 
    816 RBigIntToIntPtr::RBigIntToIntPtr(CompactBufferReader& reader) {}
    817 
    818 bool RBigIntToIntPtr::recover(JSContext* cx, SnapshotIterator& iter) const {
    819  Value input = iter.read();
    820  MOZ_ASSERT(input.isBigInt());
    821 
    822  iter.storeInstructionResult(input);
    823  return true;
    824 }
    825 
    826 bool MIntPtrToBigInt::writeRecoverData(CompactBufferWriter& writer) const {
    827  MOZ_ASSERT(canRecoverOnBailout());
    828  writer.writeUnsigned(uint32_t(RInstruction::Recover_IntPtrToBigInt));
    829  return true;
    830 }
    831 
    832 RIntPtrToBigInt::RIntPtrToBigInt(CompactBufferReader& reader) {}
    833 
    834 bool RIntPtrToBigInt::recover(JSContext* cx, SnapshotIterator& iter) const {
    835  BigInt* input = iter.readBigInt(cx);
    836  if (!input) {
    837    return false;
    838  }
    839 
    840  iter.storeInstructionResult(JS::BigIntValue(input));
    841  return true;
    842 }
    843 
    844 bool MBigIntPtrAdd::writeRecoverData(CompactBufferWriter& writer) const {
    845  MOZ_ASSERT(canRecoverOnBailout());
    846  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrAdd));
    847  return true;
    848 }
    849 
    850 RBigIntPtrAdd::RBigIntPtrAdd(CompactBufferReader& reader) {}
    851 
    852 bool RBigIntPtrAdd::recover(JSContext* cx, SnapshotIterator& iter) const {
    853  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
    854  if (!lhs) {
    855    return false;
    856  }
    857 
    858  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
    859  if (!rhs) {
    860    return false;
    861  }
    862 
    863  BigInt* result = BigInt::add(cx, lhs, rhs);
    864  if (!result) {
    865    return false;
    866  }
    867 
    868  iter.storeInstructionResult(JS::BigIntValue(result));
    869  return true;
    870 }
    871 
    872 bool MBigIntPtrSub::writeRecoverData(CompactBufferWriter& writer) const {
    873  MOZ_ASSERT(canRecoverOnBailout());
    874  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrSub));
    875  return true;
    876 }
    877 
    878 RBigIntPtrSub::RBigIntPtrSub(CompactBufferReader& reader) {}
    879 
    880 bool RBigIntPtrSub::recover(JSContext* cx, SnapshotIterator& iter) const {
    881  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
    882  if (!lhs) {
    883    return false;
    884  }
    885 
    886  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
    887  if (!rhs) {
    888    return false;
    889  }
    890 
    891  BigInt* result = BigInt::sub(cx, lhs, rhs);
    892  if (!result) {
    893    return false;
    894  }
    895 
    896  iter.storeInstructionResult(JS::BigIntValue(result));
    897  return true;
    898 }
    899 
    900 bool MBigIntPtrMul::writeRecoverData(CompactBufferWriter& writer) const {
    901  MOZ_ASSERT(canRecoverOnBailout());
    902  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrMul));
    903  return true;
    904 }
    905 
    906 RBigIntPtrMul::RBigIntPtrMul(CompactBufferReader& reader) {}
    907 
    908 bool RBigIntPtrMul::recover(JSContext* cx, SnapshotIterator& iter) const {
    909  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
    910  if (!lhs) {
    911    return false;
    912  }
    913 
    914  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
    915  if (!rhs) {
    916    return false;
    917  }
    918 
    919  BigInt* result = BigInt::mul(cx, lhs, rhs);
    920  if (!result) {
    921    return false;
    922  }
    923 
    924  iter.storeInstructionResult(JS::BigIntValue(result));
    925  return true;
    926 }
    927 
    928 bool MBigIntPtrDiv::writeRecoverData(CompactBufferWriter& writer) const {
    929  MOZ_ASSERT(canRecoverOnBailout());
    930  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrDiv));
    931  return true;
    932 }
    933 
    934 RBigIntPtrDiv::RBigIntPtrDiv(CompactBufferReader& reader) {}
    935 
    936 bool RBigIntPtrDiv::recover(JSContext* cx, SnapshotIterator& iter) const {
    937  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
    938  if (!lhs) {
    939    return false;
    940  }
    941 
    942  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
    943  if (!rhs) {
    944    return false;
    945  }
    946 
    947  BigInt* result = BigInt::div(cx, lhs, rhs);
    948  if (!result) {
    949    return false;
    950  }
    951 
    952  iter.storeInstructionResult(JS::BigIntValue(result));
    953  return true;
    954 }
    955 
    956 bool MBigIntPtrMod::writeRecoverData(CompactBufferWriter& writer) const {
    957  MOZ_ASSERT(canRecoverOnBailout());
    958  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrMod));
    959  return true;
    960 }
    961 
    962 RBigIntPtrMod::RBigIntPtrMod(CompactBufferReader& reader) {}
    963 
    964 bool RBigIntPtrMod::recover(JSContext* cx, SnapshotIterator& iter) const {
    965  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
    966  if (!lhs) {
    967    return false;
    968  }
    969 
    970  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
    971  if (!rhs) {
    972    return false;
    973  }
    974 
    975  BigInt* result = BigInt::mod(cx, lhs, rhs);
    976  if (!result) {
    977    return false;
    978  }
    979 
    980  iter.storeInstructionResult(JS::BigIntValue(result));
    981  return true;
    982 }
    983 
    984 bool MBigIntPtrPow::writeRecoverData(CompactBufferWriter& writer) const {
    985  MOZ_ASSERT(canRecoverOnBailout());
    986  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrPow));
    987  return true;
    988 }
    989 
    990 RBigIntPtrPow::RBigIntPtrPow(CompactBufferReader& reader) {}
    991 
    992 bool RBigIntPtrPow::recover(JSContext* cx, SnapshotIterator& iter) const {
    993  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
    994  if (!lhs) {
    995    return false;
    996  }
    997 
    998  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
    999  if (!rhs) {
   1000    return false;
   1001  }
   1002 
   1003  BigInt* result = BigInt::pow(cx, lhs, rhs);
   1004  if (!result) {
   1005    return false;
   1006  }
   1007 
   1008  iter.storeInstructionResult(JS::BigIntValue(result));
   1009  return true;
   1010 }
   1011 
   1012 bool MBigIntPtrBitAnd::writeRecoverData(CompactBufferWriter& writer) const {
   1013  MOZ_ASSERT(canRecoverOnBailout());
   1014  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitAnd));
   1015  return true;
   1016 }
   1017 
   1018 RBigIntPtrBitAnd::RBigIntPtrBitAnd(CompactBufferReader& reader) {}
   1019 
   1020 bool RBigIntPtrBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const {
   1021  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
   1022  if (!lhs) {
   1023    return false;
   1024  }
   1025 
   1026  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
   1027  if (!rhs) {
   1028    return false;
   1029  }
   1030 
   1031  BigInt* result = BigInt::bitAnd(cx, lhs, rhs);
   1032  if (!result) {
   1033    return false;
   1034  }
   1035 
   1036  iter.storeInstructionResult(JS::BigIntValue(result));
   1037  return true;
   1038 }
   1039 
   1040 bool MBigIntPtrBitOr::writeRecoverData(CompactBufferWriter& writer) const {
   1041  MOZ_ASSERT(canRecoverOnBailout());
   1042  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitOr));
   1043  return true;
   1044 }
   1045 
   1046 RBigIntPtrBitOr::RBigIntPtrBitOr(CompactBufferReader& reader) {}
   1047 
   1048 bool RBigIntPtrBitOr::recover(JSContext* cx, SnapshotIterator& iter) const {
   1049  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
   1050  if (!lhs) {
   1051    return false;
   1052  }
   1053 
   1054  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
   1055  if (!rhs) {
   1056    return false;
   1057  }
   1058 
   1059  BigInt* result = BigInt::bitOr(cx, lhs, rhs);
   1060  if (!result) {
   1061    return false;
   1062  }
   1063 
   1064  iter.storeInstructionResult(JS::BigIntValue(result));
   1065  return true;
   1066 }
   1067 
   1068 bool MBigIntPtrBitXor::writeRecoverData(CompactBufferWriter& writer) const {
   1069  MOZ_ASSERT(canRecoverOnBailout());
   1070  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitXor));
   1071  return true;
   1072 }
   1073 
   1074 RBigIntPtrBitXor::RBigIntPtrBitXor(CompactBufferReader& reader) {}
   1075 
   1076 bool RBigIntPtrBitXor::recover(JSContext* cx, SnapshotIterator& iter) const {
   1077  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
   1078  if (!lhs) {
   1079    return false;
   1080  }
   1081 
   1082  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
   1083  if (!rhs) {
   1084    return false;
   1085  }
   1086 
   1087  BigInt* result = BigInt::bitXor(cx, lhs, rhs);
   1088  if (!result) {
   1089    return false;
   1090  }
   1091 
   1092  iter.storeInstructionResult(JS::BigIntValue(result));
   1093  return true;
   1094 }
   1095 
   1096 bool MBigIntPtrLsh::writeRecoverData(CompactBufferWriter& writer) const {
   1097  MOZ_ASSERT(canRecoverOnBailout());
   1098  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrLsh));
   1099  return true;
   1100 }
   1101 
   1102 RBigIntPtrLsh::RBigIntPtrLsh(CompactBufferReader& reader) {}
   1103 
   1104 bool RBigIntPtrLsh::recover(JSContext* cx, SnapshotIterator& iter) const {
   1105  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
   1106  if (!lhs) {
   1107    return false;
   1108  }
   1109 
   1110  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
   1111  if (!rhs) {
   1112    return false;
   1113  }
   1114 
   1115  BigInt* result = BigInt::lsh(cx, lhs, rhs);
   1116  if (!result) {
   1117    return false;
   1118  }
   1119 
   1120  iter.storeInstructionResult(JS::BigIntValue(result));
   1121  return true;
   1122 }
   1123 
   1124 bool MBigIntPtrRsh::writeRecoverData(CompactBufferWriter& writer) const {
   1125  MOZ_ASSERT(canRecoverOnBailout());
   1126  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrRsh));
   1127  return true;
   1128 }
   1129 
   1130 RBigIntPtrRsh::RBigIntPtrRsh(CompactBufferReader& reader) {}
   1131 
   1132 bool RBigIntPtrRsh::recover(JSContext* cx, SnapshotIterator& iter) const {
   1133  Rooted<BigInt*> lhs(cx, iter.readBigInt(cx));
   1134  if (!lhs) {
   1135    return false;
   1136  }
   1137 
   1138  Rooted<BigInt*> rhs(cx, iter.readBigInt(cx));
   1139  if (!rhs) {
   1140    return false;
   1141  }
   1142 
   1143  BigInt* result = BigInt::rsh(cx, lhs, rhs);
   1144  if (!result) {
   1145    return false;
   1146  }
   1147 
   1148  iter.storeInstructionResult(JS::BigIntValue(result));
   1149  return true;
   1150 }
   1151 
   1152 bool MBigIntPtrBitNot::writeRecoverData(CompactBufferWriter& writer) const {
   1153  MOZ_ASSERT(canRecoverOnBailout());
   1154  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntPtrBitNot));
   1155  return true;
   1156 }
   1157 
   1158 RBigIntPtrBitNot::RBigIntPtrBitNot(CompactBufferReader& reader) {}
   1159 
   1160 bool RBigIntPtrBitNot::recover(JSContext* cx, SnapshotIterator& iter) const {
   1161  Rooted<BigInt*> operand(cx, iter.readBigInt(cx));
   1162  if (!operand) {
   1163    return false;
   1164  }
   1165 
   1166  BigInt* result = BigInt::bitNot(cx, operand);
   1167  if (!result) {
   1168    return false;
   1169  }
   1170 
   1171  iter.storeInstructionResult(JS::BigIntValue(result));
   1172  return true;
   1173 }
   1174 
   1175 bool MCompare::writeRecoverData(CompactBufferWriter& writer) const {
   1176  MOZ_ASSERT(canRecoverOnBailout());
   1177  writer.writeUnsigned(uint32_t(RInstruction::Recover_Compare));
   1178 
   1179  static_assert(sizeof(JSOp) == sizeof(uint8_t));
   1180  writer.writeByte(uint8_t(jsop_));
   1181  return true;
   1182 }
   1183 
   1184 RCompare::RCompare(CompactBufferReader& reader) {
   1185  jsop_ = JSOp(reader.readByte());
   1186 
   1187  MOZ_ASSERT(IsEqualityOp(jsop_) || IsRelationalOp(jsop_));
   1188 }
   1189 
   1190 bool RCompare::recover(JSContext* cx, SnapshotIterator& iter) const {
   1191  RootedValue lhs(cx, iter.read());
   1192  RootedValue rhs(cx, iter.read());
   1193 
   1194  bool result;
   1195  switch (jsop_) {
   1196    case JSOp::Eq:
   1197    case JSOp::Ne:
   1198      if (!js::LooselyEqual(cx, lhs, rhs, &result)) {
   1199        return false;
   1200      }
   1201      if (jsop_ == JSOp::Ne) {
   1202        result = !result;
   1203      }
   1204      break;
   1205    case JSOp::StrictEq:
   1206    case JSOp::StrictNe:
   1207      if (!StrictlyEqual(cx, lhs, rhs, &result)) {
   1208        return false;
   1209      }
   1210      if (jsop_ == JSOp::StrictNe) {
   1211        result = !result;
   1212      }
   1213      break;
   1214    case JSOp::Lt:
   1215      if (!js::LessThan(cx, &lhs, &rhs, &result)) {
   1216        return false;
   1217      }
   1218      break;
   1219    case JSOp::Le:
   1220      if (!js::LessThanOrEqual(cx, &lhs, &rhs, &result)) {
   1221        return false;
   1222      }
   1223      break;
   1224    case JSOp::Gt:
   1225      if (!js::GreaterThan(cx, &lhs, &rhs, &result)) {
   1226        return false;
   1227      }
   1228      break;
   1229    case JSOp::Ge:
   1230      if (!js::GreaterThanOrEqual(cx, &lhs, &rhs, &result)) {
   1231        return false;
   1232      }
   1233      break;
   1234    default:
   1235      MOZ_CRASH("Unexpected op.");
   1236  }
   1237 
   1238  iter.storeInstructionResult(BooleanValue(result));
   1239  return true;
   1240 }
   1241 
   1242 bool MStrictConstantCompareInt32::writeRecoverData(
   1243    CompactBufferWriter& writer) const {
   1244  MOZ_ASSERT(canRecoverOnBailout());
   1245  writer.writeUnsigned(
   1246      uint32_t(RInstruction::Recover_StrictConstantCompareInt32));
   1247 
   1248  writer.writeByte(uint8_t(jsop_));
   1249  writer.writeSigned(constant_);
   1250  return true;
   1251 }
   1252 
   1253 RStrictConstantCompareInt32::RStrictConstantCompareInt32(
   1254    CompactBufferReader& reader) {
   1255  jsop_ = JSOp(reader.readByte());
   1256  constant_ = reader.readSigned();
   1257  MOZ_ASSERT(IsStrictEqualityOp(jsop_));
   1258 }
   1259 
   1260 bool RStrictConstantCompareInt32::recover(JSContext* cx,
   1261                                          SnapshotIterator& iter) const {
   1262  JS::Value lhs = iter.read();
   1263 
   1264  bool result = lhs.isNumber() && lhs.toNumber() == constant_;
   1265  if (jsop_ == JSOp::StrictNe) {
   1266    result = !result;
   1267  }
   1268  iter.storeInstructionResult(BooleanValue(result));
   1269  return true;
   1270 }
   1271 
   1272 bool MStrictConstantCompareBoolean::writeRecoverData(
   1273    CompactBufferWriter& writer) const {
   1274  MOZ_ASSERT(canRecoverOnBailout());
   1275  writer.writeUnsigned(
   1276      uint32_t(RInstruction::Recover_StrictConstantCompareBoolean));
   1277 
   1278  writer.writeByte(uint8_t(jsop_));
   1279  writer.writeUnsigned(constant_);
   1280  return true;
   1281 }
   1282 
   1283 RStrictConstantCompareBoolean::RStrictConstantCompareBoolean(
   1284    CompactBufferReader& reader) {
   1285  jsop_ = JSOp(reader.readByte());
   1286  constant_ = reader.readUnsigned();
   1287  MOZ_ASSERT(IsStrictEqualityOp(jsop_));
   1288 }
   1289 
   1290 bool RStrictConstantCompareBoolean::recover(JSContext* cx,
   1291                                            SnapshotIterator& iter) const {
   1292  JS::Value lhs = iter.read();
   1293 
   1294  bool result = lhs == BooleanValue(constant_);
   1295  if (jsop_ == JSOp::StrictNe) {
   1296    result = !result;
   1297  }
   1298  iter.storeInstructionResult(BooleanValue(result));
   1299  return true;
   1300 }
   1301 
   1302 bool MConcat::writeRecoverData(CompactBufferWriter& writer) const {
   1303  MOZ_ASSERT(canRecoverOnBailout());
   1304  writer.writeUnsigned(uint32_t(RInstruction::Recover_Concat));
   1305  return true;
   1306 }
   1307 
   1308 RConcat::RConcat(CompactBufferReader& reader) {}
   1309 
   1310 bool RConcat::recover(JSContext* cx, SnapshotIterator& iter) const {
   1311  RootedValue lhs(cx, iter.read());
   1312  RootedValue rhs(cx, iter.read());
   1313  RootedValue result(cx);
   1314 
   1315  MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
   1316  if (!js::AddValues(cx, &lhs, &rhs, &result)) {
   1317    return false;
   1318  }
   1319 
   1320  iter.storeInstructionResult(result);
   1321  return true;
   1322 }
   1323 
   1324 RStringLength::RStringLength(CompactBufferReader& reader) {}
   1325 
   1326 bool RStringLength::recover(JSContext* cx, SnapshotIterator& iter) const {
   1327  JSString* string = iter.readString();
   1328 
   1329  static_assert(JSString::MAX_LENGTH <= INT32_MAX,
   1330                "Can cast string length to int32_t");
   1331 
   1332  iter.storeInstructionResult(Int32Value(int32_t(string->length())));
   1333  return true;
   1334 }
   1335 
   1336 bool MStringLength::writeRecoverData(CompactBufferWriter& writer) const {
   1337  MOZ_ASSERT(canRecoverOnBailout());
   1338  writer.writeUnsigned(uint32_t(RInstruction::Recover_StringLength));
   1339  return true;
   1340 }
   1341 
   1342 bool MArgumentsLength::writeRecoverData(CompactBufferWriter& writer) const {
   1343  MOZ_ASSERT(canRecoverOnBailout());
   1344  writer.writeUnsigned(uint32_t(RInstruction::Recover_ArgumentsLength));
   1345  return true;
   1346 }
   1347 
   1348 RArgumentsLength::RArgumentsLength(CompactBufferReader& reader) {}
   1349 
   1350 bool RArgumentsLength::recover(JSContext* cx, SnapshotIterator& iter) const {
   1351  uintptr_t numActualArgs = iter.frame()->numActualArgs();
   1352 
   1353  static_assert(ARGS_LENGTH_MAX <= INT32_MAX,
   1354                "Can cast arguments count to int32_t");
   1355  MOZ_ASSERT(numActualArgs <= ARGS_LENGTH_MAX);
   1356 
   1357  iter.storeInstructionResult(JS::Int32Value(int32_t(numActualArgs)));
   1358  return true;
   1359 }
   1360 
   1361 bool MFloor::writeRecoverData(CompactBufferWriter& writer) const {
   1362  MOZ_ASSERT(canRecoverOnBailout());
   1363  writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
   1364  return true;
   1365 }
   1366 
   1367 RFloor::RFloor(CompactBufferReader& reader) {}
   1368 
   1369 bool RFloor::recover(JSContext* cx, SnapshotIterator& iter) const {
   1370  double num = iter.readNumber();
   1371  double result = js::math_floor_impl(num);
   1372 
   1373  iter.storeInstructionResult(NumberValue(result));
   1374  return true;
   1375 }
   1376 
   1377 bool MCeil::writeRecoverData(CompactBufferWriter& writer) const {
   1378  MOZ_ASSERT(canRecoverOnBailout());
   1379  writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
   1380  return true;
   1381 }
   1382 
   1383 RCeil::RCeil(CompactBufferReader& reader) {}
   1384 
   1385 bool RCeil::recover(JSContext* cx, SnapshotIterator& iter) const {
   1386  double num = iter.readNumber();
   1387  double result = js::math_ceil_impl(num);
   1388 
   1389  iter.storeInstructionResult(NumberValue(result));
   1390  return true;
   1391 }
   1392 
   1393 bool MRound::writeRecoverData(CompactBufferWriter& writer) const {
   1394  MOZ_ASSERT(canRecoverOnBailout());
   1395  writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
   1396  return true;
   1397 }
   1398 
   1399 RRound::RRound(CompactBufferReader& reader) {}
   1400 
   1401 bool RRound::recover(JSContext* cx, SnapshotIterator& iter) const {
   1402  double num = iter.readNumber();
   1403  double result = js::math_round_impl(num);
   1404 
   1405  iter.storeInstructionResult(NumberValue(result));
   1406  return true;
   1407 }
   1408 
   1409 bool MTrunc::writeRecoverData(CompactBufferWriter& writer) const {
   1410  MOZ_ASSERT(canRecoverOnBailout());
   1411  writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
   1412  return true;
   1413 }
   1414 
   1415 RTrunc::RTrunc(CompactBufferReader& reader) {}
   1416 
   1417 bool RTrunc::recover(JSContext* cx, SnapshotIterator& iter) const {
   1418  double num = iter.readNumber();
   1419  double result = js::math_trunc_impl(num);
   1420 
   1421  iter.storeInstructionResult(NumberValue(result));
   1422  return true;
   1423 }
   1424 
   1425 bool MCharCodeAt::writeRecoverData(CompactBufferWriter& writer) const {
   1426  MOZ_ASSERT(canRecoverOnBailout());
   1427  writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));
   1428  return true;
   1429 }
   1430 
   1431 RCharCodeAt::RCharCodeAt(CompactBufferReader& reader) {}
   1432 
   1433 bool RCharCodeAt::recover(JSContext* cx, SnapshotIterator& iter) const {
   1434  JSString* string = iter.readString();
   1435 
   1436  // Int32 because |index| is computed from MBoundsCheck.
   1437  int32_t index = iter.readInt32();
   1438  MOZ_RELEASE_ASSERT(0 <= index && size_t(index) < string->length());
   1439 
   1440  char16_t c;
   1441  if (!string->getChar(cx, index, &c)) {
   1442    return false;
   1443  }
   1444 
   1445  iter.storeInstructionResult(Int32Value(c));
   1446  return true;
   1447 }
   1448 
   1449 bool MFromCharCode::writeRecoverData(CompactBufferWriter& writer) const {
   1450  MOZ_ASSERT(canRecoverOnBailout());
   1451  writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));
   1452  return true;
   1453 }
   1454 
   1455 RFromCharCode::RFromCharCode(CompactBufferReader& reader) {}
   1456 
   1457 bool RFromCharCode::recover(JSContext* cx, SnapshotIterator& iter) const {
   1458  // Number because |charCode| is computed from (recoverable) user input.
   1459  int32_t charCode = JS::ToInt32(iter.readNumber());
   1460 
   1461  JSString* str = StringFromCharCode(cx, charCode);
   1462  if (!str) {
   1463    return false;
   1464  }
   1465 
   1466  iter.storeInstructionResult(StringValue(str));
   1467  return true;
   1468 }
   1469 
   1470 bool MFromCharCodeEmptyIfNegative::writeRecoverData(
   1471    CompactBufferWriter& writer) const {
   1472  MOZ_ASSERT(canRecoverOnBailout());
   1473  writer.writeUnsigned(
   1474      uint32_t(RInstruction::Recover_FromCharCodeEmptyIfNegative));
   1475  return true;
   1476 }
   1477 
   1478 RFromCharCodeEmptyIfNegative::RFromCharCodeEmptyIfNegative(
   1479    CompactBufferReader& reader) {}
   1480 
   1481 bool RFromCharCodeEmptyIfNegative::recover(JSContext* cx,
   1482                                           SnapshotIterator& iter) const {
   1483  // Int32 because |charCode| is computed from MCharCodeAtOrNegative.
   1484  int32_t charCode = iter.readInt32();
   1485 
   1486  JSString* str;
   1487  if (charCode < 0) {
   1488    str = cx->emptyString();
   1489  } else {
   1490    str = StringFromCharCode(cx, charCode);
   1491    if (!str) {
   1492      return false;
   1493    }
   1494  }
   1495 
   1496  iter.storeInstructionResult(StringValue(str));
   1497  return true;
   1498 }
   1499 
   1500 bool MPow::writeRecoverData(CompactBufferWriter& writer) const {
   1501  MOZ_ASSERT(canRecoverOnBailout());
   1502  writer.writeUnsigned(uint32_t(RInstruction::Recover_Pow));
   1503  return true;
   1504 }
   1505 
   1506 RPow::RPow(CompactBufferReader& reader) {}
   1507 
   1508 bool RPow::recover(JSContext* cx, SnapshotIterator& iter) const {
   1509  double base = iter.readNumber();
   1510  double power = iter.readNumber();
   1511  double result = ecmaPow(base, power);
   1512 
   1513  iter.storeInstructionResult(NumberValue(result));
   1514  return true;
   1515 }
   1516 
   1517 bool MPowHalf::writeRecoverData(CompactBufferWriter& writer) const {
   1518  MOZ_ASSERT(canRecoverOnBailout());
   1519  writer.writeUnsigned(uint32_t(RInstruction::Recover_PowHalf));
   1520  return true;
   1521 }
   1522 
   1523 RPowHalf::RPowHalf(CompactBufferReader& reader) {}
   1524 
   1525 bool RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const {
   1526  double base = iter.readNumber();
   1527  double power = 0.5;
   1528  double result = ecmaPow(base, power);
   1529 
   1530  iter.storeInstructionResult(NumberValue(result));
   1531  return true;
   1532 }
   1533 
   1534 bool MMinMax::writeRecoverData(CompactBufferWriter& writer) const {
   1535  MOZ_ASSERT(canRecoverOnBailout());
   1536  writer.writeUnsigned(uint32_t(RInstruction::Recover_MinMax));
   1537  writer.writeByte(isMax_);
   1538  return true;
   1539 }
   1540 
   1541 RMinMax::RMinMax(CompactBufferReader& reader) { isMax_ = reader.readByte(); }
   1542 
   1543 bool RMinMax::recover(JSContext* cx, SnapshotIterator& iter) const {
   1544  double x = iter.readNumber();
   1545  double y = iter.readNumber();
   1546 
   1547  double result;
   1548  if (isMax_) {
   1549    result = js::math_max_impl(x, y);
   1550  } else {
   1551    result = js::math_min_impl(x, y);
   1552  }
   1553 
   1554  iter.storeInstructionResult(NumberValue(result));
   1555  return true;
   1556 }
   1557 
   1558 bool MAbs::writeRecoverData(CompactBufferWriter& writer) const {
   1559  MOZ_ASSERT(canRecoverOnBailout());
   1560  writer.writeUnsigned(uint32_t(RInstruction::Recover_Abs));
   1561  return true;
   1562 }
   1563 
   1564 RAbs::RAbs(CompactBufferReader& reader) {}
   1565 
   1566 bool RAbs::recover(JSContext* cx, SnapshotIterator& iter) const {
   1567  double num = iter.readNumber();
   1568  double result = js::math_abs_impl(num);
   1569 
   1570  iter.storeInstructionResult(NumberValue(result));
   1571  return true;
   1572 }
   1573 
   1574 bool MSqrt::writeRecoverData(CompactBufferWriter& writer) const {
   1575  MOZ_ASSERT(canRecoverOnBailout());
   1576  writer.writeUnsigned(uint32_t(RInstruction::Recover_Sqrt));
   1577  writer.writeByte(type() == MIRType::Float32);
   1578  return true;
   1579 }
   1580 
   1581 RSqrt::RSqrt(CompactBufferReader& reader) {
   1582  isFloatOperation_ = reader.readByte();
   1583 }
   1584 
   1585 bool RSqrt::recover(JSContext* cx, SnapshotIterator& iter) const {
   1586  double num = iter.readNumber();
   1587  double result = js::math_sqrt_impl(num);
   1588 
   1589  // MIRType::Float32 is a specialization embedding the fact that the result is
   1590  // rounded to a Float32.
   1591  if (isFloatOperation_) {
   1592    result = js::RoundFloat32(result);
   1593  }
   1594 
   1595  iter.storeInstructionResult(DoubleValue(result));
   1596  return true;
   1597 }
   1598 
   1599 bool MAtan2::writeRecoverData(CompactBufferWriter& writer) const {
   1600  MOZ_ASSERT(canRecoverOnBailout());
   1601  writer.writeUnsigned(uint32_t(RInstruction::Recover_Atan2));
   1602  return true;
   1603 }
   1604 
   1605 RAtan2::RAtan2(CompactBufferReader& reader) {}
   1606 
   1607 bool RAtan2::recover(JSContext* cx, SnapshotIterator& iter) const {
   1608  double y = iter.readNumber();
   1609  double x = iter.readNumber();
   1610  double result = js::ecmaAtan2(y, x);
   1611 
   1612  iter.storeInstructionResult(DoubleValue(result));
   1613  return true;
   1614 }
   1615 
   1616 bool MHypot::writeRecoverData(CompactBufferWriter& writer) const {
   1617  MOZ_ASSERT(canRecoverOnBailout());
   1618  writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
   1619  writer.writeUnsigned(uint32_t(numOperands()));
   1620  return true;
   1621 }
   1622 
   1623 RHypot::RHypot(CompactBufferReader& reader)
   1624    : numOperands_(reader.readUnsigned()) {}
   1625 
   1626 bool RHypot::recover(JSContext* cx, SnapshotIterator& iter) const {
   1627  JS::RootedValueVector vec(cx);
   1628 
   1629  if (!vec.reserve(numOperands_)) {
   1630    return false;
   1631  }
   1632 
   1633  for (uint32_t i = 0; i < numOperands_; ++i) {
   1634    vec.infallibleAppend(NumberValue(iter.readNumber()));
   1635  }
   1636 
   1637  RootedValue result(cx);
   1638 
   1639  if (!js::math_hypot_handle(cx, vec, &result)) {
   1640    return false;
   1641  }
   1642 
   1643  iter.storeInstructionResult(result);
   1644  return true;
   1645 }
   1646 
   1647 bool MNearbyInt::writeRecoverData(CompactBufferWriter& writer) const {
   1648  MOZ_ASSERT(canRecoverOnBailout());
   1649  switch (roundingMode_) {
   1650    case RoundingMode::Up:
   1651      writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
   1652      return true;
   1653    case RoundingMode::Down:
   1654      writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
   1655      return true;
   1656    case RoundingMode::TowardsZero:
   1657      writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
   1658      return true;
   1659    default:
   1660      MOZ_CRASH("Unsupported rounding mode.");
   1661  }
   1662 }
   1663 
   1664 bool MRoundToDouble::writeRecoverData(CompactBufferWriter& writer) const {
   1665  MOZ_ASSERT(canRecoverOnBailout());
   1666  writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
   1667  return true;
   1668 }
   1669 
   1670 bool MSign::writeRecoverData(CompactBufferWriter& writer) const {
   1671  MOZ_ASSERT(canRecoverOnBailout());
   1672  writer.writeUnsigned(uint32_t(RInstruction::Recover_Sign));
   1673  return true;
   1674 }
   1675 
   1676 RSign::RSign(CompactBufferReader& reader) {}
   1677 
   1678 bool RSign::recover(JSContext* cx, SnapshotIterator& iter) const {
   1679  double num = iter.readNumber();
   1680  double result = js::math_sign_impl(num);
   1681 
   1682  iter.storeInstructionResult(NumberValue(result));
   1683  return true;
   1684 }
   1685 
   1686 bool MMathFunction::writeRecoverData(CompactBufferWriter& writer) const {
   1687  MOZ_ASSERT(canRecoverOnBailout());
   1688  switch (function_) {
   1689    case UnaryMathFunction::Ceil:
   1690      writer.writeUnsigned(uint32_t(RInstruction::Recover_Ceil));
   1691      return true;
   1692    case UnaryMathFunction::Floor:
   1693      writer.writeUnsigned(uint32_t(RInstruction::Recover_Floor));
   1694      return true;
   1695    case UnaryMathFunction::Round:
   1696      writer.writeUnsigned(uint32_t(RInstruction::Recover_Round));
   1697      return true;
   1698    case UnaryMathFunction::Trunc:
   1699      writer.writeUnsigned(uint32_t(RInstruction::Recover_Trunc));
   1700      return true;
   1701    case UnaryMathFunction::SinNative:
   1702    case UnaryMathFunction::SinFdlibm:
   1703    case UnaryMathFunction::CosNative:
   1704    case UnaryMathFunction::CosFdlibm:
   1705    case UnaryMathFunction::TanNative:
   1706    case UnaryMathFunction::TanFdlibm:
   1707    case UnaryMathFunction::Log:
   1708    case UnaryMathFunction::Exp:
   1709    case UnaryMathFunction::ACos:
   1710    case UnaryMathFunction::ASin:
   1711    case UnaryMathFunction::ATan:
   1712    case UnaryMathFunction::Log10:
   1713    case UnaryMathFunction::Log2:
   1714    case UnaryMathFunction::Log1P:
   1715    case UnaryMathFunction::ExpM1:
   1716    case UnaryMathFunction::CosH:
   1717    case UnaryMathFunction::SinH:
   1718    case UnaryMathFunction::TanH:
   1719    case UnaryMathFunction::ACosH:
   1720    case UnaryMathFunction::ASinH:
   1721    case UnaryMathFunction::ATanH:
   1722    case UnaryMathFunction::Cbrt:
   1723      static_assert(sizeof(UnaryMathFunction) == sizeof(uint8_t));
   1724      writer.writeUnsigned(uint32_t(RInstruction::Recover_MathFunction));
   1725      writer.writeByte(uint8_t(function_));
   1726      return true;
   1727  }
   1728  MOZ_CRASH("Unknown math function.");
   1729 }
   1730 
   1731 RMathFunction::RMathFunction(CompactBufferReader& reader) {
   1732  function_ = UnaryMathFunction(reader.readByte());
   1733 }
   1734 
   1735 bool RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const {
   1736  double num = iter.readNumber();
   1737 
   1738  double result;
   1739  switch (function_) {
   1740    case UnaryMathFunction::SinNative:
   1741      result = js::math_sin_native_impl(num);
   1742      break;
   1743    case UnaryMathFunction::SinFdlibm:
   1744      result = js::math_sin_fdlibm_impl(num);
   1745      break;
   1746    case UnaryMathFunction::CosNative:
   1747      result = js::math_cos_native_impl(num);
   1748      break;
   1749    case UnaryMathFunction::CosFdlibm:
   1750      result = js::math_cos_fdlibm_impl(num);
   1751      break;
   1752    case UnaryMathFunction::TanNative:
   1753      result = js::math_tan_native_impl(num);
   1754      break;
   1755    case UnaryMathFunction::TanFdlibm:
   1756      result = js::math_tan_fdlibm_impl(num);
   1757      break;
   1758    case UnaryMathFunction::Log:
   1759      result = js::math_log_impl(num);
   1760      break;
   1761    case UnaryMathFunction::Exp:
   1762      result = js::math_exp_impl(num);
   1763      break;
   1764    case UnaryMathFunction::ACos:
   1765      result = js::math_acos_impl(num);
   1766      break;
   1767    case UnaryMathFunction::ASin:
   1768      result = js::math_asin_impl(num);
   1769      break;
   1770    case UnaryMathFunction::ATan:
   1771      result = js::math_atan_impl(num);
   1772      break;
   1773    case UnaryMathFunction::Log10:
   1774      result = js::math_log10_impl(num);
   1775      break;
   1776    case UnaryMathFunction::Log2:
   1777      result = js::math_log2_impl(num);
   1778      break;
   1779    case UnaryMathFunction::Log1P:
   1780      result = js::math_log1p_impl(num);
   1781      break;
   1782    case UnaryMathFunction::ExpM1:
   1783      result = js::math_expm1_impl(num);
   1784      break;
   1785    case UnaryMathFunction::CosH:
   1786      result = js::math_cosh_impl(num);
   1787      break;
   1788    case UnaryMathFunction::SinH:
   1789      result = js::math_sinh_impl(num);
   1790      break;
   1791    case UnaryMathFunction::TanH:
   1792      result = js::math_tanh_impl(num);
   1793      break;
   1794    case UnaryMathFunction::ACosH:
   1795      result = js::math_acosh_impl(num);
   1796      break;
   1797    case UnaryMathFunction::ASinH:
   1798      result = js::math_asinh_impl(num);
   1799      break;
   1800    case UnaryMathFunction::ATanH:
   1801      result = js::math_atanh_impl(num);
   1802      break;
   1803    case UnaryMathFunction::Cbrt:
   1804      result = js::math_cbrt_impl(num);
   1805      break;
   1806 
   1807    case UnaryMathFunction::Trunc:
   1808    case UnaryMathFunction::Floor:
   1809    case UnaryMathFunction::Ceil:
   1810    case UnaryMathFunction::Round:
   1811      // These have their own recover instructions.
   1812      MOZ_CRASH("Unexpected rounding math function.");
   1813  }
   1814 
   1815  iter.storeInstructionResult(DoubleValue(result));
   1816  return true;
   1817 }
   1818 
   1819 bool MRandom::writeRecoverData(CompactBufferWriter& writer) const {
   1820  MOZ_ASSERT(this->canRecoverOnBailout());
   1821  writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));
   1822  return true;
   1823 }
   1824 
   1825 bool MRandom::canRecoverOnBailout() const {
   1826  return !js::SupportDifferentialTesting();
   1827 }
   1828 
   1829 RRandom::RRandom(CompactBufferReader& reader) {}
   1830 
   1831 bool RRandom::recover(JSContext* cx, SnapshotIterator& iter) const {
   1832  iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));
   1833  return true;
   1834 }
   1835 
   1836 bool MStringSplit::writeRecoverData(CompactBufferWriter& writer) const {
   1837  MOZ_ASSERT(canRecoverOnBailout());
   1838  writer.writeUnsigned(uint32_t(RInstruction::Recover_StringSplit));
   1839  return true;
   1840 }
   1841 
   1842 RStringSplit::RStringSplit(CompactBufferReader& reader) {}
   1843 
   1844 bool RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const {
   1845  RootedString str(cx, iter.readString());
   1846  RootedString sep(cx, iter.readString());
   1847 
   1848  JSObject* res = StringSplitString(cx, str, sep, INT32_MAX);
   1849  if (!res) {
   1850    return false;
   1851  }
   1852 
   1853  iter.storeInstructionResult(ObjectValue(*res));
   1854  return true;
   1855 }
   1856 
   1857 bool MNaNToZero::writeRecoverData(CompactBufferWriter& writer) const {
   1858  MOZ_ASSERT(canRecoverOnBailout());
   1859  writer.writeUnsigned(uint32_t(RInstruction::Recover_NaNToZero));
   1860  return true;
   1861 }
   1862 
   1863 RNaNToZero::RNaNToZero(CompactBufferReader& reader) {}
   1864 
   1865 bool RNaNToZero::recover(JSContext* cx, SnapshotIterator& iter) const {
   1866  double v = iter.readNumber();
   1867  if (std::isnan(v) || mozilla::IsNegativeZero(v)) {
   1868    v = 0.0;
   1869  }
   1870 
   1871  iter.storeInstructionResult(DoubleValue(v));
   1872  return true;
   1873 }
   1874 
   1875 bool MTypeOf::writeRecoverData(CompactBufferWriter& writer) const {
   1876  MOZ_ASSERT(canRecoverOnBailout());
   1877  writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOf));
   1878  return true;
   1879 }
   1880 
   1881 RTypeOf::RTypeOf(CompactBufferReader& reader) {}
   1882 
   1883 bool RTypeOf::recover(JSContext* cx, SnapshotIterator& iter) const {
   1884  JS::Value v = iter.read();
   1885 
   1886  iter.storeInstructionResult(Int32Value(TypeOfValue(v)));
   1887  return true;
   1888 }
   1889 
   1890 bool MTypeOfName::writeRecoverData(CompactBufferWriter& writer) const {
   1891  MOZ_ASSERT(canRecoverOnBailout());
   1892  writer.writeUnsigned(uint32_t(RInstruction::Recover_TypeOfName));
   1893  return true;
   1894 }
   1895 
   1896 RTypeOfName::RTypeOfName(CompactBufferReader& reader) {}
   1897 
   1898 bool RTypeOfName::recover(JSContext* cx, SnapshotIterator& iter) const {
   1899  // Int32 because |type| is computed from MTypeOf.
   1900  int32_t type = iter.readInt32();
   1901  MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT);
   1902 
   1903  JSString* name = TypeName(JSType(type), *cx->runtime()->commonNames);
   1904  iter.storeInstructionResult(StringValue(name));
   1905  return true;
   1906 }
   1907 
   1908 bool MToDouble::writeRecoverData(CompactBufferWriter& writer) const {
   1909  MOZ_ASSERT(canRecoverOnBailout());
   1910  writer.writeUnsigned(uint32_t(RInstruction::Recover_ToDouble));
   1911  return true;
   1912 }
   1913 
   1914 RToDouble::RToDouble(CompactBufferReader& reader) {}
   1915 
   1916 bool RToDouble::recover(JSContext* cx, SnapshotIterator& iter) const {
   1917  RootedValue v(cx, iter.read());
   1918 
   1919  MOZ_ASSERT(!v.isObject());
   1920  MOZ_ASSERT(!v.isSymbol());
   1921  MOZ_ASSERT(!v.isBigInt());
   1922 
   1923  double dbl;
   1924  if (!ToNumber(cx, v, &dbl)) {
   1925    return false;
   1926  }
   1927 
   1928  iter.storeInstructionResult(DoubleValue(dbl));
   1929  return true;
   1930 }
   1931 
   1932 bool MToFloat32::writeRecoverData(CompactBufferWriter& writer) const {
   1933  MOZ_ASSERT(canRecoverOnBailout());
   1934  writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat32));
   1935  return true;
   1936 }
   1937 
   1938 RToFloat32::RToFloat32(CompactBufferReader& reader) {}
   1939 
   1940 bool RToFloat32::recover(JSContext* cx, SnapshotIterator& iter) const {
   1941  double num = iter.readNumber();
   1942  double result = js::RoundFloat32(num);
   1943 
   1944  iter.storeInstructionResult(DoubleValue(result));
   1945  return true;
   1946 }
   1947 
   1948 bool MToFloat16::writeRecoverData(CompactBufferWriter& writer) const {
   1949  MOZ_ASSERT(canRecoverOnBailout());
   1950  writer.writeUnsigned(uint32_t(RInstruction::Recover_ToFloat16));
   1951  return true;
   1952 }
   1953 
   1954 RToFloat16::RToFloat16(CompactBufferReader& reader) {}
   1955 
   1956 bool RToFloat16::recover(JSContext* cx, SnapshotIterator& iter) const {
   1957  double num = iter.readNumber();
   1958  double result = js::RoundFloat16(num);
   1959 
   1960  iter.storeInstructionResult(DoubleValue(result));
   1961  return true;
   1962 }
   1963 
   1964 bool MTruncateToInt32::writeRecoverData(CompactBufferWriter& writer) const {
   1965  MOZ_ASSERT(canRecoverOnBailout());
   1966  writer.writeUnsigned(uint32_t(RInstruction::Recover_TruncateToInt32));
   1967  return true;
   1968 }
   1969 
   1970 RTruncateToInt32::RTruncateToInt32(CompactBufferReader& reader) {}
   1971 
   1972 bool RTruncateToInt32::recover(JSContext* cx, SnapshotIterator& iter) const {
   1973  RootedValue value(cx, iter.read());
   1974 
   1975  int32_t trunc;
   1976  if (!JS::ToInt32(cx, value, &trunc)) {
   1977    return false;
   1978  }
   1979 
   1980  iter.storeInstructionResult(Int32Value(trunc));
   1981  return true;
   1982 }
   1983 
   1984 bool MNewObject::writeRecoverData(CompactBufferWriter& writer) const {
   1985  MOZ_ASSERT(canRecoverOnBailout());
   1986 
   1987  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewObject));
   1988 
   1989  // Recover instructions are only supported if we have a template object.
   1990  MOZ_ASSERT(mode_ == MNewObject::ObjectCreate);
   1991  return true;
   1992 }
   1993 
   1994 RNewObject::RNewObject(CompactBufferReader& reader) {}
   1995 
   1996 bool RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const {
   1997  RootedObject templateObject(cx, iter.readObject());
   1998 
   1999  // See CodeGenerator::visitNewObjectVMCall.
   2000  // Note that recover instructions are only used if mode == ObjectCreate.
   2001  JSObject* resultObject =
   2002      ObjectCreateWithTemplate(cx, templateObject.as<PlainObject>());
   2003  if (!resultObject) {
   2004    return false;
   2005  }
   2006 
   2007  iter.storeInstructionResult(ObjectValue(*resultObject));
   2008  return true;
   2009 }
   2010 
   2011 bool MNewPlainObject::writeRecoverData(CompactBufferWriter& writer) const {
   2012  MOZ_ASSERT(canRecoverOnBailout());
   2013  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewPlainObject));
   2014 
   2015  MOZ_ASSERT(gc::AllocKind(uint8_t(allocKind_)) == allocKind_);
   2016  writer.writeByte(uint8_t(allocKind_));
   2017  MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_);
   2018  writer.writeByte(uint8_t(initialHeap_));
   2019  return true;
   2020 }
   2021 
   2022 RNewPlainObject::RNewPlainObject(CompactBufferReader& reader) {
   2023  allocKind_ = gc::AllocKind(reader.readByte());
   2024  MOZ_ASSERT(gc::IsValidAllocKind(allocKind_));
   2025  initialHeap_ = gc::Heap(reader.readByte());
   2026  MOZ_ASSERT(initialHeap_ == gc::Heap::Default ||
   2027             initialHeap_ == gc::Heap::Tenured);
   2028 }
   2029 
   2030 bool RNewPlainObject::recover(JSContext* cx, SnapshotIterator& iter) const {
   2031  Rooted<SharedShape*> shape(cx, &iter.readGCCellPtr().as<Shape>().asShared());
   2032 
   2033  // See CodeGenerator::visitNewPlainObject.
   2034  JSObject* resultObject =
   2035      NewPlainObjectOptimizedFallback(cx, shape, allocKind_, initialHeap_);
   2036  if (!resultObject) {
   2037    return false;
   2038  }
   2039 
   2040  iter.storeInstructionResult(ObjectValue(*resultObject));
   2041  return true;
   2042 }
   2043 
   2044 bool MNewArrayObject::writeRecoverData(CompactBufferWriter& writer) const {
   2045  MOZ_ASSERT(canRecoverOnBailout());
   2046  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArrayObject));
   2047 
   2048  writer.writeUnsigned(length_);
   2049  MOZ_ASSERT(gc::Heap(uint8_t(initialHeap_)) == initialHeap_);
   2050  writer.writeByte(uint8_t(initialHeap_));
   2051  return true;
   2052 }
   2053 
   2054 RNewArrayObject::RNewArrayObject(CompactBufferReader& reader) {
   2055  length_ = reader.readUnsigned();
   2056  initialHeap_ = gc::Heap(reader.readByte());
   2057  MOZ_ASSERT(initialHeap_ == gc::Heap::Default ||
   2058             initialHeap_ == gc::Heap::Tenured);
   2059 }
   2060 
   2061 bool RNewArrayObject::recover(JSContext* cx, SnapshotIterator& iter) const {
   2062  iter.read();  // Skip unused shape field.
   2063 
   2064  NewObjectKind kind =
   2065      initialHeap_ == gc::Heap::Tenured ? TenuredObject : GenericObject;
   2066  JSObject* array = NewArrayOperation(cx, length_, kind);
   2067  if (!array) {
   2068    return false;
   2069  }
   2070 
   2071  iter.storeInstructionResult(ObjectValue(*array));
   2072  return true;
   2073 }
   2074 
   2075 bool MNewTypedArray::writeRecoverData(CompactBufferWriter& writer) const {
   2076  MOZ_ASSERT(canRecoverOnBailout());
   2077  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewTypedArray));
   2078  return true;
   2079 }
   2080 
   2081 RNewTypedArray::RNewTypedArray(CompactBufferReader& reader) {}
   2082 
   2083 bool RNewTypedArray::recover(JSContext* cx, SnapshotIterator& iter) const {
   2084  RootedObject templateObject(cx, iter.readObject());
   2085 
   2086  size_t length = templateObject.as<FixedLengthTypedArrayObject>()->length();
   2087  MOZ_ASSERT(length <= INT32_MAX,
   2088             "Template objects are only created for int32 lengths");
   2089 
   2090  JSObject* resultObject =
   2091      NewTypedArrayWithTemplateAndLength(cx, templateObject, length);
   2092  if (!resultObject) {
   2093    return false;
   2094  }
   2095 
   2096  iter.storeInstructionResult(ObjectValue(*resultObject));
   2097  return true;
   2098 }
   2099 
   2100 bool MNewArray::writeRecoverData(CompactBufferWriter& writer) const {
   2101  MOZ_ASSERT(canRecoverOnBailout());
   2102  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));
   2103  writer.writeUnsigned(length());
   2104  return true;
   2105 }
   2106 
   2107 RNewArray::RNewArray(CompactBufferReader& reader) {
   2108  count_ = reader.readUnsigned();
   2109 }
   2110 
   2111 bool RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const {
   2112  JSObject* templateObject = iter.readObject();
   2113  Rooted<Shape*> shape(cx, templateObject->shape());
   2114 
   2115  ArrayObject* resultObject = NewArrayWithShape(cx, count_, shape);
   2116  if (!resultObject) {
   2117    return false;
   2118  }
   2119 
   2120  iter.storeInstructionResult(ObjectValue(*resultObject));
   2121  return true;
   2122 }
   2123 
   2124 bool MNewIterator::writeRecoverData(CompactBufferWriter& writer) const {
   2125  MOZ_ASSERT(canRecoverOnBailout());
   2126  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewIterator));
   2127  writer.writeByte(type_);
   2128  return true;
   2129 }
   2130 
   2131 RNewIterator::RNewIterator(CompactBufferReader& reader) {
   2132  type_ = reader.readByte();
   2133 }
   2134 
   2135 bool RNewIterator::recover(JSContext* cx, SnapshotIterator& iter) const {
   2136  // Template object is not used when recovering MNewIterator.
   2137  (void)iter.readObject();
   2138 
   2139  JSObject* resultObject = nullptr;
   2140  switch (MNewIterator::Type(type_)) {
   2141    case MNewIterator::ArrayIterator:
   2142      resultObject = NewArrayIterator(cx);
   2143      break;
   2144    case MNewIterator::StringIterator:
   2145      resultObject = NewStringIterator(cx);
   2146      break;
   2147    case MNewIterator::RegExpStringIterator:
   2148      resultObject = NewRegExpStringIterator(cx);
   2149      break;
   2150  }
   2151 
   2152  if (!resultObject) {
   2153    return false;
   2154  }
   2155 
   2156  iter.storeInstructionResult(ObjectValue(*resultObject));
   2157  return true;
   2158 }
   2159 
   2160 bool MLambda::writeRecoverData(CompactBufferWriter& writer) const {
   2161  MOZ_ASSERT(canRecoverOnBailout());
   2162  writer.writeUnsigned(uint32_t(RInstruction::Recover_Lambda));
   2163  return true;
   2164 }
   2165 
   2166 RLambda::RLambda(CompactBufferReader& reader) {}
   2167 
   2168 bool RLambda::recover(JSContext* cx, SnapshotIterator& iter) const {
   2169  RootedObject scopeChain(cx, iter.readObject());
   2170  RootedFunction fun(cx, &iter.readObject()->as<JSFunction>());
   2171 
   2172  JSObject* resultObject = js::Lambda(cx, fun, scopeChain);
   2173  if (!resultObject) {
   2174    return false;
   2175  }
   2176 
   2177  iter.storeInstructionResult(ObjectValue(*resultObject));
   2178  return true;
   2179 }
   2180 
   2181 bool MFunctionWithProto::writeRecoverData(CompactBufferWriter& writer) const {
   2182  MOZ_ASSERT(canRecoverOnBailout());
   2183  writer.writeUnsigned(uint32_t(RInstruction::Recover_FunctionWithProto));
   2184  return true;
   2185 }
   2186 
   2187 RFunctionWithProto::RFunctionWithProto(CompactBufferReader& reader) {}
   2188 
   2189 bool RFunctionWithProto::recover(JSContext* cx, SnapshotIterator& iter) const {
   2190  RootedObject scopeChain(cx, iter.readObject());
   2191  RootedObject prototype(cx, iter.readObject());
   2192  RootedFunction fun(cx, &iter.readObject()->as<JSFunction>());
   2193 
   2194  JSObject* resultObject =
   2195      js::FunWithProtoOperation(cx, fun, scopeChain, prototype);
   2196  if (!resultObject) {
   2197    return false;
   2198  }
   2199 
   2200  iter.storeInstructionResult(ObjectValue(*resultObject));
   2201  return true;
   2202 }
   2203 
   2204 bool MCallee::writeRecoverData(CompactBufferWriter& writer) const {
   2205  MOZ_ASSERT(canRecoverOnBailout());
   2206  writer.writeUnsigned(uint32_t(RInstruction::Recover_Callee));
   2207  return true;
   2208 }
   2209 
   2210 RCallee::RCallee(CompactBufferReader& reader) {}
   2211 
   2212 bool RCallee::recover(JSContext* cx, SnapshotIterator& iter) const {
   2213  JSFunction* callee = CalleeTokenToFunction(iter.frame()->calleeToken());
   2214  iter.storeInstructionResult(ObjectValue(*callee));
   2215  return true;
   2216 }
   2217 
   2218 bool MFunctionEnvironment::writeRecoverData(CompactBufferWriter& writer) const {
   2219  MOZ_ASSERT(canRecoverOnBailout());
   2220  writer.writeUnsigned(uint32_t(RInstruction::Recover_FunctionEnvironment));
   2221  return true;
   2222 }
   2223 
   2224 RFunctionEnvironment::RFunctionEnvironment(CompactBufferReader& reader) {}
   2225 
   2226 bool RFunctionEnvironment::recover(JSContext* cx,
   2227                                   SnapshotIterator& iter) const {
   2228  JSObject* obj = iter.readObject();
   2229  JSObject* env = obj->as<JSFunction>().environment();
   2230  iter.storeInstructionResult(ObjectValue(*env));
   2231  return true;
   2232 }
   2233 
   2234 bool MNewCallObject::writeRecoverData(CompactBufferWriter& writer) const {
   2235  MOZ_ASSERT(canRecoverOnBailout());
   2236  writer.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject));
   2237  return true;
   2238 }
   2239 
   2240 RNewCallObject::RNewCallObject(CompactBufferReader& reader) {}
   2241 
   2242 bool RNewCallObject::recover(JSContext* cx, SnapshotIterator& iter) const {
   2243  CallObject* templateObj = &iter.readObject()->as<CallObject>();
   2244 
   2245  Rooted<SharedShape*> shape(cx, templateObj->sharedShape());
   2246 
   2247  JSObject* resultObject = CallObject::createWithShape(cx, shape);
   2248  if (!resultObject) {
   2249    return false;
   2250  }
   2251 
   2252  iter.storeInstructionResult(ObjectValue(*resultObject));
   2253  return true;
   2254 }
   2255 
   2256 bool MObjectKeys::canRecoverOnBailout() const {
   2257  // Only claim that this operation can be recovered on bailout if some other
   2258  // optimization already marked it as such.
   2259  return isRecoveredOnBailout();
   2260 }
   2261 
   2262 bool MObjectKeys::writeRecoverData(CompactBufferWriter& writer) const {
   2263  MOZ_ASSERT(canRecoverOnBailout());
   2264  writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeys));
   2265  return true;
   2266 }
   2267 
   2268 RObjectKeys::RObjectKeys(CompactBufferReader& reader) {}
   2269 
   2270 bool RObjectKeys::recover(JSContext* cx, SnapshotIterator& iter) const {
   2271  Rooted<JSObject*> obj(cx, iter.readObject());
   2272 
   2273  JSObject* resultKeys = ObjectKeys(cx, obj);
   2274  if (!resultKeys) {
   2275    return false;
   2276  }
   2277 
   2278  iter.storeInstructionResult(ObjectValue(*resultKeys));
   2279  return true;
   2280 }
   2281 
   2282 bool MObjectKeysFromIterator::writeRecoverData(
   2283    CompactBufferWriter& writer) const {
   2284  MOZ_ASSERT(canRecoverOnBailout());
   2285  writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectKeysFromIterator));
   2286  return true;
   2287 }
   2288 
   2289 RObjectKeysFromIterator::RObjectKeysFromIterator(CompactBufferReader& reader) {}
   2290 
   2291 bool RObjectKeysFromIterator::recover(JSContext* cx,
   2292                                      SnapshotIterator& iter) const {
   2293  Rooted<JSObject*> iterObj(cx, iter.readObject());
   2294 
   2295  JSObject* resultKeys = ObjectKeysFromIterator(cx, iterObj);
   2296  if (!resultKeys) {
   2297    return false;
   2298  }
   2299 
   2300  iter.storeInstructionResult(ObjectValue(*resultKeys));
   2301  return true;
   2302 }
   2303 
   2304 bool MObjectState::writeRecoverData(CompactBufferWriter& writer) const {
   2305  MOZ_ASSERT(canRecoverOnBailout());
   2306  writer.writeUnsigned(uint32_t(RInstruction::Recover_ObjectState));
   2307  writer.writeUnsigned(numSlots());
   2308  return true;
   2309 }
   2310 
   2311 RObjectState::RObjectState(CompactBufferReader& reader) {
   2312  numSlots_ = reader.readUnsigned();
   2313 }
   2314 
   2315 bool RObjectState::recover(JSContext* cx, SnapshotIterator& iter) const {
   2316  JSObject* object = iter.readObject();
   2317  NativeObject* nativeObject = &object->as<NativeObject>();
   2318  MOZ_ASSERT(!Watchtower::watchesPropertyValueChange(nativeObject));
   2319  MOZ_ASSERT(nativeObject->slotSpan() == numSlots());
   2320 
   2321  for (size_t i = 0; i < numSlots(); i++) {
   2322    Value val = iter.read();
   2323    nativeObject->setSlot(i, val);
   2324  }
   2325 
   2326  iter.storeInstructionResult(ObjectValue(*object));
   2327  return true;
   2328 }
   2329 
   2330 bool MArrayState::writeRecoverData(CompactBufferWriter& writer) const {
   2331  MOZ_ASSERT(canRecoverOnBailout());
   2332  writer.writeUnsigned(uint32_t(RInstruction::Recover_ArrayState));
   2333  writer.writeUnsigned(numElements());
   2334  return true;
   2335 }
   2336 
   2337 RArrayState::RArrayState(CompactBufferReader& reader) {
   2338  numElements_ = reader.readUnsigned();
   2339 }
   2340 
   2341 bool RArrayState::recover(JSContext* cx, SnapshotIterator& iter) const {
   2342  ArrayObject* object = &iter.readObject()->as<ArrayObject>();
   2343 
   2344  // Int32 because |initLength| is computed from MConstant.
   2345  uint32_t initLength = iter.readInt32();
   2346 
   2347  MOZ_ASSERT(object->getDenseInitializedLength() == 0,
   2348             "initDenseElement call below relies on this");
   2349  object->setDenseInitializedLength(initLength);
   2350 
   2351  for (size_t index = 0; index < numElements(); index++) {
   2352    Value val = iter.read();
   2353 
   2354    if (index >= initLength) {
   2355      MOZ_ASSERT(val.isUndefined());
   2356      continue;
   2357    }
   2358 
   2359    object->initDenseElement(index, val);
   2360  }
   2361 
   2362  iter.storeInstructionResult(ObjectValue(*object));
   2363  return true;
   2364 }
   2365 
   2366 bool MAssertRecoveredOnBailout::writeRecoverData(
   2367    CompactBufferWriter& writer) const {
   2368  MOZ_ASSERT(canRecoverOnBailout());
   2369  MOZ_RELEASE_ASSERT(input()->isRecoveredOnBailout() == mustBeRecovered_,
   2370                     "assertRecoveredOnBailout failed during compilation");
   2371  writer.writeUnsigned(
   2372      uint32_t(RInstruction::Recover_AssertRecoveredOnBailout));
   2373  return true;
   2374 }
   2375 
   2376 RAssertRecoveredOnBailout::RAssertRecoveredOnBailout(
   2377    CompactBufferReader& reader) {}
   2378 
   2379 bool RAssertRecoveredOnBailout::recover(JSContext* cx,
   2380                                        SnapshotIterator& iter) const {
   2381  iter.read();  // skip the unused operand.
   2382  iter.storeInstructionResult(UndefinedValue());
   2383  return true;
   2384 }
   2385 
   2386 bool MStringReplace::writeRecoverData(CompactBufferWriter& writer) const {
   2387  MOZ_ASSERT(canRecoverOnBailout());
   2388  writer.writeUnsigned(uint32_t(RInstruction::Recover_StringReplace));
   2389  writer.writeByte(isFlatReplacement_);
   2390  return true;
   2391 }
   2392 
   2393 RStringReplace::RStringReplace(CompactBufferReader& reader) {
   2394  isFlatReplacement_ = reader.readByte();
   2395 }
   2396 
   2397 bool RStringReplace::recover(JSContext* cx, SnapshotIterator& iter) const {
   2398  RootedString string(cx, iter.readString());
   2399  RootedString pattern(cx, iter.readString());
   2400  RootedString replace(cx, iter.readString());
   2401 
   2402  JSString* result =
   2403      isFlatReplacement_
   2404          ? js::StringFlatReplaceString(cx, string, pattern, replace)
   2405          : js::str_replace_string_raw(cx, string, pattern, replace);
   2406 
   2407  if (!result) {
   2408    return false;
   2409  }
   2410 
   2411  iter.storeInstructionResult(StringValue(result));
   2412  return true;
   2413 }
   2414 
   2415 bool MSubstr::writeRecoverData(CompactBufferWriter& writer) const {
   2416  MOZ_ASSERT(canRecoverOnBailout());
   2417  writer.writeUnsigned(uint32_t(RInstruction::Recover_Substr));
   2418  return true;
   2419 }
   2420 
   2421 RSubstr::RSubstr(CompactBufferReader& reader) {}
   2422 
   2423 bool RSubstr::recover(JSContext* cx, SnapshotIterator& iter) const {
   2424  RootedString str(cx, iter.readString());
   2425 
   2426  // Int32 because |begin| is computed from MStringTrimStartIndex, MConstant,
   2427  // or CallSubstringKernelResult.
   2428  int32_t begin = iter.readInt32();
   2429 
   2430  // |length| is computed from MSub(truncated), MStringTrimEndIndex, or
   2431  // CallSubstringKernelResult. The current MSub inputs won't overflow, so when
   2432  // RSub recovers the MSub instruction, the input will be representable as an
   2433  // Int32. This is only true as long as RSub calls |js::SubOperation|, which in
   2434  // turn calls |JS::Value::setNumber|. We don't want to rely on this exact call
   2435  // sequence, so instead use |readNumber| here and then release-assert the
   2436  // number is exactly representable as an Int32.
   2437  int32_t length = mozilla::ReleaseAssertedCast<int32_t>(iter.readNumber());
   2438 
   2439  JSString* result = SubstringKernel(cx, str, begin, length);
   2440  if (!result) {
   2441    return false;
   2442  }
   2443 
   2444  iter.storeInstructionResult(StringValue(result));
   2445  return true;
   2446 }
   2447 
   2448 bool MAtomicIsLockFree::writeRecoverData(CompactBufferWriter& writer) const {
   2449  MOZ_ASSERT(canRecoverOnBailout());
   2450  writer.writeUnsigned(uint32_t(RInstruction::Recover_AtomicIsLockFree));
   2451  return true;
   2452 }
   2453 
   2454 RAtomicIsLockFree::RAtomicIsLockFree(CompactBufferReader& reader) {}
   2455 
   2456 bool RAtomicIsLockFree::recover(JSContext* cx, SnapshotIterator& iter) const {
   2457  double dsize = JS::ToInteger(iter.readNumber());
   2458 
   2459  int32_t size;
   2460  bool result = mozilla::NumberEqualsInt32(dsize, &size) &&
   2461                AtomicOperations::isLockfreeJS(size);
   2462  iter.storeInstructionResult(BooleanValue(result));
   2463  return true;
   2464 }
   2465 
   2466 bool MInt64ToBigInt::writeRecoverData(CompactBufferWriter& writer) const {
   2467  MOZ_ASSERT(canRecoverOnBailout());
   2468  writer.writeUnsigned(uint32_t(RInstruction::Recover_Int64ToBigInt));
   2469  writer.writeByte(isSigned());
   2470  return true;
   2471 }
   2472 
   2473 RInt64ToBigInt::RInt64ToBigInt(CompactBufferReader& reader) {
   2474  isSigned_ = bool(reader.readByte());
   2475 }
   2476 
   2477 bool RInt64ToBigInt::recover(JSContext* cx, SnapshotIterator& iter) const {
   2478  int64_t n = iter.readInt64();
   2479 
   2480  BigInt* result;
   2481  if (isSigned_) {
   2482    result = BigInt::createFromInt64(cx, n);
   2483  } else {
   2484    result = BigInt::createFromUint64(cx, uint64_t(n));
   2485  }
   2486  if (!result) {
   2487    return false;
   2488  }
   2489 
   2490  iter.storeInstructionResult(JS::BigIntValue(result));
   2491  return true;
   2492 }
   2493 
   2494 bool MBigIntAsIntN::writeRecoverData(CompactBufferWriter& writer) const {
   2495  MOZ_ASSERT(canRecoverOnBailout());
   2496  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsIntN));
   2497  return true;
   2498 }
   2499 
   2500 RBigIntAsIntN::RBigIntAsIntN(CompactBufferReader& reader) {}
   2501 
   2502 bool RBigIntAsIntN::recover(JSContext* cx, SnapshotIterator& iter) const {
   2503  // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
   2504  int32_t bits = iter.readInt32();
   2505  MOZ_ASSERT(bits >= 0);
   2506 
   2507  RootedBigInt input(cx, iter.readBigInt());
   2508 
   2509  BigInt* result = BigInt::asIntN(cx, input, bits);
   2510  if (!result) {
   2511    return false;
   2512  }
   2513 
   2514  iter.storeInstructionResult(JS::BigIntValue(result));
   2515  return true;
   2516 }
   2517 
   2518 bool MBigIntAsUintN::writeRecoverData(CompactBufferWriter& writer) const {
   2519  MOZ_ASSERT(canRecoverOnBailout());
   2520  writer.writeUnsigned(uint32_t(RInstruction::Recover_BigIntAsUintN));
   2521  return true;
   2522 }
   2523 
   2524 RBigIntAsUintN::RBigIntAsUintN(CompactBufferReader& reader) {}
   2525 
   2526 bool RBigIntAsUintN::recover(JSContext* cx, SnapshotIterator& iter) const {
   2527  // Int32 because |bits| is computed from MGuardInt32IsNonNegative.
   2528  int32_t bits = iter.readInt32();
   2529  MOZ_ASSERT(bits >= 0);
   2530 
   2531  RootedBigInt input(cx, iter.readBigInt());
   2532 
   2533  BigInt* result = BigInt::asUintN(cx, input, bits);
   2534  if (!result) {
   2535    return false;
   2536  }
   2537 
   2538  iter.storeInstructionResult(JS::BigIntValue(result));
   2539  return true;
   2540 }
   2541 
   2542 bool MCreateArgumentsObject::writeRecoverData(
   2543    CompactBufferWriter& writer) const {
   2544  MOZ_ASSERT(canRecoverOnBailout());
   2545  writer.writeUnsigned(uint32_t(RInstruction::Recover_CreateArgumentsObject));
   2546  return true;
   2547 }
   2548 
   2549 RCreateArgumentsObject::RCreateArgumentsObject(CompactBufferReader& reader) {}
   2550 
   2551 bool RCreateArgumentsObject::recover(JSContext* cx,
   2552                                     SnapshotIterator& iter) const {
   2553  RootedObject callObject(cx, iter.readObject());
   2554  ArgumentsObject* result =
   2555      ArgumentsObject::createForIon(cx, iter.frame(), callObject);
   2556  if (!result) {
   2557    return false;
   2558  }
   2559 
   2560  iter.storeInstructionResult(JS::ObjectValue(*result));
   2561  return true;
   2562 }
   2563 
   2564 bool MCreateInlinedArgumentsObject::writeRecoverData(
   2565    CompactBufferWriter& writer) const {
   2566  MOZ_ASSERT(canRecoverOnBailout());
   2567  writer.writeUnsigned(
   2568      uint32_t(RInstruction::Recover_CreateInlinedArgumentsObject));
   2569  writer.writeUnsigned(numActuals());
   2570  return true;
   2571 }
   2572 
   2573 RCreateInlinedArgumentsObject::RCreateInlinedArgumentsObject(
   2574    CompactBufferReader& reader) {
   2575  numActuals_ = reader.readUnsigned();
   2576 }
   2577 
   2578 bool RCreateInlinedArgumentsObject::recover(JSContext* cx,
   2579                                            SnapshotIterator& iter) const {
   2580  RootedObject callObject(cx, iter.readObject());
   2581  RootedFunction callee(cx, &iter.readObject()->as<JSFunction>());
   2582 
   2583  JS::RootedValueArray<ArgumentsObject::MaxInlinedArgs> argsArray(cx);
   2584  for (uint32_t i = 0; i < numActuals_; i++) {
   2585    argsArray[i].set(iter.read());
   2586  }
   2587 
   2588  ArgumentsObject* result = ArgumentsObject::createFromValueArray(
   2589      cx, argsArray, callee, callObject, numActuals_);
   2590  if (!result) {
   2591    return false;
   2592  }
   2593 
   2594  iter.storeInstructionResult(JS::ObjectValue(*result));
   2595  return true;
   2596 }
   2597 
   2598 bool MRest::writeRecoverData(CompactBufferWriter& writer) const {
   2599  MOZ_ASSERT(canRecoverOnBailout());
   2600  writer.writeUnsigned(uint32_t(RInstruction::Recover_Rest));
   2601  writer.writeUnsigned(numFormals());
   2602  return true;
   2603 }
   2604 
   2605 RRest::RRest(CompactBufferReader& reader) {
   2606  numFormals_ = reader.readUnsigned();
   2607 }
   2608 
   2609 bool RRest::recover(JSContext* cx, SnapshotIterator& iter) const {
   2610  JitFrameLayout* frame = iter.frame();
   2611 
   2612  // Int32 because |numActuals| is computed from MArgumentsLength.
   2613  uint32_t numActuals = iter.readInt32();
   2614  MOZ_ASSERT(numActuals == frame->numActualArgs());
   2615 
   2616  uint32_t numFormals = numFormals_;
   2617 
   2618  uint32_t length = std::max(numActuals, numFormals) - numFormals;
   2619  Value* src = frame->actualArgs() + numFormals;
   2620  JSObject* rest = jit::InitRestParameter(cx, length, src, nullptr);
   2621  if (!rest) {
   2622    return false;
   2623  }
   2624 
   2625  iter.storeInstructionResult(ObjectValue(*rest));
   2626  return true;
   2627 }
   2628 
   2629 bool MTypedArraySubarray::writeRecoverData(CompactBufferWriter& writer) const {
   2630  MOZ_ASSERT(canRecoverOnBailout());
   2631  writer.writeUnsigned(uint32_t(RInstruction::Recover_TypedArraySubarray));
   2632  return true;
   2633 }
   2634 
   2635 RTypedArraySubarray::RTypedArraySubarray(CompactBufferReader& reader) {}
   2636 
   2637 bool RTypedArraySubarray::recover(JSContext* cx, SnapshotIterator& iter) const {
   2638  Rooted<TypedArrayObject*> obj(cx, &iter.readObject()->as<TypedArrayObject>());
   2639  intptr_t start = iter.readIntPtr();
   2640  intptr_t length = iter.readIntPtr();
   2641 
   2642  auto* result = TypedArraySubarrayRecover(cx, obj, start, length);
   2643  if (!result) {
   2644    return false;
   2645  }
   2646 
   2647  iter.storeInstructionResult(ObjectValue(*result));
   2648  return true;
   2649 }