tor-browser

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

MIR.cpp (244742B)


      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/MIR.h"
      8 
      9 #include "mozilla/EndianUtils.h"
     10 #include "mozilla/FloatingPoint.h"
     11 #include "mozilla/MathAlgorithms.h"
     12 #include "mozilla/Maybe.h"
     13 
     14 #include <algorithm>
     15 #include <array>
     16 #include <utility>
     17 
     18 #include "jslibmath.h"
     19 #include "jsmath.h"
     20 #include "jsnum.h"
     21 
     22 #include "builtin/RegExp.h"
     23 #include "jit/AtomicOperations.h"
     24 #include "jit/CompileInfo.h"
     25 #include "jit/KnownClass.h"
     26 #include "jit/MIR-wasm.h"
     27 #include "jit/MIRGraph.h"
     28 #include "jit/RangeAnalysis.h"
     29 #include "jit/VMFunctions.h"
     30 #include "jit/WarpBuilderShared.h"
     31 #include "jit/WarpSnapshot.h"
     32 #include "js/Conversions.h"
     33 #include "js/experimental/JitInfo.h"  // JSJitInfo, JSTypedMethodJitInfo
     34 #include "js/ScalarType.h"            // js::Scalar::Type
     35 #include "util/Text.h"
     36 #include "util/Unicode.h"
     37 #include "vm/BigIntType.h"
     38 #include "vm/Float16.h"
     39 #include "vm/Iteration.h"    // js::NativeIterator
     40 #include "vm/PlainObject.h"  // js::PlainObject
     41 #include "vm/Uint8Clamped.h"
     42 
     43 #include "vm/BytecodeUtil-inl.h"
     44 #include "vm/JSAtomUtils-inl.h"  // TypeName
     45 
     46 using namespace js;
     47 using namespace js::jit;
     48 
     49 using JS::ToInt32;
     50 
     51 using mozilla::IsFloat32Representable;
     52 using mozilla::IsPowerOfTwo;
     53 using mozilla::NumbersAreIdentical;
     54 
     55 NON_GC_POINTER_TYPE_ASSERTIONS_GENERATED
     56 
     57 #ifdef DEBUG
     58 size_t MUse::index() const { return consumer()->indexOf(this); }
     59 #endif
     60 
     61 template <size_t Op>
     62 static void ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def,
     63                                      MInstruction* consumer) {
     64  MInstruction* replace = MToDouble::New(alloc, def);
     65  consumer->replaceOperand(Op, replace);
     66  consumer->block()->insertBefore(consumer, replace);
     67 }
     68 
     69 template <size_t Arity, size_t Index>
     70 static void ConvertOperandToDouble(MAryInstruction<Arity>* def,
     71                                   TempAllocator& alloc) {
     72  static_assert(Index < Arity);
     73  auto* operand = def->getOperand(Index);
     74  if (operand->type() == MIRType::Float32) {
     75    ConvertDefinitionToDouble<Index>(alloc, operand, def);
     76  }
     77 }
     78 
     79 template <size_t Arity, size_t... ISeq>
     80 static void ConvertOperandsToDouble(MAryInstruction<Arity>* def,
     81                                    TempAllocator& alloc,
     82                                    std::index_sequence<ISeq...>) {
     83  (ConvertOperandToDouble<Arity, ISeq>(def, alloc), ...);
     84 }
     85 
     86 template <size_t Arity>
     87 static void ConvertOperandsToDouble(MAryInstruction<Arity>* def,
     88                                    TempAllocator& alloc) {
     89  ConvertOperandsToDouble<Arity>(def, alloc, std::make_index_sequence<Arity>{});
     90 }
     91 
     92 template <size_t Arity, size_t... ISeq>
     93 static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def,
     94                                         std::index_sequence<ISeq...>) {
     95  return (def->getOperand(ISeq)->canProduceFloat32() && ...);
     96 }
     97 
     98 template <size_t Arity>
     99 static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def) {
    100  return AllOperandsCanProduceFloat32<Arity>(def,
    101                                             std::make_index_sequence<Arity>{});
    102 }
    103 
    104 static bool CheckUsesAreFloat32Consumers(const MInstruction* ins) {
    105  if (ins->isImplicitlyUsed()) {
    106    return false;
    107  }
    108  bool allConsumerUses = true;
    109  for (MUseDefIterator use(ins); allConsumerUses && use; use++) {
    110    allConsumerUses &= use.def()->canConsumeFloat32(use.use());
    111  }
    112  return allConsumerUses;
    113 }
    114 
    115 #ifdef JS_JITSPEW
    116 static const char* OpcodeName(MDefinition::Opcode op) {
    117  static const char* const names[] = {
    118 #  define NAME(x) #x,
    119      MIR_OPCODE_LIST(NAME)
    120 #  undef NAME
    121  };
    122  return names[unsigned(op)];
    123 }
    124 
    125 void MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op) {
    126  out.printf("%s", OpcodeName(op));
    127 }
    128 
    129 uint32_t js::jit::GetMBasicBlockId(const MBasicBlock* block) {
    130  return block->id();
    131 }
    132 #endif
    133 
    134 template <MIRType Type>
    135 static auto ToIntConstant(MConstant* cst) {
    136  MOZ_ASSERT(cst->type() == Type);
    137  if constexpr (Type == MIRType::Int32) {
    138    return cst->toInt32();
    139  } else if constexpr (Type == MIRType::Int64) {
    140    return cst->toInt64();
    141  } else if constexpr (Type == MIRType::IntPtr) {
    142    return cst->toIntPtr();
    143  }
    144 }
    145 
    146 template <MIRType Type, typename IntT>
    147 static MConstant* NewIntConstant(TempAllocator& alloc, IntT i) {
    148  if constexpr (Type == MIRType::Int32) {
    149    static_assert(std::is_same_v<IntT, int32_t>);
    150    return MConstant::NewInt32(alloc, i);
    151  } else if constexpr (Type == MIRType::Int64) {
    152    static_assert(std::is_same_v<IntT, int64_t>);
    153    return MConstant::NewInt64(alloc, i);
    154  } else if constexpr (Type == MIRType::IntPtr) {
    155    static_assert(std::is_same_v<IntT, intptr_t>);
    156    return MConstant::NewIntPtr(alloc, i);
    157  }
    158 }
    159 
    160 template <MIRType Type>
    161 static MConstant* EvaluateIntConstantOperands(TempAllocator& alloc,
    162                                              MBinaryInstruction* ins) {
    163  MDefinition* left = ins->lhs();
    164  MDefinition* right = ins->rhs();
    165 
    166  if (!left->isConstant() || !right->isConstant()) {
    167    return nullptr;
    168  }
    169 
    170  using IntT = decltype(ToIntConstant<Type>(nullptr));
    171  using UnsigedInt = std::make_unsigned_t<IntT>;
    172 
    173  // Right-hand side operand of shift must be non-negative and be less-than the
    174  // number of bits in the left-hand side operand. Otherwise the behavior is
    175  // undefined.
    176  static constexpr IntT shiftMask = (sizeof(IntT) * CHAR_BIT) - 1;
    177 
    178  IntT lhs = ToIntConstant<Type>(left->toConstant());
    179  IntT rhs = ToIntConstant<Type>(right->toConstant());
    180  IntT ret;
    181 
    182  switch (ins->op()) {
    183    case MDefinition::Opcode::BitAnd:
    184    case MDefinition::Opcode::BigIntPtrBitAnd:
    185      ret = lhs & rhs;
    186      break;
    187    case MDefinition::Opcode::BitOr:
    188    case MDefinition::Opcode::BigIntPtrBitOr:
    189      ret = lhs | rhs;
    190      break;
    191    case MDefinition::Opcode::BitXor:
    192    case MDefinition::Opcode::BigIntPtrBitXor:
    193      ret = lhs ^ rhs;
    194      break;
    195    case MDefinition::Opcode::Lsh:
    196      // Left-hand side operand must be non-negative, otherwise the behavior is
    197      // undefined. Cast to unsigned to ensure the behavior is always defined.
    198      //
    199      // Note: Cast to unsigned is no longer needed when compiling to C++20.
    200      ret = UnsigedInt(lhs) << (rhs & shiftMask);
    201      break;
    202    case MDefinition::Opcode::Rsh:
    203      // The result is implementation-defined if the left-hand side operand is
    204      // negative. Most implementations perform an arithmetic right-shift, which
    205      // we rely on here.
    206      //
    207      // Note: Guaranteed to be an arithmetic right-shift in C++20.
    208      ret = lhs >> (rhs & shiftMask);
    209      break;
    210    case MDefinition::Opcode::Ursh:
    211      // Decline folding if the output doesn't fit into a signed result and
    212      // bailouts are disabled. (Wasm has bailouts disabled.)
    213      if (lhs < 0 && rhs == 0 && !ins->toUrsh()->bailoutsDisabled()) {
    214        return nullptr;
    215      }
    216      ret = UnsigedInt(lhs) >> (UnsigedInt(rhs) & shiftMask);
    217      break;
    218    case MDefinition::Opcode::BigIntPtrLsh:
    219    case MDefinition::Opcode::BigIntPtrRsh: {
    220      // BigIntPtr shifts are special:
    221      // 1. Excess shift amounts produce BigInt larger than IntPtr.
    222      // 2. Negative shifts reverse the shift direction.
    223 
    224      // Decline folding for excess shift amounts.
    225      UnsigedInt shift = mozilla::Abs(rhs);
    226      if ((shift & shiftMask) != shift) {
    227        return nullptr;
    228      }
    229 
    230      bool isLsh = (ins->isBigIntPtrLsh() && rhs >= 0) ||
    231                   (ins->isBigIntPtrRsh() && rhs < 0);
    232      if (isLsh) {
    233        ret = UnsigedInt(lhs) << shift;
    234      } else {
    235        ret = lhs >> shift;
    236      }
    237      break;
    238    }
    239    case MDefinition::Opcode::Add:
    240    case MDefinition::Opcode::BigIntPtrAdd: {
    241      auto checked = mozilla::CheckedInt<IntT>(lhs) + rhs;
    242      if (!checked.isValid()) {
    243        return nullptr;
    244      }
    245      ret = checked.value();
    246      break;
    247    }
    248    case MDefinition::Opcode::Sub:
    249    case MDefinition::Opcode::BigIntPtrSub: {
    250      auto checked = mozilla::CheckedInt<IntT>(lhs) - rhs;
    251      if (!checked.isValid()) {
    252        return nullptr;
    253      }
    254      ret = checked.value();
    255      break;
    256    }
    257    case MDefinition::Opcode::Mul:
    258    case MDefinition::Opcode::BigIntPtrMul: {
    259      auto checked = mozilla::CheckedInt<IntT>(lhs) * rhs;
    260      if (!checked.isValid()) {
    261        return nullptr;
    262      }
    263      ret = checked.value();
    264      break;
    265    }
    266    case MDefinition::Opcode::Div: {
    267      if (ins->toDiv()->isUnsigned()) {
    268        auto checked =
    269            mozilla::CheckedInt<UnsigedInt>(UnsigedInt(lhs)) / UnsigedInt(rhs);
    270        if (!checked.isValid()) {
    271          return nullptr;
    272        }
    273        ret = IntT(checked.value());
    274        break;
    275      }
    276      [[fallthrough]];
    277    }
    278    case MDefinition::Opcode::BigIntPtrDiv: {
    279      auto checked = mozilla::CheckedInt<IntT>(lhs) / rhs;
    280      if (!checked.isValid()) {
    281        return nullptr;
    282      }
    283      ret = checked.value();
    284 
    285      // Decline folding if the numerator isn't evenly divisible by the
    286      // denominator. Only applies for non-truncating int32 division.
    287      if constexpr (Type == MIRType::Int32) {
    288        if (ret * rhs != lhs && !ins->toDiv()->isTruncated()) {
    289          return nullptr;
    290        }
    291      }
    292      break;
    293    }
    294    case MDefinition::Opcode::Mod: {
    295      if (ins->toMod()->isUnsigned()) {
    296        auto checked =
    297            mozilla::CheckedInt<UnsigedInt>(UnsigedInt(lhs)) % UnsigedInt(rhs);
    298        if (!checked.isValid()) {
    299          return nullptr;
    300        }
    301        ret = IntT(checked.value());
    302        break;
    303      }
    304      [[fallthrough]];
    305    }
    306    case MDefinition::Opcode::BigIntPtrMod: {
    307      auto checked = mozilla::CheckedInt<IntT>(lhs) % rhs;
    308      if (!checked.isValid()) {
    309        return nullptr;
    310      }
    311      ret = checked.value();
    312 
    313      // Decline folding if the result is negative zero. Only applies for
    314      // non-truncating int32 remainder.
    315      if constexpr (Type == MIRType::Int32) {
    316        if (ret == 0 && lhs < 0 && !ins->toMod()->isTruncated()) {
    317          return nullptr;
    318        }
    319      }
    320      break;
    321    }
    322    default:
    323      MOZ_CRASH("NYI");
    324  }
    325 
    326  return NewIntConstant<Type>(alloc, ret);
    327 }
    328 
    329 static MConstant* EvaluateInt32ConstantOperands(TempAllocator& alloc,
    330                                                MBinaryInstruction* ins) {
    331  return EvaluateIntConstantOperands<MIRType::Int32>(alloc, ins);
    332 }
    333 
    334 static MConstant* EvaluateInt64ConstantOperands(TempAllocator& alloc,
    335                                                MBinaryInstruction* ins) {
    336  return EvaluateIntConstantOperands<MIRType::Int64>(alloc, ins);
    337 }
    338 
    339 static MConstant* EvaluateIntPtrConstantOperands(TempAllocator& alloc,
    340                                                 MBinaryInstruction* ins) {
    341  return EvaluateIntConstantOperands<MIRType::IntPtr>(alloc, ins);
    342 }
    343 
    344 static MConstant* EvaluateConstantOperands(TempAllocator& alloc,
    345                                           MBinaryInstruction* ins) {
    346  MOZ_ASSERT(IsTypeRepresentableAsDouble(ins->type()));
    347 
    348  if (ins->type() == MIRType::Int32) {
    349    return EvaluateInt32ConstantOperands(alloc, ins);
    350  }
    351 
    352  MDefinition* left = ins->lhs();
    353  MDefinition* right = ins->rhs();
    354 
    355  MOZ_ASSERT(IsFloatingPointType(left->type()));
    356  MOZ_ASSERT(IsFloatingPointType(right->type()));
    357 
    358  if (!left->isConstant() || !right->isConstant()) {
    359    return nullptr;
    360  }
    361 
    362  double lhs = left->toConstant()->numberToDouble();
    363  double rhs = right->toConstant()->numberToDouble();
    364  double ret;
    365 
    366  switch (ins->op()) {
    367    case MDefinition::Opcode::Add:
    368      ret = lhs + rhs;
    369      break;
    370    case MDefinition::Opcode::Sub:
    371      ret = lhs - rhs;
    372      break;
    373    case MDefinition::Opcode::Mul:
    374      ret = lhs * rhs;
    375      break;
    376    case MDefinition::Opcode::Div:
    377      ret = NumberDiv(lhs, rhs);
    378      break;
    379    case MDefinition::Opcode::Mod:
    380      ret = NumberMod(lhs, rhs);
    381      break;
    382    default:
    383      MOZ_CRASH("NYI");
    384  }
    385 
    386  if (ins->type() == MIRType::Float32) {
    387    return MConstant::NewFloat32(alloc, float(ret));
    388  }
    389  MOZ_ASSERT(ins->type() == MIRType::Double);
    390  return MConstant::New(alloc, DoubleValue(ret));
    391 }
    392 
    393 static MConstant* EvaluateConstantNaNOperand(MBinaryInstruction* ins) {
    394  auto* left = ins->lhs();
    395  auto* right = ins->rhs();
    396 
    397  MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()));
    398  MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()));
    399  MOZ_ASSERT(left->type() == ins->type());
    400  MOZ_ASSERT(right->type() == ins->type());
    401 
    402  // Don't fold NaN if we can't return a floating point type.
    403  if (!IsFloatingPointType(ins->type())) {
    404    return nullptr;
    405  }
    406 
    407  MOZ_ASSERT(!left->isConstant() || !right->isConstant(),
    408             "EvaluateConstantOperands should have handled this case");
    409 
    410  // One operand must be a constant NaN.
    411  MConstant* cst;
    412  if (left->isConstant()) {
    413    cst = left->toConstant();
    414  } else if (right->isConstant()) {
    415    cst = right->toConstant();
    416  } else {
    417    return nullptr;
    418  }
    419  if (!std::isnan(cst->numberToDouble())) {
    420    return nullptr;
    421  }
    422 
    423  // Fold to constant NaN.
    424  return cst;
    425 }
    426 
    427 static MMul* EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) {
    428  // we should fold only when it is a floating point operation
    429  if (!IsFloatingPointType(ins->type())) {
    430    return nullptr;
    431  }
    432 
    433  MDefinition* left = ins->getOperand(0);
    434  MDefinition* right = ins->getOperand(1);
    435 
    436  if (!right->isConstant()) {
    437    return nullptr;
    438  }
    439 
    440  int32_t num;
    441  if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num)) {
    442    return nullptr;
    443  }
    444 
    445  // check if rhs is a power of two or zero
    446  if (num != 0 && !mozilla::IsPowerOfTwo(mozilla::Abs(num))) {
    447    return nullptr;
    448  }
    449 
    450  double ret = 1.0 / double(num);
    451 
    452  MConstant* foldedRhs;
    453  if (ins->type() == MIRType::Float32) {
    454    foldedRhs = MConstant::NewFloat32(alloc, ret);
    455  } else {
    456    foldedRhs = MConstant::NewDouble(alloc, ret);
    457  }
    458 
    459  MOZ_ASSERT(foldedRhs->type() == ins->type());
    460  ins->block()->insertBefore(ins, foldedRhs);
    461 
    462  MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type());
    463  mul->setMustPreserveNaN(ins->mustPreserveNaN());
    464  return mul;
    465 }
    466 
    467 #ifdef JS_JITSPEW
    468 const char* MDefinition::opName() const { return OpcodeName(op()); }
    469 
    470 void MDefinition::printName(GenericPrinter& out) const {
    471  PrintOpcodeName(out, op());
    472  out.printf("#%u", id());
    473 }
    474 #endif
    475 
    476 HashNumber MDefinition::valueHash() const {
    477  HashNumber out = HashNumber(op());
    478  for (size_t i = 0, e = numOperands(); i < e; i++) {
    479    out = addU32ToHash(out, getOperand(i)->id());
    480  }
    481  if (MDefinition* dep = dependency()) {
    482    out = addU32ToHash(out, dep->id());
    483  }
    484  return out;
    485 }
    486 
    487 HashNumber MNullaryInstruction::valueHash() const {
    488  HashNumber hash = HashNumber(op());
    489  if (MDefinition* dep = dependency()) {
    490    hash = addU32ToHash(hash, dep->id());
    491  }
    492  MOZ_ASSERT(hash == MDefinition::valueHash());
    493  return hash;
    494 }
    495 
    496 HashNumber MUnaryInstruction::valueHash() const {
    497  HashNumber hash = HashNumber(op());
    498  hash = addU32ToHash(hash, getOperand(0)->id());
    499  if (MDefinition* dep = dependency()) {
    500    hash = addU32ToHash(hash, dep->id());
    501  }
    502  MOZ_ASSERT(hash == MDefinition::valueHash());
    503  return hash;
    504 }
    505 
    506 HashNumber MBinaryInstruction::valueHash() const {
    507  HashNumber hash = HashNumber(op());
    508  hash = addU32ToHash(hash, getOperand(0)->id());
    509  hash = addU32ToHash(hash, getOperand(1)->id());
    510  if (MDefinition* dep = dependency()) {
    511    hash = addU32ToHash(hash, dep->id());
    512  }
    513  MOZ_ASSERT(hash == MDefinition::valueHash());
    514  return hash;
    515 }
    516 
    517 HashNumber MTernaryInstruction::valueHash() const {
    518  HashNumber hash = HashNumber(op());
    519  hash = addU32ToHash(hash, getOperand(0)->id());
    520  hash = addU32ToHash(hash, getOperand(1)->id());
    521  hash = addU32ToHash(hash, getOperand(2)->id());
    522  if (MDefinition* dep = dependency()) {
    523    hash = addU32ToHash(hash, dep->id());
    524  }
    525  MOZ_ASSERT(hash == MDefinition::valueHash());
    526  return hash;
    527 }
    528 
    529 HashNumber MQuaternaryInstruction::valueHash() const {
    530  HashNumber hash = HashNumber(op());
    531  hash = addU32ToHash(hash, getOperand(0)->id());
    532  hash = addU32ToHash(hash, getOperand(1)->id());
    533  hash = addU32ToHash(hash, getOperand(2)->id());
    534  hash = addU32ToHash(hash, getOperand(3)->id());
    535  if (MDefinition* dep = dependency()) {
    536    hash = addU32ToHash(hash, dep->id());
    537  }
    538  MOZ_ASSERT(hash == MDefinition::valueHash());
    539  return hash;
    540 }
    541 
    542 HashNumber MQuinaryInstruction::valueHash() const {
    543  HashNumber hash = HashNumber(op());
    544  hash = addU32ToHash(hash, getOperand(0)->id());
    545  hash = addU32ToHash(hash, getOperand(1)->id());
    546  hash = addU32ToHash(hash, getOperand(2)->id());
    547  hash = addU32ToHash(hash, getOperand(3)->id());
    548  hash = addU32ToHash(hash, getOperand(4)->id());
    549  if (MDefinition* dep = dependency()) {
    550    hash = addU32ToHash(hash, dep->id());
    551  }
    552  MOZ_ASSERT(hash == MDefinition::valueHash());
    553  return hash;
    554 }
    555 
    556 const MDefinition* MDefinition::skipObjectGuards() const {
    557  const MDefinition* result = this;
    558  // These instructions don't modify the object and just guard specific
    559  // properties.
    560  while (true) {
    561    if (result->isGuardShape()) {
    562      result = result->toGuardShape()->object();
    563      continue;
    564    }
    565    if (result->isGuardShapeList()) {
    566      result = result->toGuardShapeList()->object();
    567      continue;
    568    }
    569    if (result->isGuardMultipleShapes()) {
    570      result = result->toGuardMultipleShapes()->object();
    571      continue;
    572    }
    573    if (result->isGuardShapeListToOffset()) {
    574      result = result->toGuardShapeListToOffset()->object();
    575      continue;
    576    }
    577    if (result->isGuardMultipleShapesToOffset()) {
    578      result = result->toGuardMultipleShapesToOffset()->object();
    579      continue;
    580    }
    581    if (result->isGuardNullProto()) {
    582      result = result->toGuardNullProto()->object();
    583      continue;
    584    }
    585    if (result->isGuardProto()) {
    586      result = result->toGuardProto()->object();
    587      continue;
    588    }
    589 
    590    break;
    591  }
    592 
    593  return result;
    594 }
    595 
    596 bool MDefinition::congruentIfOperandsEqual(const MDefinition* ins) const {
    597  if (op() != ins->op()) {
    598    return false;
    599  }
    600 
    601  if (type() != ins->type()) {
    602    return false;
    603  }
    604 
    605  if (isEffectful() || ins->isEffectful()) {
    606    return false;
    607  }
    608 
    609  if (numOperands() != ins->numOperands()) {
    610    return false;
    611  }
    612 
    613  for (size_t i = 0, e = numOperands(); i < e; i++) {
    614    if (getOperand(i) != ins->getOperand(i)) {
    615      return false;
    616    }
    617  }
    618 
    619  return true;
    620 }
    621 
    622 MDefinition* MDefinition::foldsTo(TempAllocator& alloc) {
    623  // In the default case, there are no constants to fold.
    624  return this;
    625 }
    626 
    627 MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) {
    628  if (!dependency()) {
    629    return nullptr;
    630  }
    631 
    632  MDefinition* store = dependency();
    633  if (mightAlias(store) != AliasType::MustAlias) {
    634    return nullptr;
    635  }
    636 
    637  if (!store->block()->dominates(block())) {
    638    return nullptr;
    639  }
    640 
    641  MDefinition* value;
    642  switch (store->op()) {
    643    case Opcode::StoreFixedSlot:
    644      value = store->toStoreFixedSlot()->value();
    645      break;
    646    case Opcode::StoreDynamicSlot:
    647      value = store->toStoreDynamicSlot()->value();
    648      break;
    649    case Opcode::StoreElement:
    650      value = store->toStoreElement()->value();
    651      break;
    652    default:
    653      MOZ_CRASH("unknown store");
    654  }
    655 
    656  // If the type are matching then we return the value which is used as
    657  // argument of the store.
    658  if (value->type() != type()) {
    659    // If we expect to read a type which is more generic than the type seen
    660    // by the store, then we box the value used by the store.
    661    if (type() != MIRType::Value) {
    662      return nullptr;
    663    }
    664 
    665    MOZ_ASSERT(value->type() < MIRType::Value);
    666    MBox* box = MBox::New(alloc, value);
    667    value = box;
    668  }
    669 
    670  return value;
    671 }
    672 
    673 void MDefinition::analyzeEdgeCasesForward() {}
    674 
    675 void MDefinition::analyzeEdgeCasesBackward() {}
    676 
    677 void MInstruction::setResumePoint(MResumePoint* resumePoint) {
    678  MOZ_ASSERT(!resumePoint_);
    679  resumePoint_ = resumePoint;
    680  resumePoint_->setInstruction(this);
    681 }
    682 
    683 void MInstruction::stealResumePoint(MInstruction* other) {
    684  MResumePoint* resumePoint = other->resumePoint_;
    685  other->resumePoint_ = nullptr;
    686 
    687  resumePoint->resetInstruction();
    688  setResumePoint(resumePoint);
    689 }
    690 
    691 void MInstruction::moveResumePointAsEntry() {
    692  MOZ_ASSERT(isNop());
    693  block()->clearEntryResumePoint();
    694  block()->setEntryResumePoint(resumePoint_);
    695  resumePoint_->resetInstruction();
    696  resumePoint_ = nullptr;
    697 }
    698 
    699 void MInstruction::clearResumePoint() {
    700  resumePoint_->resetInstruction();
    701  block()->discardPreAllocatedResumePoint(resumePoint_);
    702  resumePoint_ = nullptr;
    703 }
    704 
    705 MDefinition* MTest::foldsDoubleNegation(TempAllocator& alloc) {
    706  MDefinition* op = getOperand(0);
    707 
    708  if (op->isNot()) {
    709    // If the operand of the Not is itself a Not, they cancel out.
    710    MDefinition* opop = op->getOperand(0);
    711    if (opop->isNot()) {
    712      return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse());
    713    }
    714    return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue());
    715  }
    716  return nullptr;
    717 }
    718 
    719 MDefinition* MTest::foldsConstant(TempAllocator& alloc) {
    720  MDefinition* op = getOperand(0);
    721  if (MConstant* opConst = op->maybeConstantValue()) {
    722    bool b;
    723    if (opConst->valueToBoolean(&b)) {
    724      return MGoto::New(alloc, b ? ifTrue() : ifFalse());
    725    }
    726  }
    727  return nullptr;
    728 }
    729 
    730 MDefinition* MTest::foldsTypes(TempAllocator& alloc) {
    731  MDefinition* op = getOperand(0);
    732 
    733  switch (op->type()) {
    734    case MIRType::Undefined:
    735    case MIRType::Null:
    736      return MGoto::New(alloc, ifFalse());
    737    case MIRType::Symbol:
    738      return MGoto::New(alloc, ifTrue());
    739    default:
    740      break;
    741  }
    742  return nullptr;
    743 }
    744 
    745 class UsesIterator {
    746  MDefinition* def_;
    747 
    748 public:
    749  explicit UsesIterator(MDefinition* def) : def_(def) {}
    750  auto begin() const { return def_->usesBegin(); }
    751  auto end() const { return def_->usesEnd(); }
    752 };
    753 
    754 static bool AllInstructionsDeadIfUnused(MBasicBlock* block) {
    755  for (auto* ins : *block) {
    756    // Skip trivial instructions.
    757    if (ins->isNop() || ins->isGoto()) {
    758      continue;
    759    }
    760 
    761    // All uses must be within the current block.
    762    for (auto* use : UsesIterator(ins)) {
    763      if (use->consumer()->block() != block) {
    764        return false;
    765      }
    766    }
    767 
    768    // All instructions within this block must be dead if unused.
    769    if (!DeadIfUnused(ins)) {
    770      return false;
    771    }
    772  }
    773  return true;
    774 }
    775 
    776 MDefinition* MTest::foldsNeedlessControlFlow(TempAllocator& alloc) {
    777  // All instructions within both successors need be dead if unused.
    778  if (!AllInstructionsDeadIfUnused(ifTrue()) ||
    779      !AllInstructionsDeadIfUnused(ifFalse())) {
    780    return nullptr;
    781  }
    782 
    783  // Both successors must have the same target successor.
    784  if (ifTrue()->numSuccessors() != 1 || ifFalse()->numSuccessors() != 1) {
    785    return nullptr;
    786  }
    787  if (ifTrue()->getSuccessor(0) != ifFalse()->getSuccessor(0)) {
    788    return nullptr;
    789  }
    790 
    791  // The target successor's phis must be redundant. Redundant phis should have
    792  // been removed in an earlier pass, so only check if any phis are present,
    793  // which is a stronger condition.
    794  if (ifTrue()->successorWithPhis()) {
    795    return nullptr;
    796  }
    797 
    798  return MGoto::New(alloc, ifTrue());
    799 }
    800 
    801 // If a test is dominated by either the true or false path of a previous test of
    802 // the same condition, then the test is redundant and can be converted into a
    803 // goto true or goto false, respectively.
    804 MDefinition* MTest::foldsRedundantTest(TempAllocator& alloc) {
    805  MBasicBlock* myBlock = this->block();
    806  MDefinition* originalInput = getOperand(0);
    807 
    808  // Handle single and double negatives. This ensures that we do not miss a
    809  // folding opportunity due to a condition being inverted.
    810  MDefinition* newInput = input();
    811  bool inverted = false;
    812  if (originalInput->isNot()) {
    813    newInput = originalInput->toNot()->input();
    814    inverted = true;
    815    if (originalInput->toNot()->input()->isNot()) {
    816      newInput = originalInput->toNot()->input()->toNot()->input();
    817      inverted = false;
    818    }
    819  }
    820 
    821  // The specific order of traversal does not matter. If there are multiple
    822  // dominating redundant tests, they will either agree on direction (in which
    823  // case we will prune the same way regardless of order), or they will
    824  // disagree, in which case we will eventually be marked entirely dead by the
    825  // folding of the redundant parent.
    826  for (MUseIterator i(newInput->usesBegin()), e(newInput->usesEnd()); i != e;
    827       ++i) {
    828    if (!i->consumer()->isDefinition()) {
    829      continue;
    830    }
    831    if (!i->consumer()->toDefinition()->isTest()) {
    832      continue;
    833    }
    834    MTest* otherTest = i->consumer()->toDefinition()->toTest();
    835    if (otherTest == this) {
    836      continue;
    837    }
    838 
    839    if (otherTest->ifFalse()->dominates(myBlock)) {
    840      // This test cannot be true, so fold to a goto false.
    841      return MGoto::New(alloc, inverted ? ifTrue() : ifFalse());
    842    }
    843    if (otherTest->ifTrue()->dominates(myBlock)) {
    844      // This test cannot be false, so fold to a goto true.
    845      return MGoto::New(alloc, inverted ? ifFalse() : ifTrue());
    846    }
    847  }
    848 
    849  return nullptr;
    850 }
    851 
    852 MDefinition* MTest::foldsTo(TempAllocator& alloc) {
    853  if (MDefinition* def = foldsRedundantTest(alloc)) {
    854    return def;
    855  }
    856 
    857  if (MDefinition* def = foldsDoubleNegation(alloc)) {
    858    return def;
    859  }
    860 
    861  if (MDefinition* def = foldsConstant(alloc)) {
    862    return def;
    863  }
    864 
    865  if (MDefinition* def = foldsTypes(alloc)) {
    866    return def;
    867  }
    868 
    869  if (MDefinition* def = foldsNeedlessControlFlow(alloc)) {
    870    return def;
    871  }
    872 
    873  return this;
    874 }
    875 
    876 AliasSet MThrow::getAliasSet() const {
    877  return AliasSet::Store(AliasSet::ExceptionState);
    878 }
    879 
    880 AliasSet MThrowWithStack::getAliasSet() const {
    881  return AliasSet::Store(AliasSet::ExceptionState);
    882 }
    883 
    884 AliasSet MNewArrayDynamicLength::getAliasSet() const {
    885  return AliasSet::Store(AliasSet::ExceptionState);
    886 }
    887 
    888 AliasSet MNewTypedArrayDynamicLength::getAliasSet() const {
    889  return AliasSet::Store(AliasSet::ExceptionState);
    890 }
    891 
    892 #ifdef JS_JITSPEW
    893 void MDefinition::printOpcode(GenericPrinter& out) const {
    894  PrintOpcodeName(out, op());
    895  if (numOperands() > 0) {
    896    out.printf(" <- ");
    897  }
    898  for (size_t j = 0, e = numOperands(); j < e; j++) {
    899    if (j > 0) {
    900      out.printf(", ");
    901    }
    902    if (getUseFor(j)->hasProducer()) {
    903      getOperand(j)->printName(out);
    904    } else {
    905      out.printf("(null)");
    906    }
    907  }
    908 }
    909 
    910 void MDefinition::dump(GenericPrinter& out) const {
    911  printName(out);
    912  out.printf(":%s", StringFromMIRType(type()));
    913  out.printf(" = ");
    914  printOpcode(out);
    915  out.printf("\n");
    916 
    917  if (isInstruction()) {
    918    if (MResumePoint* resume = toInstruction()->resumePoint()) {
    919      resume->dump(out);
    920    }
    921  }
    922 }
    923 
    924 void MDefinition::dump() const {
    925  Fprinter out(stderr);
    926  dump(out);
    927  out.finish();
    928 }
    929 
    930 void MDefinition::dumpLocation(GenericPrinter& out) const {
    931  MResumePoint* rp = nullptr;
    932  const char* linkWord = nullptr;
    933  if (isInstruction() && toInstruction()->resumePoint()) {
    934    rp = toInstruction()->resumePoint();
    935    linkWord = "at";
    936  } else {
    937    rp = block()->entryResumePoint();
    938    linkWord = "after";
    939  }
    940 
    941  while (rp) {
    942    JSScript* script = rp->block()->info().script();
    943    uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc());
    944    out.printf("  %s %s:%u\n", linkWord, script->filename(), lineno);
    945    rp = rp->caller();
    946    linkWord = "in";
    947  }
    948 }
    949 
    950 void MDefinition::dumpLocation() const {
    951  Fprinter out(stderr);
    952  dumpLocation(out);
    953  out.finish();
    954 }
    955 #endif
    956 
    957 #if defined(DEBUG) || defined(JS_JITSPEW)
    958 size_t MDefinition::useCount() const {
    959  size_t count = 0;
    960  for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
    961    count++;
    962  }
    963  return count;
    964 }
    965 
    966 size_t MDefinition::defUseCount() const {
    967  size_t count = 0;
    968  for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
    969    if ((*i)->consumer()->isDefinition()) {
    970      count++;
    971    }
    972  }
    973  return count;
    974 }
    975 #endif
    976 
    977 bool MDefinition::hasOneUse() const {
    978  MUseIterator i(uses_.begin());
    979  if (i == uses_.end()) {
    980    return false;
    981  }
    982  i++;
    983  return i == uses_.end();
    984 }
    985 
    986 bool MDefinition::hasOneDefUse() const {
    987  bool hasOneDefUse = false;
    988  for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
    989    if (!(*i)->consumer()->isDefinition()) {
    990      continue;
    991    }
    992 
    993    // We already have a definition use. So 1+
    994    if (hasOneDefUse) {
    995      return false;
    996    }
    997 
    998    // We saw one definition. Loop to test if there is another.
    999    hasOneDefUse = true;
   1000  }
   1001 
   1002  return hasOneDefUse;
   1003 }
   1004 
   1005 bool MDefinition::hasOneLiveDefUse() const {
   1006  bool hasOneDefUse = false;
   1007  for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
   1008    if (!(*i)->consumer()->isDefinition()) {
   1009      continue;
   1010    }
   1011 
   1012    MDefinition* def = (*i)->consumer()->toDefinition();
   1013    if (def->isRecoveredOnBailout()) {
   1014      continue;
   1015    }
   1016 
   1017    // We already have a definition use. So 1+
   1018    if (hasOneDefUse) {
   1019      return false;
   1020    }
   1021 
   1022    // We saw one definition. Loop to test if there is another.
   1023    hasOneDefUse = true;
   1024  }
   1025 
   1026  return hasOneDefUse;
   1027 }
   1028 
   1029 bool MDefinition::hasDefUses() const {
   1030  for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
   1031    if ((*i)->consumer()->isDefinition()) {
   1032      return true;
   1033    }
   1034  }
   1035 
   1036  return false;
   1037 }
   1038 
   1039 bool MDefinition::hasLiveDefUses() const {
   1040  for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
   1041    MNode* ins = (*i)->consumer();
   1042    if (ins->isDefinition()) {
   1043      if (!ins->toDefinition()->isRecoveredOnBailout()) {
   1044        return true;
   1045      }
   1046    } else {
   1047      MOZ_ASSERT(ins->isResumePoint());
   1048      if (!ins->toResumePoint()->isRecoverableOperand(*i)) {
   1049        return true;
   1050      }
   1051    }
   1052  }
   1053  return false;
   1054 }
   1055 
   1056 MDefinition* MDefinition::maybeSingleDefUse() const {
   1057  MUseDefIterator use(this);
   1058  if (!use) {
   1059    // No def-uses.
   1060    return nullptr;
   1061  }
   1062 
   1063  MDefinition* useDef = use.def();
   1064 
   1065  use++;
   1066  if (use) {
   1067    // More than one def-use.
   1068    return nullptr;
   1069  }
   1070 
   1071  return useDef;
   1072 }
   1073 
   1074 MDefinition* MDefinition::maybeMostRecentlyAddedDefUse() const {
   1075  MUseDefIterator use(this);
   1076  if (!use) {
   1077    // No def-uses.
   1078    return nullptr;
   1079  }
   1080 
   1081  MDefinition* mostRecentUse = use.def();
   1082 
   1083 #ifdef DEBUG
   1084  // This function relies on addUse adding new uses to the front of the list.
   1085  // Check this invariant by asserting the next few uses are 'older'. Skip this
   1086  // for phis because setBackedge can add a new use for a loop phi even if the
   1087  // loop body has a use with an id greater than the loop phi's id.
   1088  if (!mostRecentUse->isPhi()) {
   1089    static constexpr size_t NumUsesToCheck = 3;
   1090    use++;
   1091    for (size_t i = 0; use && i < NumUsesToCheck; i++, use++) {
   1092      MOZ_ASSERT(use.def()->id() <= mostRecentUse->id());
   1093    }
   1094  }
   1095 #endif
   1096 
   1097  return mostRecentUse;
   1098 }
   1099 
   1100 void MDefinition::replaceAllUsesWith(MDefinition* dom) {
   1101  for (size_t i = 0, e = numOperands(); i < e; ++i) {
   1102    getOperand(i)->setImplicitlyUsedUnchecked();
   1103  }
   1104 
   1105  justReplaceAllUsesWith(dom);
   1106 }
   1107 
   1108 void MDefinition::justReplaceAllUsesWith(MDefinition* dom) {
   1109  MOZ_ASSERT(dom != nullptr);
   1110  MOZ_ASSERT(dom != this);
   1111 
   1112  // Carry over the fact the value has uses which are no longer inspectable
   1113  // with the graph.
   1114  if (isImplicitlyUsed()) {
   1115    dom->setImplicitlyUsedUnchecked();
   1116  }
   1117 
   1118  for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) {
   1119    i->setProducerUnchecked(dom);
   1120  }
   1121  dom->uses_.takeElements(uses_);
   1122 }
   1123 
   1124 bool MDefinition::optimizeOutAllUses(TempAllocator& alloc) {
   1125  for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
   1126    MUse* use = *i++;
   1127    MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc);
   1128    if (!alloc.ensureBallast()) {
   1129      return false;
   1130    }
   1131 
   1132    // Update the resume point operand to use the optimized-out constant.
   1133    use->setProducerUnchecked(constant);
   1134    constant->addUseUnchecked(use);
   1135  }
   1136 
   1137  // Remove dangling pointers.
   1138  this->uses_.clear();
   1139  return true;
   1140 }
   1141 
   1142 void MDefinition::replaceAllLiveUsesWith(MDefinition* dom) {
   1143  for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
   1144    MUse* use = *i++;
   1145    MNode* consumer = use->consumer();
   1146    if (consumer->isResumePoint()) {
   1147      continue;
   1148    }
   1149    if (consumer->isDefinition() &&
   1150        consumer->toDefinition()->isRecoveredOnBailout()) {
   1151      continue;
   1152    }
   1153 
   1154    // Update the operand to use the dominating definition.
   1155    use->replaceProducer(dom);
   1156  }
   1157 }
   1158 
   1159 MConstant* MConstant::New(TempAllocator& alloc, const Value& v) {
   1160  return new (alloc) MConstant(alloc, v);
   1161 }
   1162 
   1163 MConstant* MConstant::New(TempAllocator::Fallible alloc, const Value& v) {
   1164  return new (alloc) MConstant(alloc.alloc, v);
   1165 }
   1166 
   1167 MConstant* MConstant::NewBoolean(TempAllocator& alloc, bool b) {
   1168  return new (alloc) MConstant(b);
   1169 }
   1170 
   1171 MConstant* MConstant::NewDouble(TempAllocator& alloc, double d) {
   1172  return new (alloc) MConstant(d);
   1173 }
   1174 
   1175 MConstant* MConstant::NewFloat32(TempAllocator& alloc, double d) {
   1176  MOZ_ASSERT(mozilla::IsFloat32Representable(d));
   1177  return new (alloc) MConstant(float(d));
   1178 }
   1179 
   1180 MConstant* MConstant::NewInt32(TempAllocator& alloc, int32_t i) {
   1181  return new (alloc) MConstant(i);
   1182 }
   1183 
   1184 MConstant* MConstant::NewInt64(TempAllocator& alloc, int64_t i) {
   1185  return new (alloc) MConstant(MIRType::Int64, i);
   1186 }
   1187 
   1188 MConstant* MConstant::NewIntPtr(TempAllocator& alloc, intptr_t i) {
   1189  return new (alloc) MConstant(MIRType::IntPtr, i);
   1190 }
   1191 
   1192 MConstant* MConstant::NewMagic(TempAllocator& alloc, JSWhyMagic m) {
   1193  return new (alloc) MConstant(alloc, MagicValue(m));
   1194 }
   1195 
   1196 MConstant* MConstant::NewNull(TempAllocator& alloc) {
   1197  return new (alloc) MConstant(MIRType::Null);
   1198 }
   1199 
   1200 MConstant* MConstant::NewObject(TempAllocator& alloc, JSObject* v) {
   1201  return new (alloc) MConstant(v);
   1202 }
   1203 
   1204 MConstant* MConstant::NewShape(TempAllocator& alloc, Shape* s) {
   1205  return new (alloc) MConstant(s);
   1206 }
   1207 
   1208 MConstant* MConstant::NewString(TempAllocator& alloc, JSString* s) {
   1209  return new (alloc) MConstant(alloc, StringValue(s));
   1210 }
   1211 
   1212 MConstant* MConstant::NewUndefined(TempAllocator& alloc) {
   1213  return new (alloc) MConstant(MIRType::Undefined);
   1214 }
   1215 
   1216 static MIRType MIRTypeFromValue(const js::Value& vp) {
   1217  if (vp.isDouble()) {
   1218    return MIRType::Double;
   1219  }
   1220  if (vp.isMagic()) {
   1221    switch (vp.whyMagic()) {
   1222      case JS_OPTIMIZED_OUT:
   1223        return MIRType::MagicOptimizedOut;
   1224      case JS_ELEMENTS_HOLE:
   1225        return MIRType::MagicHole;
   1226      case JS_IS_CONSTRUCTING:
   1227        return MIRType::MagicIsConstructing;
   1228      case JS_UNINITIALIZED_LEXICAL:
   1229        return MIRType::MagicUninitializedLexical;
   1230      default:
   1231        MOZ_ASSERT_UNREACHABLE("Unexpected magic constant");
   1232    }
   1233  }
   1234  return MIRTypeFromValueType(vp.extractNonDoubleType());
   1235 }
   1236 
   1237 MConstant::MConstant(TempAllocator& alloc, const js::Value& vp)
   1238    : MNullaryInstruction(classOpcode) {
   1239  setResultType(MIRTypeFromValue(vp));
   1240 
   1241  MOZ_ASSERT(payload_.asBits == 0);
   1242 
   1243  switch (type()) {
   1244    case MIRType::Undefined:
   1245    case MIRType::Null:
   1246      break;
   1247    case MIRType::Boolean:
   1248      payload_.b = vp.toBoolean();
   1249      break;
   1250    case MIRType::Int32:
   1251      payload_.i32 = vp.toInt32();
   1252      break;
   1253    case MIRType::Double:
   1254      payload_.d = vp.toDouble();
   1255      break;
   1256    case MIRType::String: {
   1257      JSString* str = vp.toString();
   1258      MOZ_ASSERT(!IsInsideNursery(str));
   1259      payload_.str = &str->asOffThreadAtom();
   1260      break;
   1261    }
   1262    case MIRType::Symbol:
   1263      payload_.sym = vp.toSymbol();
   1264      break;
   1265    case MIRType::BigInt:
   1266      MOZ_ASSERT(!IsInsideNursery(vp.toBigInt()));
   1267      payload_.bi = vp.toBigInt();
   1268      break;
   1269    case MIRType::Object:
   1270      MOZ_ASSERT(!IsInsideNursery(&vp.toObject()));
   1271      payload_.obj = &vp.toObject();
   1272      break;
   1273    case MIRType::MagicOptimizedOut:
   1274    case MIRType::MagicHole:
   1275    case MIRType::MagicIsConstructing:
   1276    case MIRType::MagicUninitializedLexical:
   1277      break;
   1278    default:
   1279      MOZ_CRASH("Unexpected type");
   1280  }
   1281 
   1282  setMovable();
   1283 }
   1284 
   1285 MConstant::MConstant(JSObject* obj) : MConstant(MIRType::Object) {
   1286  MOZ_ASSERT(!IsInsideNursery(obj));
   1287  payload_.obj = obj;
   1288 }
   1289 
   1290 MConstant::MConstant(Shape* shape) : MConstant(MIRType::Shape) {
   1291  payload_.shape = shape;
   1292 }
   1293 
   1294 #ifdef DEBUG
   1295 void MConstant::assertInitializedPayload() const {
   1296  // valueHash() and equals() expect the unused payload bits to be
   1297  // initialized to zero. Assert this in debug builds.
   1298 
   1299  switch (type()) {
   1300    case MIRType::Int32:
   1301    case MIRType::Float32:
   1302 #  if MOZ_LITTLE_ENDIAN()
   1303      MOZ_ASSERT((payload_.asBits >> 32) == 0);
   1304 #  else
   1305      MOZ_ASSERT((payload_.asBits << 32) == 0);
   1306 #  endif
   1307      break;
   1308    case MIRType::Boolean:
   1309 #  if MOZ_LITTLE_ENDIAN()
   1310      MOZ_ASSERT((payload_.asBits >> 1) == 0);
   1311 #  else
   1312      MOZ_ASSERT((payload_.asBits & ~(1ULL << 56)) == 0);
   1313 #  endif
   1314      break;
   1315    case MIRType::Double:
   1316    case MIRType::Int64:
   1317      break;
   1318    case MIRType::String:
   1319    case MIRType::Object:
   1320    case MIRType::Symbol:
   1321    case MIRType::BigInt:
   1322    case MIRType::IntPtr:
   1323    case MIRType::Shape:
   1324 #  if MOZ_LITTLE_ENDIAN()
   1325      MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0);
   1326 #  else
   1327      MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits << 32) == 0);
   1328 #  endif
   1329      break;
   1330    default:
   1331      MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()));
   1332      MOZ_ASSERT(payload_.asBits == 0);
   1333      break;
   1334  }
   1335 }
   1336 #endif
   1337 
   1338 HashNumber MConstant::valueHash() const {
   1339  static_assert(sizeof(Payload) == sizeof(uint64_t),
   1340                "Code below assumes payload fits in 64 bits");
   1341 
   1342  assertInitializedPayload();
   1343  return ConstantValueHash(type(), payload_.asBits);
   1344 }
   1345 
   1346 HashNumber MConstantProto::valueHash() const {
   1347  HashNumber hash = protoObject()->valueHash();
   1348  const MDefinition* receiverObject = getReceiverObject();
   1349  if (receiverObject) {
   1350    hash = addU32ToHash(hash, receiverObject->id());
   1351  }
   1352  return hash;
   1353 }
   1354 
   1355 bool MConstant::congruentTo(const MDefinition* ins) const {
   1356  return ins->isConstant() && equals(ins->toConstant());
   1357 }
   1358 
   1359 #ifdef JS_JITSPEW
   1360 void MConstant::printOpcode(GenericPrinter& out) const {
   1361  PrintOpcodeName(out, op());
   1362  out.printf(" ");
   1363  switch (type()) {
   1364    case MIRType::Undefined:
   1365      out.printf("undefined");
   1366      break;
   1367    case MIRType::Null:
   1368      out.printf("null");
   1369      break;
   1370    case MIRType::Boolean:
   1371      out.printf(toBoolean() ? "true" : "false");
   1372      break;
   1373    case MIRType::Int32:
   1374      out.printf("0x%x", uint32_t(toInt32()));
   1375      break;
   1376    case MIRType::Int64:
   1377      out.printf("0x%" PRIx64, uint64_t(toInt64()));
   1378      break;
   1379    case MIRType::IntPtr:
   1380      out.printf("0x%" PRIxPTR, uintptr_t(toIntPtr()));
   1381      break;
   1382    case MIRType::Double:
   1383      out.printf("%.16g", toDouble());
   1384      break;
   1385    case MIRType::Float32: {
   1386      float val = toFloat32();
   1387      out.printf("%.16g", val);
   1388      break;
   1389    }
   1390    case MIRType::Object:
   1391      if (toObject().is<JSFunction>()) {
   1392        JSFunction* fun = &toObject().as<JSFunction>();
   1393        if (fun->maybePartialDisplayAtom()) {
   1394          out.put("function ");
   1395          EscapedStringPrinter(out, fun->maybePartialDisplayAtom(), 0);
   1396        } else {
   1397          out.put("unnamed function");
   1398        }
   1399        if (fun->hasBaseScript()) {
   1400          BaseScript* script = fun->baseScript();
   1401          out.printf(" (%s:%u)", script->filename() ? script->filename() : "",
   1402                     script->lineno());
   1403        }
   1404        out.printf(" at %p", (void*)fun);
   1405        break;
   1406      }
   1407      out.printf("object %p (%s)", (void*)&toObject(),
   1408                 toObject().getClass()->name);
   1409      break;
   1410    case MIRType::Symbol:
   1411      out.printf("symbol at %p", (void*)toSymbol());
   1412      break;
   1413    case MIRType::BigInt:
   1414      out.printf("BigInt at %p", (void*)toBigInt());
   1415      break;
   1416    case MIRType::String:
   1417      out.printf("string %p", (void*)toString());
   1418      break;
   1419    case MIRType::Shape:
   1420      out.printf("shape at %p", (void*)toShape());
   1421      break;
   1422    case MIRType::MagicHole:
   1423      out.printf("magic hole");
   1424      break;
   1425    case MIRType::MagicIsConstructing:
   1426      out.printf("magic is-constructing");
   1427      break;
   1428    case MIRType::MagicOptimizedOut:
   1429      out.printf("magic optimized-out");
   1430      break;
   1431    case MIRType::MagicUninitializedLexical:
   1432      out.printf("magic uninitialized-lexical");
   1433      break;
   1434    default:
   1435      MOZ_CRASH("unexpected type");
   1436  }
   1437 }
   1438 #endif
   1439 
   1440 bool MConstant::canProduceFloat32() const {
   1441  if (!isTypeRepresentableAsDouble()) {
   1442    return false;
   1443  }
   1444 
   1445  if (type() == MIRType::Int32) {
   1446    return IsFloat32Representable(static_cast<double>(toInt32()));
   1447  }
   1448  if (type() == MIRType::Double) {
   1449    return IsFloat32Representable(toDouble());
   1450  }
   1451  MOZ_ASSERT(type() == MIRType::Float32);
   1452  return true;
   1453 }
   1454 
   1455 Value MConstant::toJSValue() const {
   1456  // Wasm has types like int64 that cannot be stored as js::Value. It also
   1457  // doesn't want the NaN canonicalization enforced by js::Value.
   1458  MOZ_ASSERT(!IsCompilingWasm());
   1459 
   1460  switch (type()) {
   1461    case MIRType::Undefined:
   1462      return UndefinedValue();
   1463    case MIRType::Null:
   1464      return NullValue();
   1465    case MIRType::Boolean:
   1466      return BooleanValue(toBoolean());
   1467    case MIRType::Int32:
   1468      return Int32Value(toInt32());
   1469    case MIRType::Double:
   1470      return DoubleValue(toDouble());
   1471    case MIRType::Float32:
   1472      return Float32Value(toFloat32());
   1473    case MIRType::String:
   1474      return StringValue(toString()->unwrap());
   1475    case MIRType::Symbol:
   1476      return SymbolValue(toSymbol());
   1477    case MIRType::BigInt:
   1478      return BigIntValue(toBigInt());
   1479    case MIRType::Object:
   1480      return ObjectValue(toObject());
   1481    case MIRType::Shape:
   1482      return PrivateGCThingValue(toShape());
   1483    case MIRType::MagicOptimizedOut:
   1484      return MagicValue(JS_OPTIMIZED_OUT);
   1485    case MIRType::MagicHole:
   1486      return MagicValue(JS_ELEMENTS_HOLE);
   1487    case MIRType::MagicIsConstructing:
   1488      return MagicValue(JS_IS_CONSTRUCTING);
   1489    case MIRType::MagicUninitializedLexical:
   1490      return MagicValue(JS_UNINITIALIZED_LEXICAL);
   1491    default:
   1492      MOZ_CRASH("Unexpected type");
   1493  }
   1494 }
   1495 
   1496 bool MConstant::valueToBoolean(bool* res) const {
   1497  switch (type()) {
   1498    case MIRType::Boolean:
   1499      *res = toBoolean();
   1500      return true;
   1501    case MIRType::Int32:
   1502      *res = toInt32() != 0;
   1503      return true;
   1504    case MIRType::Int64:
   1505      *res = toInt64() != 0;
   1506      return true;
   1507    case MIRType::IntPtr:
   1508      *res = toIntPtr() != 0;
   1509      return true;
   1510    case MIRType::Double:
   1511      *res = !std::isnan(toDouble()) && toDouble() != 0.0;
   1512      return true;
   1513    case MIRType::Float32:
   1514      *res = !std::isnan(toFloat32()) && toFloat32() != 0.0f;
   1515      return true;
   1516    case MIRType::Null:
   1517    case MIRType::Undefined:
   1518      *res = false;
   1519      return true;
   1520    case MIRType::Symbol:
   1521      *res = true;
   1522      return true;
   1523    case MIRType::BigInt:
   1524      *res = !toBigInt()->isZero();
   1525      return true;
   1526    case MIRType::String:
   1527      *res = toString()->length() != 0;
   1528      return true;
   1529    case MIRType::Object:
   1530      // TODO(Warp): Lazy groups have been removed.
   1531      // We have to call EmulatesUndefined but that reads obj->group->clasp
   1532      // and so it's racy when the object has a lazy group. The main callers
   1533      // of this (MTest, MNot) already know how to fold the object case, so
   1534      // just give up.
   1535      return false;
   1536    default:
   1537      MOZ_ASSERT(IsMagicType(type()));
   1538      return false;
   1539  }
   1540 }
   1541 
   1542 #ifdef JS_JITSPEW
   1543 void MControlInstruction::printOpcode(GenericPrinter& out) const {
   1544  MDefinition::printOpcode(out);
   1545  if (numSuccessors() > 0) {
   1546    out.printf(" -> ");
   1547  }
   1548  for (size_t j = 0; j < numSuccessors(); j++) {
   1549    if (j > 0) {
   1550      out.printf(", ");
   1551    }
   1552    if (getSuccessor(j)) {
   1553      out.printf("block %u", getSuccessor(j)->id());
   1554    } else {
   1555      out.printf("(null-to-be-patched)");
   1556    }
   1557  }
   1558 }
   1559 
   1560 void MCompare::printOpcode(GenericPrinter& out) const {
   1561  MDefinition::printOpcode(out);
   1562  out.printf(" %s", CodeName(jsop()));
   1563 }
   1564 
   1565 void MTypeOfIs::printOpcode(GenericPrinter& out) const {
   1566  MDefinition::printOpcode(out);
   1567  out.printf(" %s", CodeName(jsop()));
   1568 
   1569  const char* name = "";
   1570  switch (jstype()) {
   1571    case JSTYPE_UNDEFINED:
   1572      name = "undefined";
   1573      break;
   1574    case JSTYPE_OBJECT:
   1575      name = "object";
   1576      break;
   1577    case JSTYPE_FUNCTION:
   1578      name = "function";
   1579      break;
   1580    case JSTYPE_STRING:
   1581      name = "string";
   1582      break;
   1583    case JSTYPE_NUMBER:
   1584      name = "number";
   1585      break;
   1586    case JSTYPE_BOOLEAN:
   1587      name = "boolean";
   1588      break;
   1589    case JSTYPE_SYMBOL:
   1590      name = "symbol";
   1591      break;
   1592    case JSTYPE_BIGINT:
   1593      name = "bigint";
   1594      break;
   1595    case JSTYPE_LIMIT:
   1596      MOZ_CRASH("Unexpected type");
   1597  }
   1598  out.printf(" '%s'", name);
   1599 }
   1600 
   1601 void MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const {
   1602  MDefinition::printOpcode(out);
   1603  out.printf(" %s", Scalar::name(storageType()));
   1604 }
   1605 
   1606 void MLoadDataViewElement::printOpcode(GenericPrinter& out) const {
   1607  MDefinition::printOpcode(out);
   1608  out.printf(" %s", Scalar::name(storageType()));
   1609 }
   1610 
   1611 void MAssertRange::printOpcode(GenericPrinter& out) const {
   1612  MDefinition::printOpcode(out);
   1613  out.put(" ");
   1614  assertedRange()->dump(out);
   1615 }
   1616 
   1617 void MNearbyInt::printOpcode(GenericPrinter& out) const {
   1618  MDefinition::printOpcode(out);
   1619  const char* roundingModeStr = nullptr;
   1620  switch (roundingMode_) {
   1621    case RoundingMode::Up:
   1622      roundingModeStr = "(up)";
   1623      break;
   1624    case RoundingMode::Down:
   1625      roundingModeStr = "(down)";
   1626      break;
   1627    case RoundingMode::NearestTiesToEven:
   1628      roundingModeStr = "(nearest ties even)";
   1629      break;
   1630    case RoundingMode::TowardsZero:
   1631      roundingModeStr = "(towards zero)";
   1632      break;
   1633  }
   1634  out.printf(" %s", roundingModeStr);
   1635 }
   1636 #endif
   1637 
   1638 AliasSet MRandom::getAliasSet() const { return AliasSet::Store(AliasSet::RNG); }
   1639 
   1640 MDefinition* MSign::foldsTo(TempAllocator& alloc) {
   1641  MDefinition* input = getOperand(0);
   1642  if (!input->isConstant() ||
   1643      !input->toConstant()->isTypeRepresentableAsDouble()) {
   1644    return this;
   1645  }
   1646 
   1647  double in = input->toConstant()->numberToDouble();
   1648  double out = js::math_sign_impl(in);
   1649 
   1650  if (type() == MIRType::Int32) {
   1651    // Decline folding if this is an int32 operation, but the result type
   1652    // isn't an int32.
   1653    int32_t i;
   1654    if (!mozilla::NumberIsInt32(out, &i)) {
   1655      return this;
   1656    }
   1657    return MConstant::NewInt32(alloc, i);
   1658  }
   1659 
   1660  return MConstant::NewDouble(alloc, out);
   1661 }
   1662 
   1663 const char* MMathFunction::FunctionName(UnaryMathFunction function) {
   1664  return GetUnaryMathFunctionName(function);
   1665 }
   1666 
   1667 #ifdef JS_JITSPEW
   1668 void MMathFunction::printOpcode(GenericPrinter& out) const {
   1669  MDefinition::printOpcode(out);
   1670  out.printf(" %s", FunctionName(function()));
   1671 }
   1672 #endif
   1673 
   1674 MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) {
   1675  MDefinition* input = getOperand(0);
   1676  if (!input->isConstant() ||
   1677      !input->toConstant()->isTypeRepresentableAsDouble()) {
   1678    return this;
   1679  }
   1680 
   1681  UnaryMathFunctionType funPtr = GetUnaryMathFunctionPtr(function());
   1682 
   1683  double in = input->toConstant()->numberToDouble();
   1684 
   1685  // The function pointer call can't GC.
   1686  JS::AutoSuppressGCAnalysis nogc;
   1687  double out = funPtr(in);
   1688 
   1689  if (input->type() == MIRType::Float32) {
   1690    return MConstant::NewFloat32(alloc, out);
   1691  }
   1692  return MConstant::NewDouble(alloc, out);
   1693 }
   1694 
   1695 MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) {
   1696  MDefinition* input = getOperand(0);
   1697  if (!input->isConstant() || input->type() != MIRType::Int32) {
   1698    return this;
   1699  }
   1700 
   1701  int32_t i = input->toConstant()->toInt32();
   1702  return MConstant::NewBoolean(alloc, AtomicOperations::isLockfreeJS(i));
   1703 }
   1704 
   1705 // Define |THIS_SLOT| as part of this translation unit, as it is used to
   1706 // specialized the parameterized |New| function calls introduced by
   1707 // TRIVIAL_NEW_WRAPPERS.
   1708 const int32_t MParameter::THIS_SLOT;
   1709 
   1710 #ifdef JS_JITSPEW
   1711 void MParameter::printOpcode(GenericPrinter& out) const {
   1712  PrintOpcodeName(out, op());
   1713  if (index() == THIS_SLOT) {
   1714    out.printf(" THIS_SLOT");
   1715  } else {
   1716    out.printf(" %d", index());
   1717  }
   1718 }
   1719 #endif
   1720 
   1721 HashNumber MParameter::valueHash() const {
   1722  HashNumber hash = MNullaryInstruction::valueHash();
   1723  hash = addU32ToHash(hash, index_);
   1724  return hash;
   1725 }
   1726 
   1727 bool MParameter::congruentTo(const MDefinition* ins) const {
   1728  if (!ins->isParameter()) {
   1729    return false;
   1730  }
   1731 
   1732  return ins->toParameter()->index() == index_;
   1733 }
   1734 
   1735 WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs,
   1736                                 FunctionFlags flags)
   1737    : nativeFun_(nativeFun), nargs_(nargs), flags_(flags) {
   1738  MOZ_ASSERT_IF(nativeFun, isNativeWithoutJitEntry());
   1739 
   1740 #ifdef DEBUG
   1741  // If we are not running off-main thread we can assert that the
   1742  // metadata is consistent.
   1743  if (!CanUseExtraThreads() && nativeFun) {
   1744    MOZ_ASSERT(nativeFun->nargs() == nargs);
   1745 
   1746    MOZ_ASSERT(nativeFun->isNativeWithoutJitEntry() ==
   1747               isNativeWithoutJitEntry());
   1748    MOZ_ASSERT(nativeFun->hasJitEntry() == hasJitEntry());
   1749    MOZ_ASSERT(nativeFun->isConstructor() == isConstructor());
   1750    MOZ_ASSERT(nativeFun->isClassConstructor() == isClassConstructor());
   1751  }
   1752 #endif
   1753 }
   1754 
   1755 MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, size_t maxArgc,
   1756                  size_t numActualArgs, bool construct, bool ignoresReturnValue,
   1757                  bool isDOMCall, mozilla::Maybe<DOMObjectKind> objectKind,
   1758                  mozilla::Maybe<gc::Heap> initialHeap) {
   1759  MOZ_ASSERT(isDOMCall == objectKind.isSome());
   1760  MOZ_ASSERT(isDOMCall == initialHeap.isSome());
   1761 
   1762  MOZ_ASSERT(maxArgc >= numActualArgs);
   1763  MCall* ins;
   1764  if (isDOMCall) {
   1765    MOZ_ASSERT(!construct);
   1766    ins = new (alloc)
   1767        MCallDOMNative(target, numActualArgs, *objectKind, *initialHeap);
   1768  } else {
   1769    ins =
   1770        new (alloc) MCall(target, numActualArgs, construct, ignoresReturnValue);
   1771  }
   1772  if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) {
   1773    return nullptr;
   1774  }
   1775  return ins;
   1776 }
   1777 
   1778 AliasSet MCallDOMNative::getAliasSet() const {
   1779  const JSJitInfo* jitInfo = getJitInfo();
   1780 
   1781  // If we don't know anything about the types of our arguments, we have to
   1782  // assume that type-coercions can have side-effects, so we need to alias
   1783  // everything.
   1784  if (jitInfo->aliasSet() == JSJitInfo::AliasEverything ||
   1785      !jitInfo->isTypedMethodJitInfo()) {
   1786    return AliasSet::Store(AliasSet::Any);
   1787  }
   1788 
   1789  uint32_t argIndex = 0;
   1790  const JSTypedMethodJitInfo* methodInfo =
   1791      reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
   1792  for (const JSJitInfo::ArgType* argType = methodInfo->argTypes;
   1793       *argType != JSJitInfo::ArgTypeListEnd; ++argType, ++argIndex) {
   1794    if (argIndex >= numActualArgs()) {
   1795      // Passing through undefined can't have side-effects
   1796      continue;
   1797    }
   1798    // getArg(0) is "this", so skip it
   1799    MDefinition* arg = getArg(argIndex + 1);
   1800    MIRType actualType = arg->type();
   1801    // The only way to reliably avoid side-effects given the information we
   1802    // have here is if we're passing in a known primitive value to an
   1803    // argument that expects a primitive value.
   1804    //
   1805    // XXXbz maybe we need to communicate better information.  For example,
   1806    // a sequence argument will sort of unavoidably have side effects, while
   1807    // a typed array argument won't have any, but both are claimed to be
   1808    // JSJitInfo::Object.  But if we do that, we need to watch out for our
   1809    // movability/DCE-ability bits: if we have an arg type that can reliably
   1810    // throw an exception on conversion, that might not affect our alias set
   1811    // per se, but it should prevent us being moved or DCE-ed, unless we
   1812    // know the incoming things match that arg type and won't throw.
   1813    //
   1814    if ((actualType == MIRType::Value || actualType == MIRType::Object) ||
   1815        (*argType & JSJitInfo::Object)) {
   1816      return AliasSet::Store(AliasSet::Any);
   1817    }
   1818  }
   1819 
   1820  // We checked all the args, and they check out.  So we only alias DOM
   1821  // mutations or alias nothing, depending on the alias set in the jitinfo.
   1822  if (jitInfo->aliasSet() == JSJitInfo::AliasNone) {
   1823    return AliasSet::None();
   1824  }
   1825 
   1826  MOZ_ASSERT(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets);
   1827  return AliasSet::Load(AliasSet::DOMProperty);
   1828 }
   1829 
   1830 void MCallDOMNative::computeMovable() {
   1831  // We are movable if the jitinfo says we can be and if we're also not
   1832  // effectful.  The jitinfo can't check for the latter, since it depends on
   1833  // the types of our arguments.
   1834  const JSJitInfo* jitInfo = getJitInfo();
   1835 
   1836  MOZ_ASSERT_IF(jitInfo->isMovable,
   1837                jitInfo->aliasSet() != JSJitInfo::AliasEverything);
   1838 
   1839  if (jitInfo->isMovable && !isEffectful()) {
   1840    setMovable();
   1841  }
   1842 }
   1843 
   1844 bool MCallDOMNative::congruentTo(const MDefinition* ins) const {
   1845  if (!isMovable()) {
   1846    return false;
   1847  }
   1848 
   1849  if (!ins->isCall()) {
   1850    return false;
   1851  }
   1852 
   1853  const MCall* call = ins->toCall();
   1854 
   1855  if (!call->isCallDOMNative()) {
   1856    return false;
   1857  }
   1858 
   1859  if (getSingleTarget() != call->getSingleTarget()) {
   1860    return false;
   1861  }
   1862 
   1863  if (isConstructing() != call->isConstructing()) {
   1864    return false;
   1865  }
   1866 
   1867  if (numActualArgs() != call->numActualArgs()) {
   1868    return false;
   1869  }
   1870 
   1871  if (!congruentIfOperandsEqual(call)) {
   1872    return false;
   1873  }
   1874 
   1875  // The other call had better be movable at this point!
   1876  MOZ_ASSERT(call->isMovable());
   1877 
   1878  return true;
   1879 }
   1880 
   1881 const JSJitInfo* MCallDOMNative::getJitInfo() const {
   1882  MOZ_ASSERT(getSingleTarget()->hasJitInfo());
   1883  return getSingleTarget()->jitInfo();
   1884 }
   1885 
   1886 MCallClassHook* MCallClassHook::New(TempAllocator& alloc, JSNative target,
   1887                                    uint32_t argc, bool constructing) {
   1888  auto* ins = new (alloc) MCallClassHook(target, constructing);
   1889 
   1890  // Add callee + |this| + (if constructing) newTarget.
   1891  uint32_t numOperands = 2 + argc + constructing;
   1892 
   1893  if (!ins->init(alloc, numOperands)) {
   1894    return nullptr;
   1895  }
   1896 
   1897  return ins;
   1898 }
   1899 
   1900 MDefinition* MStringLength::foldsTo(TempAllocator& alloc) {
   1901  if (string()->isConstant()) {
   1902    JSOffThreadAtom* str = string()->toConstant()->toString();
   1903    return MConstant::NewInt32(alloc, str->length());
   1904  }
   1905 
   1906  // MFromCharCode returns a one-element string.
   1907  if (string()->isFromCharCode()) {
   1908    return MConstant::NewInt32(alloc, 1);
   1909  }
   1910 
   1911  return this;
   1912 }
   1913 
   1914 MDefinition* MConcat::foldsTo(TempAllocator& alloc) {
   1915  if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty()) {
   1916    return rhs();
   1917  }
   1918 
   1919  if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty()) {
   1920    return lhs();
   1921  }
   1922 
   1923  return this;
   1924 }
   1925 
   1926 MDefinition* MStringConvertCase::foldsTo(TempAllocator& alloc) {
   1927  MDefinition* string = this->string();
   1928 
   1929  // Handle the pattern |str[idx].toUpperCase()| and simplify it from
   1930  // |StringConvertCase(FromCharCode(CharCodeAt(str, idx)))| to just
   1931  // |CharCodeConvertCase(CharCodeAt(str, idx))|.
   1932  if (string->isFromCharCode()) {
   1933    auto* charCode = string->toFromCharCode()->code();
   1934    auto mode = mode_ == Mode::LowerCase ? MCharCodeConvertCase::LowerCase
   1935                                         : MCharCodeConvertCase::UpperCase;
   1936    return MCharCodeConvertCase::New(alloc, charCode, mode);
   1937  }
   1938 
   1939  // Handle the pattern |num.toString(base).toUpperCase()| and simplify it to
   1940  // directly return the string representation in the correct case.
   1941  if (string->isInt32ToStringWithBase()) {
   1942    auto* toString = string->toInt32ToStringWithBase();
   1943 
   1944    bool lowerCase = mode_ == Mode::LowerCase;
   1945    if (toString->lowerCase() == lowerCase) {
   1946      return toString;
   1947    }
   1948    return MInt32ToStringWithBase::New(alloc, toString->input(),
   1949                                       toString->base(), lowerCase);
   1950  }
   1951 
   1952  return this;
   1953 }
   1954 
   1955 // Return true if |def| is `MConstant(Int32(0))`.
   1956 static bool IsConstantZeroInt32(MDefinition* def) {
   1957  return def->isConstant() && def->toConstant()->isInt32(0);
   1958 }
   1959 
   1960 // If |def| is `MBitOr` and one operand is `MConstant(Int32(0))`, then return
   1961 // the other operand. Otherwise return |def|.
   1962 static MDefinition* RemoveUnnecessaryBitOps(MDefinition* def) {
   1963  if (def->isBitOr()) {
   1964    auto* bitOr = def->toBitOr();
   1965    if (IsConstantZeroInt32(bitOr->lhs())) {
   1966      return bitOr->rhs();
   1967    }
   1968    if (IsConstantZeroInt32(bitOr->rhs())) {
   1969      return bitOr->lhs();
   1970    }
   1971  }
   1972  return def;
   1973 }
   1974 
   1975 // Return a match if both operands of |binary| have the requested types. If
   1976 // |binary| is commutative, the operands may appear in any order.
   1977 template <typename Lhs, typename Rhs>
   1978 static mozilla::Maybe<std::pair<Lhs*, Rhs*>> MatchOperands(
   1979    MBinaryInstruction* binary) {
   1980  auto* lhs = binary->lhs();
   1981  auto* rhs = binary->rhs();
   1982  if (lhs->is<Lhs>() && rhs->is<Rhs>()) {
   1983    return mozilla::Some(std::pair{lhs->to<Lhs>(), rhs->to<Rhs>()});
   1984  }
   1985  if (binary->isCommutative() && rhs->is<Lhs>() && lhs->is<Rhs>()) {
   1986    return mozilla::Some(std::pair{rhs->to<Lhs>(), lhs->to<Rhs>()});
   1987  }
   1988  return mozilla::Nothing();
   1989 }
   1990 
   1991 static bool IsSubstrTo(MSubstr* substr, int32_t len) {
   1992  // We want to match this pattern:
   1993  //
   1994  // Substr(string, Constant(0), Min(Constant(length), StringLength(string)))
   1995  //
   1996  // which is generated for the self-hosted `String.p.{substring,slice,substr}`
   1997  // functions when called with constants `start` and `end` parameters.
   1998 
   1999  if (!IsConstantZeroInt32(substr->begin())) {
   2000    return false;
   2001  }
   2002 
   2003  // Unnecessary bit-ops haven't yet been removed.
   2004  auto* length = RemoveUnnecessaryBitOps(substr->length());
   2005  if (!length->isMinMax() || length->toMinMax()->isMax()) {
   2006    return false;
   2007  }
   2008 
   2009  auto match = MatchOperands<MConstant, MStringLength>(length->toMinMax());
   2010  if (!match) {
   2011    return false;
   2012  }
   2013 
   2014  // Ensure |len| matches the substring's length.
   2015  auto [cst, strLength] = *match;
   2016  return cst->isInt32(len) && strLength->string() == substr->string();
   2017 }
   2018 
   2019 static bool IsSubstrLast(MSubstr* substr, int32_t start) {
   2020  MOZ_ASSERT(start < 0, "start from end is negative");
   2021 
   2022  // We want to match either this pattern:
   2023  //
   2024  // begin = Max(StringLength(string) + start, 0)
   2025  // length = Max(StringLength(string) - begin, 0)
   2026  // Substr(string, begin, length)
   2027  //
   2028  // or this pattern:
   2029  //
   2030  // begin = Max(StringLength(string) + start, 0)
   2031  // length = Min(StringLength(string), StringLength(string) - begin)
   2032  // Substr(string, begin, length)
   2033  //
   2034  // which is generated for the self-hosted `String.p.{slice,substr}`
   2035  // functions when called with parameters `start < 0` and `end = undefined`.
   2036 
   2037  auto* string = substr->string();
   2038 
   2039  // Unnecessary bit-ops haven't yet been removed.
   2040  auto* begin = RemoveUnnecessaryBitOps(substr->begin());
   2041  auto* length = RemoveUnnecessaryBitOps(substr->length());
   2042 
   2043  // Matches: Max(StringLength(string) + start, 0)
   2044  auto matchesBegin = [&]() {
   2045    if (!begin->isMinMax() || !begin->toMinMax()->isMax()) {
   2046      return false;
   2047    }
   2048 
   2049    auto maxOperands = MatchOperands<MAdd, MConstant>(begin->toMinMax());
   2050    if (!maxOperands) {
   2051      return false;
   2052    }
   2053 
   2054    auto [add, cst] = *maxOperands;
   2055    if (!cst->isInt32(0)) {
   2056      return false;
   2057    }
   2058 
   2059    auto addOperands = MatchOperands<MStringLength, MConstant>(add);
   2060    if (!addOperands) {
   2061      return false;
   2062    }
   2063 
   2064    auto [strLength, cstAdd] = *addOperands;
   2065    return strLength->string() == string && cstAdd->isInt32(start);
   2066  };
   2067 
   2068  // Matches: Max(StringLength(string) - begin, 0)
   2069  auto matchesSliceLength = [&]() {
   2070    if (!length->isMinMax() || !length->toMinMax()->isMax()) {
   2071      return false;
   2072    }
   2073 
   2074    auto maxOperands = MatchOperands<MSub, MConstant>(length->toMinMax());
   2075    if (!maxOperands) {
   2076      return false;
   2077    }
   2078 
   2079    auto [sub, cst] = *maxOperands;
   2080    if (!cst->isInt32(0)) {
   2081      return false;
   2082    }
   2083 
   2084    auto subOperands = MatchOperands<MStringLength, MMinMax>(sub);
   2085    if (!subOperands) {
   2086      return false;
   2087    }
   2088 
   2089    auto [strLength, minmax] = *subOperands;
   2090    return strLength->string() == string && minmax == begin;
   2091  };
   2092 
   2093  // Matches: Min(StringLength(string), StringLength(string) - begin)
   2094  auto matchesSubstrLength = [&]() {
   2095    if (!length->isMinMax() || length->toMinMax()->isMax()) {
   2096      return false;
   2097    }
   2098 
   2099    auto minOperands = MatchOperands<MStringLength, MSub>(length->toMinMax());
   2100    if (!minOperands) {
   2101      return false;
   2102    }
   2103 
   2104    auto [strLength1, sub] = *minOperands;
   2105    if (strLength1->string() != string) {
   2106      return false;
   2107    }
   2108 
   2109    auto subOperands = MatchOperands<MStringLength, MMinMax>(sub);
   2110    if (!subOperands) {
   2111      return false;
   2112    }
   2113 
   2114    auto [strLength2, minmax] = *subOperands;
   2115    return strLength2->string() == string && minmax == begin;
   2116  };
   2117 
   2118  return matchesBegin() && (matchesSliceLength() || matchesSubstrLength());
   2119 }
   2120 
   2121 MDefinition* MSubstr::foldsTo(TempAllocator& alloc) {
   2122  // Fold |str.substring(0, 1)| to |str.charAt(0)|.
   2123  if (IsSubstrTo(this, 1)) {
   2124    MOZ_ASSERT(IsConstantZeroInt32(begin()));
   2125 
   2126    auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), begin());
   2127    block()->insertBefore(this, charCode);
   2128 
   2129    return MFromCharCodeEmptyIfNegative::New(alloc, charCode);
   2130  }
   2131 
   2132  // Fold |str.slice(-1)| and |str.substr(-1)| to |str.charAt(str.length + -1)|.
   2133  if (IsSubstrLast(this, -1)) {
   2134    auto* length = MStringLength::New(alloc, string());
   2135    block()->insertBefore(this, length);
   2136 
   2137    auto* index = MConstant::NewInt32(alloc, -1);
   2138    block()->insertBefore(this, index);
   2139 
   2140    // Folded MToRelativeStringIndex, see MToRelativeStringIndex::foldsTo.
   2141    //
   2142    // Safe to truncate because |length| is never negative.
   2143    auto* add = MAdd::New(alloc, index, length, TruncateKind::Truncate);
   2144    block()->insertBefore(this, add);
   2145 
   2146    auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), add);
   2147    block()->insertBefore(this, charCode);
   2148 
   2149    return MFromCharCodeEmptyIfNegative::New(alloc, charCode);
   2150  }
   2151 
   2152  return this;
   2153 }
   2154 
   2155 MDefinition* MCharCodeAt::foldsTo(TempAllocator& alloc) {
   2156  MDefinition* string = this->string();
   2157  if (!string->isConstant() && !string->isFromCharCode()) {
   2158    return this;
   2159  }
   2160 
   2161  MDefinition* index = this->index();
   2162  if (index->isSpectreMaskIndex()) {
   2163    index = index->toSpectreMaskIndex()->index();
   2164  }
   2165  if (!index->isConstant()) {
   2166    return this;
   2167  }
   2168  int32_t idx = index->toConstant()->toInt32();
   2169 
   2170  // Handle the pattern |s[idx].charCodeAt(0)|.
   2171  if (string->isFromCharCode()) {
   2172    if (idx != 0) {
   2173      return this;
   2174    }
   2175 
   2176    // Simplify |CharCodeAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
   2177    // |CharCodeAt(s, idx)|.
   2178    auto* charCode = string->toFromCharCode()->code();
   2179    if (!charCode->isCharCodeAt()) {
   2180      return this;
   2181    }
   2182 
   2183    return charCode;
   2184  }
   2185 
   2186  JSOffThreadAtom* str = string->toConstant()->toString();
   2187  if (idx < 0 || uint32_t(idx) >= str->length()) {
   2188    return this;
   2189  }
   2190 
   2191  char16_t ch = str->latin1OrTwoByteChar(idx);
   2192  return MConstant::NewInt32(alloc, ch);
   2193 }
   2194 
   2195 MDefinition* MCodePointAt::foldsTo(TempAllocator& alloc) {
   2196  MDefinition* string = this->string();
   2197  if (!string->isConstant() && !string->isFromCharCode()) {
   2198    return this;
   2199  }
   2200 
   2201  MDefinition* index = this->index();
   2202  if (index->isSpectreMaskIndex()) {
   2203    index = index->toSpectreMaskIndex()->index();
   2204  }
   2205  if (!index->isConstant()) {
   2206    return this;
   2207  }
   2208  int32_t idx = index->toConstant()->toInt32();
   2209 
   2210  // Handle the pattern |s[idx].codePointAt(0)|.
   2211  if (string->isFromCharCode()) {
   2212    if (idx != 0) {
   2213      return this;
   2214    }
   2215 
   2216    // Simplify |CodePointAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
   2217    // |CharCodeAt(s, idx)|.
   2218    auto* charCode = string->toFromCharCode()->code();
   2219    if (!charCode->isCharCodeAt()) {
   2220      return this;
   2221    }
   2222 
   2223    return charCode;
   2224  }
   2225 
   2226  JSOffThreadAtom* str = string->toConstant()->toString();
   2227  if (idx < 0 || uint32_t(idx) >= str->length()) {
   2228    return this;
   2229  }
   2230 
   2231  char32_t first = str->latin1OrTwoByteChar(idx);
   2232  if (unicode::IsLeadSurrogate(first) && uint32_t(idx) + 1 < str->length()) {
   2233    char32_t second = str->latin1OrTwoByteChar(idx + 1);
   2234    if (unicode::IsTrailSurrogate(second)) {
   2235      first = unicode::UTF16Decode(first, second);
   2236    }
   2237  }
   2238  return MConstant::NewInt32(alloc, first);
   2239 }
   2240 
   2241 MDefinition* MToRelativeStringIndex::foldsTo(TempAllocator& alloc) {
   2242  MDefinition* index = this->index();
   2243  MDefinition* length = this->length();
   2244 
   2245  if (!index->isConstant()) {
   2246    return this;
   2247  }
   2248  if (!length->isStringLength() && !length->isConstant()) {
   2249    return this;
   2250  }
   2251  MOZ_ASSERT_IF(length->isConstant(), length->toConstant()->toInt32() >= 0);
   2252 
   2253  int32_t relativeIndex = index->toConstant()->toInt32();
   2254  if (relativeIndex >= 0) {
   2255    return index;
   2256  }
   2257 
   2258  // Safe to truncate because |length| is never negative.
   2259  return MAdd::New(alloc, index, length, TruncateKind::Truncate);
   2260 }
   2261 
   2262 template <size_t Arity>
   2263 [[nodiscard]] static bool EnsureFloatInputOrConvert(
   2264    MAryInstruction<Arity>* owner, TempAllocator& alloc) {
   2265  MOZ_ASSERT(!IsFloatingPointType(owner->type()),
   2266             "Floating point types must check consumers");
   2267 
   2268  if (AllOperandsCanProduceFloat32(owner)) {
   2269    return true;
   2270  }
   2271  ConvertOperandsToDouble(owner, alloc);
   2272  return false;
   2273 }
   2274 
   2275 template <size_t Arity>
   2276 [[nodiscard]] static bool EnsureFloatConsumersAndInputOrConvert(
   2277    MAryInstruction<Arity>* owner, TempAllocator& alloc) {
   2278  MOZ_ASSERT(IsFloatingPointType(owner->type()),
   2279             "Integer types don't need to check consumers");
   2280 
   2281  if (AllOperandsCanProduceFloat32(owner) &&
   2282      CheckUsesAreFloat32Consumers(owner)) {
   2283    return true;
   2284  }
   2285  ConvertOperandsToDouble(owner, alloc);
   2286  return false;
   2287 }
   2288 
   2289 void MFloor::trySpecializeFloat32(TempAllocator& alloc) {
   2290  MOZ_ASSERT(type() == MIRType::Int32);
   2291  if (EnsureFloatInputOrConvert(this, alloc)) {
   2292    specialization_ = MIRType::Float32;
   2293  }
   2294 }
   2295 
   2296 void MCeil::trySpecializeFloat32(TempAllocator& alloc) {
   2297  MOZ_ASSERT(type() == MIRType::Int32);
   2298  if (EnsureFloatInputOrConvert(this, alloc)) {
   2299    specialization_ = MIRType::Float32;
   2300  }
   2301 }
   2302 
   2303 void MRound::trySpecializeFloat32(TempAllocator& alloc) {
   2304  MOZ_ASSERT(type() == MIRType::Int32);
   2305  if (EnsureFloatInputOrConvert(this, alloc)) {
   2306    specialization_ = MIRType::Float32;
   2307  }
   2308 }
   2309 
   2310 void MTrunc::trySpecializeFloat32(TempAllocator& alloc) {
   2311  MOZ_ASSERT(type() == MIRType::Int32);
   2312  if (EnsureFloatInputOrConvert(this, alloc)) {
   2313    specialization_ = MIRType::Float32;
   2314  }
   2315 }
   2316 
   2317 void MNearbyInt::trySpecializeFloat32(TempAllocator& alloc) {
   2318  if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
   2319    specialization_ = MIRType::Float32;
   2320    setResultType(MIRType::Float32);
   2321  }
   2322 }
   2323 
   2324 void MRoundToDouble::trySpecializeFloat32(TempAllocator& alloc) {
   2325  if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
   2326    specialization_ = MIRType::Float32;
   2327    setResultType(MIRType::Float32);
   2328  }
   2329 }
   2330 
   2331 MGoto* MGoto::New(TempAllocator& alloc, MBasicBlock* target) {
   2332  return new (alloc) MGoto(target);
   2333 }
   2334 
   2335 MGoto* MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target) {
   2336  MOZ_ASSERT(target);
   2337  return new (alloc) MGoto(target);
   2338 }
   2339 
   2340 MGoto* MGoto::New(TempAllocator& alloc) { return new (alloc) MGoto(nullptr); }
   2341 
   2342 MDefinition* MBox::foldsTo(TempAllocator& alloc) {
   2343  if (input()->isUnbox()) {
   2344    return input()->toUnbox()->input();
   2345  }
   2346  return this;
   2347 }
   2348 
   2349 #ifdef JS_JITSPEW
   2350 void MUnbox::printOpcode(GenericPrinter& out) const {
   2351  PrintOpcodeName(out, op());
   2352  out.printf(" ");
   2353  getOperand(0)->printName(out);
   2354  out.printf(" ");
   2355 
   2356  switch (type()) {
   2357    case MIRType::Int32:
   2358      out.printf("to Int32");
   2359      break;
   2360    case MIRType::Double:
   2361      out.printf("to Double");
   2362      break;
   2363    case MIRType::Boolean:
   2364      out.printf("to Boolean");
   2365      break;
   2366    case MIRType::String:
   2367      out.printf("to String");
   2368      break;
   2369    case MIRType::Symbol:
   2370      out.printf("to Symbol");
   2371      break;
   2372    case MIRType::BigInt:
   2373      out.printf("to BigInt");
   2374      break;
   2375    case MIRType::Object:
   2376      out.printf("to Object");
   2377      break;
   2378    default:
   2379      break;
   2380  }
   2381 
   2382  switch (mode()) {
   2383    case Fallible:
   2384      out.printf(" (fallible)");
   2385      break;
   2386    case Infallible:
   2387      out.printf(" (infallible)");
   2388      break;
   2389    default:
   2390      break;
   2391  }
   2392 }
   2393 #endif
   2394 
   2395 MDefinition* MUnbox::foldsTo(TempAllocator& alloc) {
   2396  if (input()->isBox()) {
   2397    MDefinition* unboxed = input()->toBox()->input();
   2398 
   2399    // Fold MUnbox(MBox(x)) => x if types match.
   2400    if (unboxed->type() == type()) {
   2401      if (fallible()) {
   2402        unboxed->setImplicitlyUsedUnchecked();
   2403      }
   2404      return unboxed;
   2405    }
   2406 
   2407    // Fold MUnbox(MBox(x)) => MToDouble(x) if possible.
   2408    if (type() == MIRType::Double &&
   2409        IsTypeRepresentableAsDouble(unboxed->type())) {
   2410      if (unboxed->isConstant()) {
   2411        return MConstant::NewDouble(alloc,
   2412                                    unboxed->toConstant()->numberToDouble());
   2413      }
   2414 
   2415      return MToDouble::New(alloc, unboxed);
   2416    }
   2417 
   2418    // MUnbox<Int32>(MBox<Double>(x)) will always fail, even if x can be
   2419    // represented as an Int32. Fold to avoid unnecessary bailouts.
   2420    if (type() == MIRType::Int32 && unboxed->type() == MIRType::Double) {
   2421      auto* folded = MToNumberInt32::New(alloc, unboxed,
   2422                                         IntConversionInputKind::NumbersOnly);
   2423      folded->setGuard();
   2424      return folded;
   2425    }
   2426  }
   2427 
   2428  return this;
   2429 }
   2430 
   2431 #ifdef DEBUG
   2432 void MPhi::assertLoopPhi() const {
   2433  // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these
   2434  // predecessors being at known indices.
   2435  if (block()->numPredecessors() == 2) {
   2436    MBasicBlock* pred = block()->getPredecessor(0);
   2437    MBasicBlock* back = block()->getPredecessor(1);
   2438    MOZ_ASSERT(pred == block()->loopPredecessor());
   2439    MOZ_ASSERT(pred->successorWithPhis() == block());
   2440    MOZ_ASSERT(pred->positionInPhiSuccessor() == 0);
   2441    MOZ_ASSERT(back == block()->backedge());
   2442    MOZ_ASSERT(back->successorWithPhis() == block());
   2443    MOZ_ASSERT(back->positionInPhiSuccessor() == 1);
   2444  } else {
   2445    // After we remove fake loop predecessors for loop headers that
   2446    // are only reachable via OSR, the only predecessor is the
   2447    // loop backedge.
   2448    MOZ_ASSERT(block()->numPredecessors() == 1);
   2449    MOZ_ASSERT(block()->graph().osrBlock());
   2450    MOZ_ASSERT(!block()->graph().canBuildDominators());
   2451    MBasicBlock* back = block()->getPredecessor(0);
   2452    MOZ_ASSERT(back == block()->backedge());
   2453    MOZ_ASSERT(back->successorWithPhis() == block());
   2454    MOZ_ASSERT(back->positionInPhiSuccessor() == 0);
   2455  }
   2456 }
   2457 #endif
   2458 
   2459 MDefinition* MPhi::getLoopPredecessorOperand() const {
   2460  // This should not be called after removing fake loop predecessors.
   2461  MOZ_ASSERT(block()->numPredecessors() == 2);
   2462  assertLoopPhi();
   2463  return getOperand(0);
   2464 }
   2465 
   2466 MDefinition* MPhi::getLoopBackedgeOperand() const {
   2467  assertLoopPhi();
   2468  uint32_t idx = block()->numPredecessors() == 2 ? 1 : 0;
   2469  return getOperand(idx);
   2470 }
   2471 
   2472 void MPhi::removeOperand(size_t index) {
   2473  MOZ_ASSERT(index < numOperands());
   2474  MOZ_ASSERT(getUseFor(index)->index() == index);
   2475  MOZ_ASSERT(getUseFor(index)->consumer() == this);
   2476 
   2477  // If we have phi(..., a, b, c, d, ..., z) and we plan
   2478  // on removing a, then first shift downward so that we have
   2479  // phi(..., b, c, d, ..., z, z):
   2480  MUse* p = inputs_.begin() + index;
   2481  MUse* e = inputs_.end();
   2482  p->producer()->removeUse(p);
   2483  for (; p < e - 1; ++p) {
   2484    MDefinition* producer = (p + 1)->producer();
   2485    p->setProducerUnchecked(producer);
   2486    producer->replaceUse(p + 1, p);
   2487  }
   2488 
   2489  // truncate the inputs_ list:
   2490  inputs_.popBack();
   2491 }
   2492 
   2493 void MPhi::removeAllOperands() {
   2494  for (MUse& p : inputs_) {
   2495    p.producer()->removeUse(&p);
   2496  }
   2497  inputs_.clear();
   2498 }
   2499 
   2500 MDefinition* MPhi::foldsTernary(TempAllocator& alloc) {
   2501  /* Look if this MPhi is a ternary construct.
   2502   * This is a very loose term as it actually only checks for
   2503   *
   2504   *      MTest X
   2505   *       /  \
   2506   *    ...    ...
   2507   *       \  /
   2508   *     MPhi X Y
   2509   *
   2510   * Which we will simply call:
   2511   * x ? x : y or x ? y : x
   2512   */
   2513 
   2514  if (numOperands() != 2) {
   2515    return nullptr;
   2516  }
   2517 
   2518  MOZ_ASSERT(block()->numPredecessors() == 2);
   2519 
   2520  MBasicBlock* pred = block()->immediateDominator();
   2521  if (!pred || !pred->lastIns()->isTest()) {
   2522    return nullptr;
   2523  }
   2524 
   2525  MTest* test = pred->lastIns()->toTest();
   2526 
   2527  // True branch may only dominate one edge of MPhi.
   2528  if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
   2529      test->ifTrue()->dominates(block()->getPredecessor(1))) {
   2530    return nullptr;
   2531  }
   2532 
   2533  // False branch may only dominate one edge of MPhi.
   2534  if (test->ifFalse()->dominates(block()->getPredecessor(0)) ==
   2535      test->ifFalse()->dominates(block()->getPredecessor(1))) {
   2536    return nullptr;
   2537  }
   2538 
   2539  // True and false branch must dominate different edges of MPhi.
   2540  if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
   2541      test->ifFalse()->dominates(block()->getPredecessor(0))) {
   2542    return nullptr;
   2543  }
   2544 
   2545  // We found a ternary construct.
   2546  bool firstIsTrueBranch =
   2547      test->ifTrue()->dominates(block()->getPredecessor(0));
   2548  MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1);
   2549  MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0);
   2550 
   2551  // Accept either
   2552  // testArg ? testArg : constant or
   2553  // testArg ? constant : testArg
   2554  if (!trueDef->isConstant() && !falseDef->isConstant()) {
   2555    return nullptr;
   2556  }
   2557 
   2558  MConstant* c =
   2559      trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
   2560  MDefinition* testArg = (trueDef == c) ? falseDef : trueDef;
   2561  if (testArg != test->input()) {
   2562    return nullptr;
   2563  }
   2564 
   2565  // This check should be a tautology, except that the constant might be the
   2566  // result of the removal of a branch.  In such case the domination scope of
   2567  // the block which is holding the constant might be incomplete. This
   2568  // condition is used to prevent doing this optimization based on incomplete
   2569  // information.
   2570  //
   2571  // As GVN removed a branch, it will update the dominations rules before
   2572  // trying to fold this MPhi again. Thus, this condition does not inhibit
   2573  // this optimization.
   2574  MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
   2575  MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
   2576  if (!trueDef->block()->dominates(truePred) ||
   2577      !falseDef->block()->dominates(falsePred)) {
   2578    return nullptr;
   2579  }
   2580 
   2581  // If testArg is an int32 type we can:
   2582  // - fold testArg ? testArg : 0 to testArg
   2583  // - fold testArg ? 0 : testArg to 0
   2584  if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) {
   2585    testArg->setGuardRangeBailoutsUnchecked();
   2586 
   2587    // When folding to the constant we need to hoist it.
   2588    if (trueDef == c && !c->block()->dominates(block())) {
   2589      c->block()->moveBefore(pred->lastIns(), c);
   2590    }
   2591    return trueDef;
   2592  }
   2593 
   2594  // If testArg is an double type we can:
   2595  // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg)
   2596  if (testArg->type() == MIRType::Double &&
   2597      mozilla::IsPositiveZero(c->numberToDouble()) && c != trueDef) {
   2598    MNaNToZero* replace = MNaNToZero::New(alloc, testArg);
   2599    test->block()->insertBefore(test, replace);
   2600    return replace;
   2601  }
   2602 
   2603  // If testArg is a string type we can:
   2604  // - fold testArg ? testArg : "" to testArg
   2605  // - fold testArg ? "" : testArg to ""
   2606  if (testArg->type() == MIRType::String && c->toString()->empty()) {
   2607    // When folding to the constant we need to hoist it.
   2608    if (trueDef == c && !c->block()->dominates(block())) {
   2609      c->block()->moveBefore(pred->lastIns(), c);
   2610    }
   2611    return trueDef;
   2612  }
   2613 
   2614  return nullptr;
   2615 }
   2616 
   2617 MDefinition* MPhi::operandIfRedundant() {
   2618  if (inputs_.length() == 0) {
   2619    return nullptr;
   2620  }
   2621 
   2622  // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
   2623  // returns the operand that it will always be equal to (a, in
   2624  // those two cases).
   2625  MDefinition* first = getOperand(0);
   2626  for (size_t i = 1, e = numOperands(); i < e; i++) {
   2627    MDefinition* op = getOperand(i);
   2628    if (op != first && op != this) {
   2629      return nullptr;
   2630    }
   2631  }
   2632  return first;
   2633 }
   2634 
   2635 MDefinition* MPhi::foldsTo(TempAllocator& alloc) {
   2636  if (MDefinition* def = operandIfRedundant()) {
   2637    return def;
   2638  }
   2639 
   2640  if (MDefinition* def = foldsTernary(alloc)) {
   2641    return def;
   2642  }
   2643 
   2644  return this;
   2645 }
   2646 
   2647 bool MPhi::congruentTo(const MDefinition* ins) const {
   2648  if (!ins->isPhi()) {
   2649    return false;
   2650  }
   2651 
   2652  // Phis in different blocks may have different control conditions.
   2653  // For example, these phis:
   2654  //
   2655  //   if (p)
   2656  //     goto a
   2657  //   a:
   2658  //     t = phi(x, y)
   2659  //
   2660  //   if (q)
   2661  //     goto b
   2662  //   b:
   2663  //     s = phi(x, y)
   2664  //
   2665  // have identical operands, but they are not equvalent because t is
   2666  // effectively p?x:y and s is effectively q?x:y.
   2667  //
   2668  // For now, consider phis in different blocks incongruent.
   2669  if (ins->block() != block()) {
   2670    return false;
   2671  }
   2672 
   2673  return congruentIfOperandsEqual(ins);
   2674 }
   2675 
   2676 void MPhi::updateForReplacement(MPhi* other) {
   2677  // This function is called to fix the current Phi flags using it as a
   2678  // replacement of the other Phi instruction |other|.
   2679  //
   2680  // When dealing with usage analysis, any Use will replace all other values,
   2681  // such as Unused and Unknown. Unless both are Unused, the merge would be
   2682  // Unknown.
   2683  if (usageAnalysis_ == PhiUsage::Used ||
   2684      other->usageAnalysis_ == PhiUsage::Used) {
   2685    usageAnalysis_ = PhiUsage::Used;
   2686  } else if (usageAnalysis_ != other->usageAnalysis_) {
   2687    //    this == unused && other == unknown
   2688    // or this == unknown && other == unused
   2689    usageAnalysis_ = PhiUsage::Unknown;
   2690  } else {
   2691    //    this == unused && other == unused
   2692    // or this == unknown && other = unknown
   2693    MOZ_ASSERT(usageAnalysis_ == PhiUsage::Unused ||
   2694               usageAnalysis_ == PhiUsage::Unknown);
   2695    MOZ_ASSERT(usageAnalysis_ == other->usageAnalysis_);
   2696  }
   2697 }
   2698 
   2699 /* static */
   2700 bool MPhi::markIteratorPhis(const PhiVector& iterators) {
   2701  // Find and mark phis that must transitively hold an iterator live.
   2702 
   2703  Vector<MPhi*, 8, SystemAllocPolicy> worklist;
   2704 
   2705  for (MPhi* iter : iterators) {
   2706    if (!iter->isInWorklist()) {
   2707      if (!worklist.append(iter)) {
   2708        return false;
   2709      }
   2710      iter->setInWorklist();
   2711    }
   2712  }
   2713 
   2714  while (!worklist.empty()) {
   2715    MPhi* phi = worklist.popCopy();
   2716    phi->setNotInWorklist();
   2717 
   2718    phi->setIterator();
   2719    phi->setImplicitlyUsedUnchecked();
   2720 
   2721    for (MUseDefIterator iter(phi); iter; iter++) {
   2722      MDefinition* use = iter.def();
   2723      if (!use->isInWorklist() && use->isPhi() && !use->toPhi()->isIterator()) {
   2724        if (!worklist.append(use->toPhi())) {
   2725          return false;
   2726        }
   2727        use->setInWorklist();
   2728      }
   2729    }
   2730  }
   2731 
   2732  return true;
   2733 }
   2734 
   2735 bool MPhi::typeIncludes(MDefinition* def) {
   2736  MOZ_ASSERT(!IsMagicType(def->type()));
   2737 
   2738  if (def->type() == this->type()) {
   2739    return true;
   2740  }
   2741 
   2742  // This phi must be able to be any value.
   2743  if (this->type() == MIRType::Value) {
   2744    return true;
   2745  }
   2746 
   2747  if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) {
   2748    return true;
   2749  }
   2750 
   2751  return false;
   2752 }
   2753 
   2754 void MCallBase::addArg(size_t argnum, MDefinition* arg) {
   2755  // The operand vector is initialized in reverse order by WarpBuilder.
   2756  // It cannot be checked for consistency until all arguments are added.
   2757  // FixedList doesn't initialize its elements, so do an unchecked init.
   2758  initOperand(argnum + NumNonArgumentOperands, arg);
   2759 }
   2760 
   2761 static inline bool IsConstant(MDefinition* def, double v) {
   2762  if (!def->isConstant()) {
   2763    return false;
   2764  }
   2765 
   2766  return NumbersAreIdentical(def->toConstant()->numberToDouble(), v);
   2767 }
   2768 
   2769 static inline bool IsConstantInt64(MDefinition* def, int64_t v) {
   2770  if (!def->isConstant()) {
   2771    return false;
   2772  }
   2773 
   2774  return def->toConstant()->toInt64() == v;
   2775 }
   2776 
   2777 static inline bool IsConstantIntPtr(MDefinition* def, intptr_t v) {
   2778  if (!def->isConstant()) {
   2779    return false;
   2780  }
   2781 
   2782  return def->toConstant()->toIntPtr() == v;
   2783 }
   2784 
   2785 MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) {
   2786  // Identity operations are removed (for int32 only) in foldUnnecessaryBitop.
   2787 
   2788  if (type() == MIRType::Int32) {
   2789    if (MDefinition* folded = EvaluateInt32ConstantOperands(alloc, this)) {
   2790      return folded;
   2791    }
   2792  } else if (type() == MIRType::Int64) {
   2793    if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
   2794      return folded;
   2795    }
   2796  } else if (type() == MIRType::IntPtr) {
   2797    if (MDefinition* folded = EvaluateIntPtrConstantOperands(alloc, this)) {
   2798      return folded;
   2799    }
   2800  }
   2801 
   2802  return this;
   2803 }
   2804 
   2805 MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() {
   2806  // It's probably OK to perform this optimization only for int32, as it will
   2807  // have the greatest effect for asm.js code that is compiled with the JS
   2808  // pipeline, and that code will not see int64 values.
   2809 
   2810  if (type() != MIRType::Int32) {
   2811    return this;
   2812  }
   2813 
   2814  // Fold unsigned shift right operator when the second operand is zero and
   2815  // the only use is an unsigned modulo. Thus, the expression
   2816  // |(x >>> 0) % y| becomes |x % y|.
   2817  if (isUrsh() && IsUint32Type(this)) {
   2818    MDefinition* defUse = maybeSingleDefUse();
   2819    if (defUse && defUse->isMod() && defUse->toMod()->isUnsigned()) {
   2820      return getOperand(0);
   2821    }
   2822  }
   2823 
   2824  // Eliminate bitwise operations that are no-ops when used on integer
   2825  // inputs, such as (x | 0).
   2826 
   2827  MDefinition* lhs = getOperand(0);
   2828  MDefinition* rhs = getOperand(1);
   2829 
   2830  if (IsConstant(lhs, 0)) {
   2831    return foldIfZero(0);
   2832  }
   2833 
   2834  if (IsConstant(rhs, 0)) {
   2835    return foldIfZero(1);
   2836  }
   2837 
   2838  if (IsConstant(lhs, -1)) {
   2839    return foldIfNegOne(0);
   2840  }
   2841 
   2842  if (IsConstant(rhs, -1)) {
   2843    return foldIfNegOne(1);
   2844  }
   2845 
   2846  if (lhs == rhs) {
   2847    return foldIfEqual();
   2848  }
   2849 
   2850  if (maskMatchesRightRange) {
   2851    MOZ_ASSERT(lhs->isConstant());
   2852    MOZ_ASSERT(lhs->type() == MIRType::Int32);
   2853    return foldIfAllBitsSet(0);
   2854  }
   2855 
   2856  if (maskMatchesLeftRange) {
   2857    MOZ_ASSERT(rhs->isConstant());
   2858    MOZ_ASSERT(rhs->type() == MIRType::Int32);
   2859    return foldIfAllBitsSet(1);
   2860  }
   2861 
   2862  return this;
   2863 }
   2864 
   2865 static inline bool CanProduceNegativeZero(MDefinition* def) {
   2866  // Test if this instruction can produce negative zero even when bailing out
   2867  // and changing types.
   2868  switch (def->op()) {
   2869    case MDefinition::Opcode::Constant:
   2870      if (def->type() == MIRType::Double &&
   2871          def->toConstant()->toDouble() == -0.0) {
   2872        return true;
   2873      }
   2874      [[fallthrough]];
   2875    case MDefinition::Opcode::BitAnd:
   2876    case MDefinition::Opcode::BitOr:
   2877    case MDefinition::Opcode::BitXor:
   2878    case MDefinition::Opcode::BitNot:
   2879    case MDefinition::Opcode::Lsh:
   2880    case MDefinition::Opcode::Rsh:
   2881      return false;
   2882    default:
   2883      return true;
   2884  }
   2885 }
   2886 
   2887 static inline bool NeedNegativeZeroCheck(MDefinition* def) {
   2888  if (def->isGuard() || def->isGuardRangeBailouts()) {
   2889    return true;
   2890  }
   2891 
   2892  // Test if all uses have the same semantics for -0 and 0
   2893  for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
   2894    if (use->consumer()->isResumePoint()) {
   2895      return true;
   2896    }
   2897 
   2898    MDefinition* use_def = use->consumer()->toDefinition();
   2899    switch (use_def->op()) {
   2900      case MDefinition::Opcode::Add: {
   2901        // If add is truncating -0 and 0 are observed as the same.
   2902        if (use_def->toAdd()->isTruncated()) {
   2903          break;
   2904        }
   2905 
   2906        // x + y gives -0, when both x and y are -0
   2907 
   2908        // Figure out the order in which the addition's operands will
   2909        // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
   2910        // definitions for us so that this just requires comparing ids.
   2911        MDefinition* first = use_def->toAdd()->lhs();
   2912        MDefinition* second = use_def->toAdd()->rhs();
   2913        if (first->id() > second->id()) {
   2914          std::swap(first, second);
   2915        }
   2916        // Negative zero checks can be removed on the first executed
   2917        // operand only if it is guaranteed the second executed operand
   2918        // will produce a value other than -0. While the second is
   2919        // typed as an int32, a bailout taken between execution of the
   2920        // operands may change that type and cause a -0 to flow to the
   2921        // second.
   2922        //
   2923        // There is no way to test whether there are any bailouts
   2924        // between execution of the operands, so remove negative
   2925        // zero checks from the first only if the second's type is
   2926        // independent from type changes that may occur after bailing.
   2927        if (def == first && CanProduceNegativeZero(second)) {
   2928          return true;
   2929        }
   2930 
   2931        // The negative zero check can always be removed on the second
   2932        // executed operand; by the time this executes the first will have
   2933        // been evaluated as int32 and the addition's result cannot be -0.
   2934        break;
   2935      }
   2936      case MDefinition::Opcode::Sub: {
   2937        // If sub is truncating -0 and 0 are observed as the same
   2938        if (use_def->toSub()->isTruncated()) {
   2939          break;
   2940        }
   2941 
   2942        // x + y gives -0, when x is -0 and y is 0
   2943 
   2944        // We can remove the negative zero check on the rhs, only if we
   2945        // are sure the lhs isn't negative zero.
   2946 
   2947        // The lhs is typed as integer (i.e. not -0.0), but it can bailout
   2948        // and change type. This should be fine if the lhs is executed
   2949        // first. However if the rhs is executed first, the lhs can bail,
   2950        // change type and become -0.0 while the rhs has already been
   2951        // optimized to not make a difference between zero and negative zero.
   2952        MDefinition* lhs = use_def->toSub()->lhs();
   2953        MDefinition* rhs = use_def->toSub()->rhs();
   2954        if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) {
   2955          return true;
   2956        }
   2957 
   2958        [[fallthrough]];
   2959      }
   2960      case MDefinition::Opcode::StoreElement:
   2961      case MDefinition::Opcode::StoreHoleValueElement:
   2962      case MDefinition::Opcode::LoadElement:
   2963      case MDefinition::Opcode::LoadElementHole:
   2964      case MDefinition::Opcode::LoadUnboxedScalar:
   2965      case MDefinition::Opcode::LoadDataViewElement:
   2966      case MDefinition::Opcode::LoadTypedArrayElementHole:
   2967      case MDefinition::Opcode::CharCodeAt:
   2968      case MDefinition::Opcode::Mod:
   2969      case MDefinition::Opcode::InArray:
   2970        // Only allowed to remove check when definition is the second operand
   2971        if (use_def->getOperand(0) == def) {
   2972          return true;
   2973        }
   2974        for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
   2975          if (use_def->getOperand(i) == def) {
   2976            return true;
   2977          }
   2978        }
   2979        break;
   2980      case MDefinition::Opcode::BoundsCheck:
   2981        // Only allowed to remove check when definition is the first operand
   2982        if (use_def->toBoundsCheck()->getOperand(1) == def) {
   2983          return true;
   2984        }
   2985        break;
   2986      case MDefinition::Opcode::ToString:
   2987      case MDefinition::Opcode::FromCharCode:
   2988      case MDefinition::Opcode::FromCodePoint:
   2989      case MDefinition::Opcode::TableSwitch:
   2990      case MDefinition::Opcode::Compare:
   2991      case MDefinition::Opcode::BitAnd:
   2992      case MDefinition::Opcode::BitOr:
   2993      case MDefinition::Opcode::BitXor:
   2994      case MDefinition::Opcode::Abs:
   2995      case MDefinition::Opcode::TruncateToInt32:
   2996        // Always allowed to remove check. No matter which operand.
   2997        break;
   2998      case MDefinition::Opcode::StoreElementHole:
   2999      case MDefinition::Opcode::StoreTypedArrayElementHole:
   3000      case MDefinition::Opcode::PostWriteElementBarrier:
   3001        // Only allowed to remove check when definition is the third operand.
   3002        for (size_t i = 0, e = use_def->numOperands(); i < e; i++) {
   3003          if (i == 2) {
   3004            continue;
   3005          }
   3006          if (use_def->getOperand(i) == def) {
   3007            return true;
   3008          }
   3009        }
   3010        break;
   3011      default:
   3012        return true;
   3013    }
   3014  }
   3015  return false;
   3016 }
   3017 
   3018 #ifdef JS_JITSPEW
   3019 void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const {
   3020  MDefinition::printOpcode(out);
   3021 
   3022  switch (type()) {
   3023    case MIRType::Int32:
   3024      if (isDiv()) {
   3025        out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32");
   3026      } else if (isMod()) {
   3027        out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32");
   3028      } else {
   3029        out.printf(" [int32]");
   3030      }
   3031      break;
   3032    case MIRType::Int64:
   3033      if (isDiv()) {
   3034        out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64");
   3035      } else if (isMod()) {
   3036        out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64");
   3037      } else {
   3038        out.printf(" [int64]");
   3039      }
   3040      break;
   3041    case MIRType::Float32:
   3042      out.printf(" [float]");
   3043      break;
   3044    case MIRType::Double:
   3045      out.printf(" [double]");
   3046      break;
   3047    default:
   3048      break;
   3049  }
   3050 }
   3051 #endif
   3052 
   3053 MDefinition* MRsh::foldsTo(TempAllocator& alloc) {
   3054  MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
   3055 
   3056  if (f != this) {
   3057    return f;
   3058  }
   3059 
   3060  MDefinition* lhs = getOperand(0);
   3061  MDefinition* rhs = getOperand(1);
   3062 
   3063  // It's probably OK to perform this optimization only for int32, as it will
   3064  // have the greatest effect for asm.js code that is compiled with the JS
   3065  // pipeline, and that code will not see int64 values.
   3066 
   3067  if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32) {
   3068    return this;
   3069  }
   3070 
   3071  if (!lhs->getOperand(1)->isConstant() ||
   3072      lhs->getOperand(1)->type() != MIRType::Int32) {
   3073    return this;
   3074  }
   3075 
   3076  uint32_t shift = rhs->toConstant()->toInt32();
   3077  uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32();
   3078  if (shift != shift_lhs) {
   3079    return this;
   3080  }
   3081 
   3082  switch (shift) {
   3083    case 16:
   3084      return MSignExtendInt32::New(alloc, lhs->getOperand(0),
   3085                                   MSignExtendInt32::Half);
   3086    case 24:
   3087      return MSignExtendInt32::New(alloc, lhs->getOperand(0),
   3088                                   MSignExtendInt32::Byte);
   3089  }
   3090 
   3091  return this;
   3092 }
   3093 
   3094 MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) {
   3095  MOZ_ASSERT(IsNumberType(type()));
   3096  MOZ_ASSERT(!isDiv() && !isMod(), "Div and Mod don't call this method");
   3097 
   3098  MDefinition* lhs = getOperand(0);
   3099  MDefinition* rhs = getOperand(1);
   3100 
   3101  if (type() == MIRType::Int64) {
   3102    MOZ_ASSERT(!isTruncated());
   3103 
   3104    if (MConstant* folded = EvaluateInt64ConstantOperands(alloc, this)) {
   3105      return folded;
   3106    }
   3107    if (IsConstantInt64(rhs, int64_t(getIdentity()))) {
   3108      return lhs;  // x op id => x
   3109    }
   3110    if (isCommutative() && IsConstantInt64(lhs, int64_t(getIdentity()))) {
   3111      return rhs;  // id op x => x
   3112    }
   3113    return this;
   3114  }
   3115 
   3116  if (type() == MIRType::IntPtr) {
   3117    MOZ_ASSERT(!isTruncated());
   3118 
   3119    if (MConstant* folded = EvaluateIntPtrConstantOperands(alloc, this)) {
   3120      return folded;
   3121    }
   3122    if (IsConstantIntPtr(rhs, intptr_t(getIdentity()))) {
   3123      return lhs;  // x op id => x
   3124    }
   3125    if (isCommutative() && IsConstantIntPtr(lhs, intptr_t(getIdentity()))) {
   3126      return rhs;  // id op x => x
   3127    }
   3128    return this;
   3129  }
   3130 
   3131  // The remaining operations expect types representable as doubles.
   3132  MOZ_ASSERT(IsTypeRepresentableAsDouble(type()));
   3133 
   3134  if (MConstant* folded = EvaluateConstantOperands(alloc, this)) {
   3135    if (isTruncated()) {
   3136      if (folded->type() != MIRType::Int32) {
   3137        if (!folded->block()) {
   3138          block()->insertBefore(this, folded);
   3139        }
   3140        return MTruncateToInt32::New(alloc, folded);
   3141      }
   3142    }
   3143    return folded;
   3144  }
   3145 
   3146  if (MConstant* folded = EvaluateConstantNaNOperand(this)) {
   3147    MOZ_ASSERT(!isTruncated());
   3148    return folded;
   3149  }
   3150 
   3151  if (mustPreserveNaN_) {
   3152    return this;
   3153  }
   3154 
   3155  // 0 + -0 = 0. So we can't remove addition
   3156  if (isAdd() && type() != MIRType::Int32) {
   3157    return this;
   3158  }
   3159 
   3160  if (IsConstant(rhs, getIdentity())) {
   3161    if (isTruncated()) {
   3162      return MTruncateToInt32::New(alloc, lhs);
   3163    }
   3164    return lhs;
   3165  }
   3166 
   3167  // subtraction isn't commutative. So we can't remove subtraction when lhs
   3168  // equals 0
   3169  if (isSub()) {
   3170    return this;
   3171  }
   3172 
   3173  if (IsConstant(lhs, getIdentity())) {
   3174    if (isTruncated()) {
   3175      return MTruncateToInt32::New(alloc, rhs);
   3176    }
   3177    return rhs;  // id op x => x
   3178  }
   3179 
   3180  return this;
   3181 }
   3182 
   3183 void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) {
   3184  MOZ_ASSERT(IsNumberType(type()));
   3185 
   3186  // Do not use Float32 if we can use integer types.
   3187  if (!IsFloatingPointType(type())) {
   3188    return;
   3189  }
   3190 
   3191  if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
   3192    setResultType(MIRType::Float32);
   3193  }
   3194 }
   3195 
   3196 void MMinMax::trySpecializeFloat32(TempAllocator& alloc) {
   3197  if (!IsFloatingPointType(type())) {
   3198    return;
   3199  }
   3200 
   3201  MDefinition* left = lhs();
   3202  MDefinition* right = rhs();
   3203 
   3204  if ((left->canProduceFloat32() ||
   3205       (left->isMinMax() && left->type() == MIRType::Float32)) &&
   3206      (right->canProduceFloat32() ||
   3207       (right->isMinMax() && right->type() == MIRType::Float32))) {
   3208    setResultType(MIRType::Float32);
   3209  } else {
   3210    ConvertOperandsToDouble(this, alloc);
   3211  }
   3212 }
   3213 
   3214 template <MIRType Type>
   3215 static MConstant* EvaluateMinMaxInt(TempAllocator& alloc, MConstant* lhs,
   3216                                    MConstant* rhs, bool isMax) {
   3217  auto lnum = ToIntConstant<Type>(lhs);
   3218  auto rnum = ToIntConstant<Type>(rhs);
   3219  auto result = isMax ? std::max(lnum, rnum) : std::min(lnum, rnum);
   3220  return NewIntConstant<Type>(alloc, result);
   3221 }
   3222 
   3223 static MConstant* EvaluateMinMax(TempAllocator& alloc, MConstant* lhs,
   3224                                 MConstant* rhs, bool isMax) {
   3225  MOZ_ASSERT(lhs->type() == rhs->type());
   3226  MOZ_ASSERT(IsNumberType(lhs->type()));
   3227 
   3228  // The folded MConstant should maintain the same MIRType with the original
   3229  // inputs.
   3230  switch (lhs->type()) {
   3231    case MIRType::Int32:
   3232      return EvaluateMinMaxInt<MIRType::Int32>(alloc, lhs, rhs, isMax);
   3233    case MIRType::Int64:
   3234      return EvaluateMinMaxInt<MIRType::Int64>(alloc, lhs, rhs, isMax);
   3235    case MIRType::IntPtr:
   3236      return EvaluateMinMaxInt<MIRType::IntPtr>(alloc, lhs, rhs, isMax);
   3237    case MIRType::Float32:
   3238    case MIRType::Double: {
   3239      double lnum = lhs->numberToDouble();
   3240      double rnum = rhs->numberToDouble();
   3241 
   3242      double result;
   3243      if (isMax) {
   3244        result = js::math_max_impl(lnum, rnum);
   3245      } else {
   3246        result = js::math_min_impl(lnum, rnum);
   3247      }
   3248 
   3249      if (lhs->type() == MIRType::Float32) {
   3250        return MConstant::NewFloat32(alloc, result);
   3251      }
   3252      return MConstant::NewDouble(alloc, result);
   3253    }
   3254    default:
   3255      MOZ_CRASH("not a number type");
   3256  }
   3257 }
   3258 
   3259 MDefinition* MMinMax::foldsTo(TempAllocator& alloc) {
   3260  MOZ_ASSERT(lhs()->type() == type());
   3261  MOZ_ASSERT(rhs()->type() == type());
   3262 
   3263  if (lhs() == rhs()) {
   3264    return lhs();
   3265  }
   3266 
   3267  auto foldConstants = [&alloc](MDefinition* lhs, MDefinition* rhs,
   3268                                bool isMax) -> MConstant* {
   3269    return EvaluateMinMax(alloc, lhs->toConstant(), rhs->toConstant(), isMax);
   3270  };
   3271 
   3272  auto foldLength = [](MDefinition* operand, MConstant* constant,
   3273                       bool isMax) -> MDefinition* {
   3274    if (operand->isArrayLength() || operand->isArrayBufferViewLength() ||
   3275        operand->isArgumentsLength() || operand->isStringLength() ||
   3276        operand->isNonNegativeIntPtrToInt32()) {
   3277      bool isZeroOrNegative;
   3278      switch (constant->type()) {
   3279        case MIRType::Int32:
   3280          isZeroOrNegative = constant->toInt32() <= 0;
   3281          break;
   3282        case MIRType::IntPtr:
   3283          isZeroOrNegative = constant->toIntPtr() <= 0;
   3284          break;
   3285        default:
   3286          isZeroOrNegative = false;
   3287          break;
   3288      }
   3289 
   3290      // (Array|ArrayBufferView|Arguments|String)Length is always >= 0.
   3291      // max(array.length, cte <= 0) = array.length
   3292      // min(array.length, cte <= 0) = cte
   3293      if (isZeroOrNegative) {
   3294        return isMax ? operand : constant;
   3295      }
   3296    }
   3297    return nullptr;
   3298  };
   3299 
   3300  // Try to fold the following patterns when |x| and |y| are constants.
   3301  //
   3302  // min(min(x, z), min(y, z)) = min(min(x, y), z)
   3303  // max(max(x, z), max(y, z)) = max(max(x, y), z)
   3304  // max(min(x, z), min(y, z)) = min(max(x, y), z)
   3305  // min(max(x, z), max(y, z)) = max(min(x, y), z)
   3306  if (lhs()->isMinMax() && rhs()->isMinMax()) {
   3307    do {
   3308      auto* left = lhs()->toMinMax();
   3309      auto* right = rhs()->toMinMax();
   3310      if (left->isMax() != right->isMax()) {
   3311        break;
   3312      }
   3313 
   3314      MDefinition* x;
   3315      MDefinition* y;
   3316      MDefinition* z;
   3317      if (left->lhs() == right->lhs()) {
   3318        std::tie(x, y, z) = std::tuple{left->rhs(), right->rhs(), left->lhs()};
   3319      } else if (left->lhs() == right->rhs()) {
   3320        std::tie(x, y, z) = std::tuple{left->rhs(), right->lhs(), left->lhs()};
   3321      } else if (left->rhs() == right->lhs()) {
   3322        std::tie(x, y, z) = std::tuple{left->lhs(), right->rhs(), left->rhs()};
   3323      } else if (left->rhs() == right->rhs()) {
   3324        std::tie(x, y, z) = std::tuple{left->lhs(), right->lhs(), left->rhs()};
   3325      } else {
   3326        break;
   3327      }
   3328 
   3329      if (!x->isConstant() || !y->isConstant()) {
   3330        break;
   3331      }
   3332 
   3333      if (auto* foldedCst = foldConstants(x, y, isMax())) {
   3334        if (auto* folded = foldLength(z, foldedCst, left->isMax())) {
   3335          return folded;
   3336        }
   3337        block()->insertBefore(this, foldedCst);
   3338        return MMinMax::New(alloc, foldedCst, z, type(), left->isMax());
   3339      }
   3340    } while (false);
   3341  }
   3342 
   3343  // Fold min/max operations with same inputs.
   3344  if (lhs()->isMinMax() || rhs()->isMinMax()) {
   3345    auto* other = lhs()->isMinMax() ? lhs()->toMinMax() : rhs()->toMinMax();
   3346    auto* operand = lhs()->isMinMax() ? rhs() : lhs();
   3347 
   3348    if (operand == other->lhs() || operand == other->rhs()) {
   3349      if (isMax() == other->isMax()) {
   3350        // min(x, min(x, y)) = min(x, y)
   3351        // max(x, max(x, y)) = max(x, y)
   3352        return other;
   3353      }
   3354      if (!IsFloatingPointType(type())) {
   3355        // When neither value is NaN:
   3356        // max(x, min(x, y)) = x
   3357        // min(x, max(x, y)) = x
   3358 
   3359        // Ensure that any bailouts that we depend on to guarantee that |y| is
   3360        // Int32 are not removed.
   3361        auto* otherOp = operand == other->lhs() ? other->rhs() : other->lhs();
   3362        otherOp->setGuardRangeBailoutsUnchecked();
   3363 
   3364        return operand;
   3365      }
   3366    }
   3367  }
   3368 
   3369  if (!lhs()->isConstant() && !rhs()->isConstant()) {
   3370    return this;
   3371  }
   3372 
   3373  // Directly apply math utility to compare the rhs() and lhs() when
   3374  // they are both constants.
   3375  if (lhs()->isConstant() && rhs()->isConstant()) {
   3376    if (auto* folded = foldConstants(lhs(), rhs(), isMax())) {
   3377      return folded;
   3378    }
   3379  }
   3380 
   3381  MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
   3382  MConstant* constant =
   3383      lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
   3384 
   3385  if (operand->isToDouble() &&
   3386      operand->getOperand(0)->type() == MIRType::Int32) {
   3387    MOZ_ASSERT(constant->type() == MIRType::Double);
   3388 
   3389    // min(int32, cte >= INT32_MAX) = int32
   3390    if (!isMax() && constant->toDouble() >= INT32_MAX) {
   3391      MLimitedTruncate* limit = MLimitedTruncate::New(
   3392          alloc, operand->getOperand(0), TruncateKind::NoTruncate);
   3393      block()->insertBefore(this, limit);
   3394      MToDouble* toDouble = MToDouble::New(alloc, limit);
   3395      return toDouble;
   3396    }
   3397 
   3398    // max(int32, cte <= INT32_MIN) = int32
   3399    if (isMax() && constant->toDouble() <= INT32_MIN) {
   3400      MLimitedTruncate* limit = MLimitedTruncate::New(
   3401          alloc, operand->getOperand(0), TruncateKind::NoTruncate);
   3402      block()->insertBefore(this, limit);
   3403      MToDouble* toDouble = MToDouble::New(alloc, limit);
   3404      return toDouble;
   3405    }
   3406  }
   3407 
   3408  if (auto* folded = foldLength(operand, constant, isMax())) {
   3409    return folded;
   3410  }
   3411 
   3412  // Attempt to fold nested min/max operations which are produced by
   3413  // self-hosted built-in functions.
   3414  if (operand->isMinMax()) {
   3415    auto* other = operand->toMinMax();
   3416    MOZ_ASSERT(other->lhs()->type() == type());
   3417    MOZ_ASSERT(other->rhs()->type() == type());
   3418 
   3419    MConstant* otherConstant = nullptr;
   3420    MDefinition* otherOperand = nullptr;
   3421    if (other->lhs()->isConstant()) {
   3422      otherConstant = other->lhs()->toConstant();
   3423      otherOperand = other->rhs();
   3424    } else if (other->rhs()->isConstant()) {
   3425      otherConstant = other->rhs()->toConstant();
   3426      otherOperand = other->lhs();
   3427    }
   3428 
   3429    if (otherConstant) {
   3430      if (isMax() == other->isMax()) {
   3431        // Fold min(x, min(y, z)) to min(min(x, y), z) with constant min(x, y).
   3432        // Fold max(x, max(y, z)) to max(max(x, y), z) with constant max(x, y).
   3433        if (auto* left = foldConstants(constant, otherConstant, isMax())) {
   3434          if (auto* folded = foldLength(otherOperand, left, isMax())) {
   3435            return folded;
   3436          }
   3437          block()->insertBefore(this, left);
   3438          return MMinMax::New(alloc, left, otherOperand, type(), isMax());
   3439        }
   3440      } else {
   3441        // Fold min(x, max(y, z)) to max(min(x, y), min(x, z)).
   3442        // Fold max(x, min(y, z)) to min(max(x, y), max(x, z)).
   3443        //
   3444        // But only do this when min(x, z) can also be simplified.
   3445        if (auto* right = foldLength(otherOperand, constant, isMax())) {
   3446          if (auto* left = foldConstants(constant, otherConstant, isMax())) {
   3447            block()->insertBefore(this, left);
   3448            return MMinMax::New(alloc, left, right, type(), !isMax());
   3449          }
   3450        }
   3451      }
   3452    }
   3453  }
   3454 
   3455  return this;
   3456 }
   3457 
   3458 #ifdef JS_JITSPEW
   3459 void MMinMax::printOpcode(GenericPrinter& out) const {
   3460  MDefinition::printOpcode(out);
   3461  out.printf(" (%s)", isMax() ? "max" : "min");
   3462 }
   3463 
   3464 void MMinMaxArray::printOpcode(GenericPrinter& out) const {
   3465  MDefinition::printOpcode(out);
   3466  out.printf(" (%s)", isMax() ? "max" : "min");
   3467 }
   3468 #endif
   3469 
   3470 MDefinition* MPow::foldsConstant(TempAllocator& alloc) {
   3471  // Both `x` and `p` in `x^p` must be constants in order to precompute.
   3472  if (!input()->isConstant() || !power()->isConstant()) {
   3473    return nullptr;
   3474  }
   3475  if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
   3476    return nullptr;
   3477  }
   3478  if (!input()->toConstant()->isTypeRepresentableAsDouble()) {
   3479    return nullptr;
   3480  }
   3481 
   3482  double x = input()->toConstant()->numberToDouble();
   3483  double p = power()->toConstant()->numberToDouble();
   3484  double result = js::ecmaPow(x, p);
   3485  if (type() == MIRType::Int32) {
   3486    int32_t cast;
   3487    if (!mozilla::NumberIsInt32(result, &cast)) {
   3488      // Reject folding if the result isn't an int32, because we'll bail anyway.
   3489      return nullptr;
   3490    }
   3491    return MConstant::NewInt32(alloc, cast);
   3492  }
   3493  return MConstant::NewDouble(alloc, result);
   3494 }
   3495 
   3496 MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) {
   3497  // If `p` in `x^p` isn't constant, we can't apply these folds.
   3498  if (!power()->isConstant()) {
   3499    return nullptr;
   3500  }
   3501  if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
   3502    return nullptr;
   3503  }
   3504 
   3505  MOZ_ASSERT(type() == MIRType::Double || type() == MIRType::Int32);
   3506 
   3507  // NOTE: The optimizations must match the optimizations used in |js::ecmaPow|
   3508  // resp. |js::powi| to avoid differential testing issues.
   3509 
   3510  double pow = power()->toConstant()->numberToDouble();
   3511 
   3512  // Math.pow(x, 0.5) is a sqrt with edge-case detection.
   3513  if (pow == 0.5) {
   3514    MOZ_ASSERT(type() == MIRType::Double);
   3515    return MPowHalf::New(alloc, input());
   3516  }
   3517 
   3518  // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
   3519  if (pow == -0.5) {
   3520    MOZ_ASSERT(type() == MIRType::Double);
   3521    MPowHalf* half = MPowHalf::New(alloc, input());
   3522    block()->insertBefore(this, half);
   3523    MConstant* one = MConstant::NewDouble(alloc, 1.0);
   3524    block()->insertBefore(this, one);
   3525    return MDiv::New(alloc, one, half, MIRType::Double);
   3526  }
   3527 
   3528  // Math.pow(x, 1) == x.
   3529  if (pow == 1.0) {
   3530    return input();
   3531  }
   3532 
   3533  auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) {
   3534    MMul* mul = MMul::New(alloc, lhs, rhs, type());
   3535    mul->setBailoutKind(bailoutKind());
   3536 
   3537    // Multiplying the same number can't yield negative zero.
   3538    mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero());
   3539    return mul;
   3540  };
   3541 
   3542  // Math.pow(x, 2) == x*x.
   3543  if (pow == 2.0) {
   3544    return multiply(input(), input());
   3545  }
   3546 
   3547  // Math.pow(x, 3) == x*x*x.
   3548  if (pow == 3.0) {
   3549    MMul* mul1 = multiply(input(), input());
   3550    block()->insertBefore(this, mul1);
   3551    return multiply(input(), mul1);
   3552  }
   3553 
   3554  // Math.pow(x, 4) == y*y, where y = x*x.
   3555  if (pow == 4.0) {
   3556    MMul* y = multiply(input(), input());
   3557    block()->insertBefore(this, y);
   3558    return multiply(y, y);
   3559  }
   3560 
   3561  // Math.pow(x, NaN) == NaN.
   3562  if (std::isnan(pow)) {
   3563    return power();
   3564  }
   3565 
   3566  // No optimization
   3567  return nullptr;
   3568 }
   3569 
   3570 MDefinition* MPow::foldsTo(TempAllocator& alloc) {
   3571  if (MDefinition* def = foldsConstant(alloc)) {
   3572    return def;
   3573  }
   3574  if (MDefinition* def = foldsConstantPower(alloc)) {
   3575    return def;
   3576  }
   3577  return this;
   3578 }
   3579 
   3580 MDefinition* MBigIntPow::foldsTo(TempAllocator& alloc) {
   3581  auto* base = lhs();
   3582  MOZ_ASSERT(base->type() == MIRType::BigInt);
   3583 
   3584  auto* power = rhs();
   3585  MOZ_ASSERT(power->type() == MIRType::BigInt);
   3586 
   3587  // |power| must be a constant.
   3588  if (!power->isConstant()) {
   3589    return this;
   3590  }
   3591 
   3592  int32_t pow;
   3593  if (BigInt::isInt32(power->toConstant()->toBigInt(), &pow)) {
   3594    // x ** 1n == x.
   3595    if (pow == 1) {
   3596      return base;
   3597    }
   3598 
   3599    // x ** 2n == x*x.
   3600    if (pow == 2) {
   3601      auto* mul = MBigIntMul::New(alloc, base, base);
   3602      mul->setBailoutKind(bailoutKind());
   3603      return mul;
   3604    }
   3605  }
   3606 
   3607  // No optimization
   3608  return this;
   3609 }
   3610 
   3611 MDefinition* MBigIntAsIntN::foldsTo(TempAllocator& alloc) {
   3612  auto* bitsDef = bits();
   3613  if (!bitsDef->isConstant()) {
   3614    return this;
   3615  }
   3616 
   3617  // Negative |bits| throw an error and too large |bits| don't fit into Int64.
   3618  int32_t bitsInt = bitsDef->toConstant()->toInt32();
   3619  if (bitsInt < 0 || bitsInt > 64) {
   3620    return this;
   3621  }
   3622 
   3623  // Prefer sign-extension if possible.
   3624  bool canSignExtend = false;
   3625  switch (bitsInt) {
   3626    case 8:
   3627    case 16:
   3628    case 32:
   3629    case 64:
   3630      canSignExtend = true;
   3631      break;
   3632  }
   3633 
   3634  // Ensure the input is either IntPtr or Int64 typed.
   3635  auto* inputDef = input();
   3636  if (inputDef->isIntPtrToBigInt()) {
   3637    inputDef = inputDef->toIntPtrToBigInt()->input();
   3638 
   3639    if (!canSignExtend) {
   3640      auto* int64 = MIntPtrToInt64::New(alloc, inputDef);
   3641      block()->insertBefore(this, int64);
   3642      inputDef = int64;
   3643    }
   3644  } else if (inputDef->isInt64ToBigInt()) {
   3645    inputDef = inputDef->toInt64ToBigInt()->input();
   3646  } else {
   3647    auto* truncate = MTruncateBigIntToInt64::New(alloc, inputDef);
   3648    block()->insertBefore(this, truncate);
   3649    inputDef = truncate;
   3650  }
   3651 
   3652  if (inputDef->type() == MIRType::IntPtr) {
   3653    MOZ_ASSERT(canSignExtend);
   3654 
   3655    // If |bits| is larger-or-equal to |BigInt::DigitBits|, return the input.
   3656    if (size_t(bitsInt) >= BigInt::DigitBits) {
   3657      auto* limited = MIntPtrLimitedTruncate::New(alloc, inputDef);
   3658      block()->insertBefore(this, limited);
   3659      inputDef = limited;
   3660    } else {
   3661      MOZ_ASSERT(bitsInt < 64);
   3662 
   3663      // Otherwise extension is the way to go.
   3664      MSignExtendIntPtr::Mode mode;
   3665      switch (bitsInt) {
   3666        case 8:
   3667          mode = MSignExtendIntPtr::Byte;
   3668          break;
   3669        case 16:
   3670          mode = MSignExtendIntPtr::Half;
   3671          break;
   3672        case 32:
   3673          mode = MSignExtendIntPtr::Word;
   3674          break;
   3675      }
   3676 
   3677      auto* extend = MSignExtendIntPtr::New(alloc, inputDef, mode);
   3678      block()->insertBefore(this, extend);
   3679      inputDef = extend;
   3680    }
   3681 
   3682    return MIntPtrToBigInt::New(alloc, inputDef);
   3683  }
   3684  MOZ_ASSERT(inputDef->type() == MIRType::Int64);
   3685 
   3686  if (canSignExtend) {
   3687    // If |bits| is equal to 64, return the input.
   3688    if (bitsInt == 64) {
   3689      auto* limited = MInt64LimitedTruncate::New(alloc, inputDef);
   3690      block()->insertBefore(this, limited);
   3691      inputDef = limited;
   3692    } else {
   3693      MOZ_ASSERT(bitsInt < 64);
   3694 
   3695      // Otherwise extension is the way to go.
   3696      MSignExtendInt64::Mode mode;
   3697      switch (bitsInt) {
   3698        case 8:
   3699          mode = MSignExtendInt64::Byte;
   3700          break;
   3701        case 16:
   3702          mode = MSignExtendInt64::Half;
   3703          break;
   3704        case 32:
   3705          mode = MSignExtendInt64::Word;
   3706          break;
   3707      }
   3708 
   3709      auto* extend = MSignExtendInt64::New(alloc, inputDef, mode);
   3710      block()->insertBefore(this, extend);
   3711      inputDef = extend;
   3712    }
   3713  } else {
   3714    MOZ_ASSERT(bitsInt < 64);
   3715 
   3716    uint64_t mask = 0;
   3717    if (bitsInt > 0) {
   3718      mask = uint64_t(-1) >> (64 - bitsInt);
   3719    }
   3720 
   3721    auto* cst = MConstant::NewInt64(alloc, int64_t(mask));
   3722    block()->insertBefore(this, cst);
   3723 
   3724    // Mask off any excess bits.
   3725    auto* bitAnd = MBitAnd::New(alloc, inputDef, cst, MIRType::Int64);
   3726    block()->insertBefore(this, bitAnd);
   3727 
   3728    auto* shift = MConstant::NewInt64(alloc, int64_t(64 - bitsInt));
   3729    block()->insertBefore(this, shift);
   3730 
   3731    // Left-shift to make the sign-bit the left-most bit.
   3732    auto* lsh = MLsh::New(alloc, bitAnd, shift, MIRType::Int64);
   3733    block()->insertBefore(this, lsh);
   3734 
   3735    // Right-shift to propagate the sign-bit.
   3736    auto* rsh = MRsh::New(alloc, lsh, shift, MIRType::Int64);
   3737    block()->insertBefore(this, rsh);
   3738 
   3739    inputDef = rsh;
   3740  }
   3741 
   3742  return MInt64ToBigInt::New(alloc, inputDef, /* isSigned = */ true);
   3743 }
   3744 
   3745 MDefinition* MBigIntAsUintN::foldsTo(TempAllocator& alloc) {
   3746  auto* bitsDef = bits();
   3747  if (!bitsDef->isConstant()) {
   3748    return this;
   3749  }
   3750 
   3751  // Negative |bits| throw an error and too large |bits| don't fit into Int64.
   3752  int32_t bitsInt = bitsDef->toConstant()->toInt32();
   3753  if (bitsInt < 0 || bitsInt > 64) {
   3754    return this;
   3755  }
   3756 
   3757  // Ensure the input is Int64 typed.
   3758  auto* inputDef = input();
   3759  if (inputDef->isIntPtrToBigInt()) {
   3760    inputDef = inputDef->toIntPtrToBigInt()->input();
   3761 
   3762    auto* int64 = MIntPtrToInt64::New(alloc, inputDef);
   3763    block()->insertBefore(this, int64);
   3764    inputDef = int64;
   3765  } else if (inputDef->isInt64ToBigInt()) {
   3766    inputDef = inputDef->toInt64ToBigInt()->input();
   3767  } else {
   3768    auto* truncate = MTruncateBigIntToInt64::New(alloc, inputDef);
   3769    block()->insertBefore(this, truncate);
   3770    inputDef = truncate;
   3771  }
   3772  MOZ_ASSERT(inputDef->type() == MIRType::Int64);
   3773 
   3774  if (bitsInt < 64) {
   3775    uint64_t mask = 0;
   3776    if (bitsInt > 0) {
   3777      mask = uint64_t(-1) >> (64 - bitsInt);
   3778    }
   3779 
   3780    // Mask off any excess bits.
   3781    auto* cst = MConstant::NewInt64(alloc, int64_t(mask));
   3782    block()->insertBefore(this, cst);
   3783 
   3784    auto* bitAnd = MBitAnd::New(alloc, inputDef, cst, MIRType::Int64);
   3785    block()->insertBefore(this, bitAnd);
   3786 
   3787    inputDef = bitAnd;
   3788  }
   3789 
   3790  return MInt64ToBigInt::New(alloc, inputDef, /* isSigned = */ false);
   3791 }
   3792 
   3793 bool MBigIntPtrBinaryArithInstruction::isMaybeZero(MDefinition* ins) {
   3794  MOZ_ASSERT(ins->type() == MIRType::IntPtr);
   3795  if (ins->isBigIntToIntPtr()) {
   3796    ins = ins->toBigIntToIntPtr()->input();
   3797  }
   3798  if (ins->isConstant()) {
   3799    if (ins->type() == MIRType::IntPtr) {
   3800      return ins->toConstant()->toIntPtr() == 0;
   3801    }
   3802    MOZ_ASSERT(ins->type() == MIRType::BigInt);
   3803    return ins->toConstant()->toBigInt()->isZero();
   3804  }
   3805  return true;
   3806 }
   3807 
   3808 bool MBigIntPtrBinaryArithInstruction::isMaybeNegative(MDefinition* ins) {
   3809  MOZ_ASSERT(ins->type() == MIRType::IntPtr);
   3810  if (ins->isBigIntToIntPtr()) {
   3811    ins = ins->toBigIntToIntPtr()->input();
   3812  }
   3813  if (ins->isConstant()) {
   3814    if (ins->type() == MIRType::IntPtr) {
   3815      return ins->toConstant()->toIntPtr() < 0;
   3816    }
   3817    MOZ_ASSERT(ins->type() == MIRType::BigInt);
   3818    return ins->toConstant()->toBigInt()->isNegative();
   3819  }
   3820  return true;
   3821 }
   3822 
   3823 MDefinition* MBigIntPtrBinaryArithInstruction::foldsTo(TempAllocator& alloc) {
   3824  if (auto* folded = EvaluateIntPtrConstantOperands(alloc, this)) {
   3825    return folded;
   3826  }
   3827  return this;
   3828 }
   3829 
   3830 MDefinition* MBigIntPtrPow::foldsTo(TempAllocator& alloc) {
   3831  // Follow MPow::foldsTo and fold if:
   3832  // 1. Both operands are constants.
   3833  // 2. The power operand is ≤ 4 and the operation can be expressed as a series
   3834  //    of multiplications.
   3835 
   3836  if (!rhs()->isConstant()) {
   3837    return this;
   3838  }
   3839  intptr_t pow = rhs()->toConstant()->toIntPtr();
   3840 
   3841  if (lhs()->isConstant()) {
   3842    intptr_t base = lhs()->toConstant()->toIntPtr();
   3843    intptr_t result;
   3844    if (!BigInt::powIntPtr(base, pow, &result)) {
   3845      return this;
   3846    }
   3847    return MConstant::NewIntPtr(alloc, result);
   3848  }
   3849 
   3850  if (pow == 1) {
   3851    return lhs();
   3852  }
   3853 
   3854  auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) {
   3855    auto* mul = MBigIntPtrMul::New(alloc, lhs, rhs);
   3856    mul->setBailoutKind(bailoutKind());
   3857    return mul;
   3858  };
   3859 
   3860  // (x ** 2n) == x*x.
   3861  if (pow == 2) {
   3862    return multiply(lhs(), lhs());
   3863  }
   3864 
   3865  // (x ** 3n) == x*x*x.
   3866  if (pow == 3) {
   3867    auto* mul1 = multiply(lhs(), lhs());
   3868    block()->insertBefore(this, mul1);
   3869    return multiply(lhs(), mul1);
   3870  }
   3871 
   3872  // (x ** 4n) == y*y, where y = x*x.
   3873  if (pow == 4) {
   3874    auto* y = multiply(lhs(), lhs());
   3875    block()->insertBefore(this, y);
   3876    return multiply(y, y);
   3877  }
   3878 
   3879  // No optimization
   3880  return this;
   3881 }
   3882 
   3883 MDefinition* MBigIntPtrBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) {
   3884  if (auto* folded = EvaluateIntPtrConstantOperands(alloc, this)) {
   3885    return folded;
   3886  }
   3887  return this;
   3888 }
   3889 
   3890 MDefinition* MBigIntPtrBitNot::foldsTo(TempAllocator& alloc) {
   3891  if (!input()->isConstant()) {
   3892    return this;
   3893  }
   3894  return MConstant::NewIntPtr(alloc, ~input()->toConstant()->toIntPtr());
   3895 }
   3896 
   3897 MDefinition* MInt32ToIntPtr::foldsTo(TempAllocator& alloc) {
   3898  MDefinition* def = input();
   3899  if (def->isConstant()) {
   3900    int32_t i = def->toConstant()->toInt32();
   3901    return MConstant::NewIntPtr(alloc, intptr_t(i));
   3902  }
   3903 
   3904  if (def->isNonNegativeIntPtrToInt32()) {
   3905    return def->toNonNegativeIntPtrToInt32()->input();
   3906  }
   3907 
   3908  return this;
   3909 }
   3910 
   3911 bool MAbs::fallible() const {
   3912  return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
   3913 }
   3914 
   3915 void MAbs::trySpecializeFloat32(TempAllocator& alloc) {
   3916  // Do not use Float32 if we can use int32.
   3917  if (input()->type() == MIRType::Int32) {
   3918    return;
   3919  }
   3920 
   3921  if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
   3922    setResultType(MIRType::Float32);
   3923  }
   3924 }
   3925 
   3926 MDefinition* MDiv::foldsTo(TempAllocator& alloc) {
   3927  MOZ_ASSERT(IsNumberType(type()));
   3928  MOZ_ASSERT(type() != MIRType::IntPtr, "not yet implemented");
   3929 
   3930  if (type() == MIRType::Int64) {
   3931    if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
   3932      return folded;
   3933    }
   3934    return this;
   3935  }
   3936 
   3937  if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
   3938    return folded;
   3939  }
   3940 
   3941  if (MDefinition* folded = EvaluateExactReciprocal(alloc, this)) {
   3942    return folded;
   3943  }
   3944 
   3945  return this;
   3946 }
   3947 
   3948 void MDiv::analyzeEdgeCasesForward() {
   3949  // This is only meaningful when doing integer division.
   3950  if (type() != MIRType::Int32) {
   3951    return;
   3952  }
   3953 
   3954  MOZ_ASSERT(lhs()->type() == MIRType::Int32);
   3955  MOZ_ASSERT(rhs()->type() == MIRType::Int32);
   3956 
   3957  // Try removing divide by zero check
   3958  if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
   3959    canBeDivideByZero_ = false;
   3960  }
   3961 
   3962  // If lhs is a constant int != INT32_MIN, then
   3963  // negative overflow check can be skipped.
   3964  if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN)) {
   3965    canBeNegativeOverflow_ = false;
   3966  }
   3967 
   3968  // If rhs is a constant int != -1, likewise.
   3969  if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) {
   3970    canBeNegativeOverflow_ = false;
   3971  }
   3972 
   3973  // If lhs is != 0, then negative zero check can be skipped.
   3974  if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) {
   3975    setCanBeNegativeZero(false);
   3976  }
   3977 
   3978  // If rhs is >= 0, likewise.
   3979  if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
   3980    if (rhs()->toConstant()->toInt32() >= 0) {
   3981      setCanBeNegativeZero(false);
   3982    }
   3983  }
   3984 }
   3985 
   3986 void MDiv::analyzeEdgeCasesBackward() {
   3987  // In general, canBeNegativeZero_ is only valid for integer divides.
   3988  // It's fine to access here because we're only using it to avoid
   3989  // wasting effort to decide whether we can clear an already cleared
   3990  // flag.
   3991  if (canBeNegativeZero_ && !NeedNegativeZeroCheck(this)) {
   3992    setCanBeNegativeZero(false);
   3993  }
   3994 }
   3995 
   3996 bool MDiv::fallible() const { return !isTruncated(); }
   3997 
   3998 MDefinition* MMod::foldsTo(TempAllocator& alloc) {
   3999  MOZ_ASSERT(IsNumberType(type()));
   4000  MOZ_ASSERT(type() != MIRType::IntPtr, "not yet implemented");
   4001 
   4002  if (type() == MIRType::Int64) {
   4003    if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
   4004      return folded;
   4005    }
   4006  } else {
   4007    if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
   4008      return folded;
   4009    }
   4010  }
   4011  return this;
   4012 }
   4013 
   4014 void MMod::analyzeEdgeCasesForward() {
   4015  // These optimizations make sense only for integer division
   4016  if (type() != MIRType::Int32) {
   4017    return;
   4018  }
   4019 
   4020  if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
   4021    canBeDivideByZero_ = false;
   4022  }
   4023 
   4024  if (rhs()->isConstant()) {
   4025    int32_t n = rhs()->toConstant()->toInt32();
   4026    if (n > 0 && !IsPowerOfTwo(uint32_t(n))) {
   4027      canBePowerOfTwoDivisor_ = false;
   4028    }
   4029  }
   4030 }
   4031 
   4032 bool MMod::fallible() const {
   4033  return !isTruncated() &&
   4034         (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
   4035 }
   4036 
   4037 void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) {
   4038  if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
   4039    setResultType(MIRType::Float32);
   4040    specialization_ = MIRType::Float32;
   4041  }
   4042 }
   4043 
   4044 bool MMathFunction::isFloat32Commutative() const {
   4045  switch (function_) {
   4046    case UnaryMathFunction::Floor:
   4047    case UnaryMathFunction::Ceil:
   4048    case UnaryMathFunction::Round:
   4049    case UnaryMathFunction::Trunc:
   4050      return true;
   4051    default:
   4052      return false;
   4053  }
   4054 }
   4055 
   4056 MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector& vector) {
   4057  uint32_t length = vector.length();
   4058  MHypot* hypot = new (alloc) MHypot;
   4059  if (!hypot->init(alloc, length)) {
   4060    return nullptr;
   4061  }
   4062 
   4063  for (uint32_t i = 0; i < length; ++i) {
   4064    hypot->initOperand(i, vector[i]);
   4065  }
   4066  return hypot;
   4067 }
   4068 
   4069 bool MAdd::fallible() const {
   4070  // the add is fallible if range analysis does not say that it is finite, AND
   4071  // either the truncation analysis shows that there are non-truncated uses.
   4072  if (truncateKind() >= TruncateKind::IndirectTruncate) {
   4073    return false;
   4074  }
   4075  if (range() && range()->hasInt32Bounds()) {
   4076    return false;
   4077  }
   4078  return true;
   4079 }
   4080 
   4081 bool MSub::fallible() const {
   4082  // see comment in MAdd::fallible()
   4083  if (truncateKind() >= TruncateKind::IndirectTruncate) {
   4084    return false;
   4085  }
   4086  if (range() && range()->hasInt32Bounds()) {
   4087    return false;
   4088  }
   4089  return true;
   4090 }
   4091 
   4092 MDefinition* MSub::foldsTo(TempAllocator& alloc) {
   4093  MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
   4094  if (out != this) {
   4095    return out;
   4096  }
   4097 
   4098  // Optimize X - X to 0. This optimization is only valid for integer values.
   4099  // Subtracting a floating point value from itself returns NaN when the operand
   4100  // is either Infinity or NaN.
   4101  if (lhs() == rhs()) {
   4102    switch (type()) {
   4103      case MIRType::Int32:
   4104        // Ensure that any bailouts that we depend on to guarantee that X
   4105        // is Int32 are not removed.
   4106        lhs()->setGuardRangeBailoutsUnchecked();
   4107        return MConstant::NewInt32(alloc, 0);
   4108      case MIRType::Int64:
   4109        return MConstant::NewInt64(alloc, 0);
   4110      case MIRType::IntPtr:
   4111        return MConstant::NewIntPtr(alloc, 0);
   4112      default:
   4113        MOZ_ASSERT(IsFloatingPointType(type()));
   4114    }
   4115  }
   4116 
   4117  return this;
   4118 }
   4119 
   4120 MDefinition* MMul::foldsTo(TempAllocator& alloc) {
   4121  MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
   4122  if (out != this) {
   4123    return out;
   4124  }
   4125 
   4126  if (type() != MIRType::Int32) {
   4127    return this;
   4128  }
   4129 
   4130  if (lhs() == rhs()) {
   4131    setCanBeNegativeZero(false);
   4132  }
   4133 
   4134  return this;
   4135 }
   4136 
   4137 void MMul::analyzeEdgeCasesForward() {
   4138  // Try to remove the check for negative zero
   4139  // This only makes sense when using the integer multiplication
   4140  if (type() != MIRType::Int32) {
   4141    return;
   4142  }
   4143 
   4144  // If lhs is > 0, no need for negative zero check.
   4145  if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) {
   4146    if (lhs()->toConstant()->toInt32() > 0) {
   4147      setCanBeNegativeZero(false);
   4148    }
   4149  }
   4150 
   4151  // If rhs is > 0, likewise.
   4152  if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
   4153    if (rhs()->toConstant()->toInt32() > 0) {
   4154      setCanBeNegativeZero(false);
   4155    }
   4156  }
   4157 }
   4158 
   4159 void MMul::analyzeEdgeCasesBackward() {
   4160  if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
   4161    setCanBeNegativeZero(false);
   4162  }
   4163 }
   4164 
   4165 bool MMul::canOverflow() const {
   4166  if (isTruncated()) {
   4167    return false;
   4168  }
   4169  return !range() || !range()->hasInt32Bounds();
   4170 }
   4171 
   4172 bool MUrsh::fallible() const {
   4173  if (bailoutsDisabled()) {
   4174    return false;
   4175  }
   4176  return !range() || !range()->hasInt32Bounds();
   4177 }
   4178 
   4179 static inline bool MustBeUInt32(MDefinition* def, MDefinition** pwrapped) {
   4180  if (def->isUrsh()) {
   4181    *pwrapped = def->toUrsh()->lhs();
   4182    MDefinition* rhs = def->toUrsh()->rhs();
   4183    return def->toUrsh()->bailoutsDisabled() && rhs->maybeConstantValue() &&
   4184           rhs->maybeConstantValue()->isInt32(0);
   4185  }
   4186 
   4187  if (MConstant* defConst = def->maybeConstantValue()) {
   4188    *pwrapped = defConst;
   4189    return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0;
   4190  }
   4191 
   4192  *pwrapped = nullptr;  // silence GCC warning
   4193  return false;
   4194 }
   4195 
   4196 /* static */
   4197 bool MBinaryInstruction::unsignedOperands(MDefinition* left,
   4198                                          MDefinition* right) {
   4199  MDefinition* replace;
   4200  if (!MustBeUInt32(left, &replace)) {
   4201    return false;
   4202  }
   4203  if (replace->type() != MIRType::Int32) {
   4204    return false;
   4205  }
   4206  if (!MustBeUInt32(right, &replace)) {
   4207    return false;
   4208  }
   4209  if (replace->type() != MIRType::Int32) {
   4210    return false;
   4211  }
   4212  return true;
   4213 }
   4214 
   4215 bool MBinaryInstruction::unsignedOperands() {
   4216  return unsignedOperands(getOperand(0), getOperand(1));
   4217 }
   4218 
   4219 void MBinaryInstruction::replaceWithUnsignedOperands() {
   4220  MOZ_ASSERT(unsignedOperands());
   4221 
   4222  for (size_t i = 0; i < numOperands(); i++) {
   4223    MDefinition* replace;
   4224    MustBeUInt32(getOperand(i), &replace);
   4225    if (replace == getOperand(i)) {
   4226      continue;
   4227    }
   4228 
   4229    getOperand(i)->setImplicitlyUsedUnchecked();
   4230    replaceOperand(i, replace);
   4231  }
   4232 }
   4233 
   4234 MDefinition* MBitNot::foldsTo(TempAllocator& alloc) {
   4235  if (type() == MIRType::Int64) {
   4236    return this;
   4237  }
   4238  MOZ_ASSERT(type() == MIRType::Int32);
   4239 
   4240  MDefinition* input = getOperand(0);
   4241 
   4242  if (input->isConstant()) {
   4243    int32_t v = ~(input->toConstant()->toInt32());
   4244    return MConstant::NewInt32(alloc, v);
   4245  }
   4246 
   4247  if (input->isBitNot()) {
   4248    MOZ_ASSERT(input->toBitNot()->type() == MIRType::Int32);
   4249    MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType::Int32);
   4250    return MTruncateToInt32::New(alloc,
   4251                                 input->toBitNot()->input());  // ~~x => x | 0
   4252  }
   4253 
   4254  return this;
   4255 }
   4256 
   4257 static void AssertKnownClass(TempAllocator& alloc, MInstruction* ins,
   4258                             MDefinition* obj) {
   4259 #ifdef DEBUG
   4260  const JSClass* clasp = GetObjectKnownJSClass(obj);
   4261  MOZ_ASSERT(clasp);
   4262 
   4263  auto* assert = MAssertClass::New(alloc, obj, clasp);
   4264  ins->block()->insertBefore(ins, assert);
   4265 #endif
   4266 }
   4267 
   4268 MDefinition* MBoxNonStrictThis::foldsTo(TempAllocator& alloc) {
   4269  MDefinition* in = input();
   4270 
   4271  if (!in->isBox()) {
   4272    return this;
   4273  }
   4274 
   4275  MDefinition* unboxed = in->toBox()->input();
   4276  if (unboxed->type() == MIRType::Object) {
   4277    return unboxed;
   4278  }
   4279 
   4280  if (unboxed->typeIsOneOf({MIRType::Undefined, MIRType::Null})) {
   4281    return MConstant::NewObject(alloc, this->globalThis());
   4282  }
   4283 
   4284  return this;
   4285 }
   4286 
   4287 AliasSet MLoadArgumentsObjectArg::getAliasSet() const {
   4288  return AliasSet::Load(AliasSet::Any);
   4289 }
   4290 
   4291 AliasSet MLoadArgumentsObjectArgHole::getAliasSet() const {
   4292  return AliasSet::Load(AliasSet::Any);
   4293 }
   4294 
   4295 AliasSet MInArgumentsObjectArg::getAliasSet() const {
   4296  // Loads |arguments.length|, but not the actual element, so we can use the
   4297  // same alias-set as MArgumentsObjectLength.
   4298  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   4299                        AliasSet::DynamicSlot);
   4300 }
   4301 
   4302 AliasSet MArgumentsObjectLength::getAliasSet() const {
   4303  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   4304                        AliasSet::DynamicSlot);
   4305 }
   4306 
   4307 bool MGuardArgumentsObjectFlags::congruentTo(const MDefinition* ins) const {
   4308  if (!ins->isGuardArgumentsObjectFlags() ||
   4309      ins->toGuardArgumentsObjectFlags()->flags() != flags()) {
   4310    return false;
   4311  }
   4312  return congruentIfOperandsEqual(ins);
   4313 }
   4314 
   4315 AliasSet MGuardArgumentsObjectFlags::getAliasSet() const {
   4316  // The flags are packed with the length in a fixed private slot.
   4317  return AliasSet::Load(AliasSet::FixedSlot);
   4318 }
   4319 
   4320 MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) {
   4321  if (idVal()->isBox()) {
   4322    auto* input = idVal()->toBox()->input();
   4323    MIRType idType = input->type();
   4324    if (idType == MIRType::String || idType == MIRType::Symbol) {
   4325      return idVal();
   4326    }
   4327    if (idType == MIRType::Int32) {
   4328      auto* toString =
   4329          MToString::New(alloc, input, MToString::SideEffectHandling::Bailout);
   4330      block()->insertBefore(this, toString);
   4331 
   4332      return MBox::New(alloc, toString);
   4333    }
   4334  }
   4335 
   4336  return this;
   4337 }
   4338 
   4339 MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) {
   4340  MDefinition* rval = value();
   4341  if (!rval->isBox()) {
   4342    return this;
   4343  }
   4344 
   4345  MDefinition* unboxed = rval->toBox()->input();
   4346  if (unboxed->type() == MIRType::Object) {
   4347    return unboxed;
   4348  }
   4349 
   4350  return object();
   4351 }
   4352 
   4353 MDefinition* MTypeOf::foldsTo(TempAllocator& alloc) {
   4354  MDefinition* unboxed = input();
   4355  if (unboxed->isBox()) {
   4356    unboxed = unboxed->toBox()->input();
   4357  }
   4358 
   4359  JSType type;
   4360  switch (unboxed->type()) {
   4361    case MIRType::Double:
   4362    case MIRType::Float32:
   4363    case MIRType::Int32:
   4364      type = JSTYPE_NUMBER;
   4365      break;
   4366    case MIRType::String:
   4367      type = JSTYPE_STRING;
   4368      break;
   4369    case MIRType::Symbol:
   4370      type = JSTYPE_SYMBOL;
   4371      break;
   4372    case MIRType::BigInt:
   4373      type = JSTYPE_BIGINT;
   4374      break;
   4375    case MIRType::Null:
   4376      type = JSTYPE_OBJECT;
   4377      break;
   4378    case MIRType::Undefined:
   4379      type = JSTYPE_UNDEFINED;
   4380      break;
   4381    case MIRType::Boolean:
   4382      type = JSTYPE_BOOLEAN;
   4383      break;
   4384    case MIRType::Object: {
   4385      KnownClass known = GetObjectKnownClass(unboxed);
   4386      if (known != KnownClass::None) {
   4387        if (known == KnownClass::Function) {
   4388          type = JSTYPE_FUNCTION;
   4389        } else {
   4390          type = JSTYPE_OBJECT;
   4391        }
   4392 
   4393        AssertKnownClass(alloc, this, unboxed);
   4394        break;
   4395      }
   4396      [[fallthrough]];
   4397    }
   4398    default:
   4399      return this;
   4400  }
   4401 
   4402  return MConstant::NewInt32(alloc, static_cast<int32_t>(type));
   4403 }
   4404 
   4405 MDefinition* MTypeOfName::foldsTo(TempAllocator& alloc) {
   4406  MOZ_ASSERT(input()->type() == MIRType::Int32);
   4407 
   4408  if (!input()->isConstant()) {
   4409    return this;
   4410  }
   4411 
   4412  static_assert(JSTYPE_UNDEFINED == 0);
   4413 
   4414  int32_t type = input()->toConstant()->toInt32();
   4415  MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT);
   4416 
   4417  JSString* name =
   4418      TypeName(static_cast<JSType>(type), GetJitContext()->runtime->names());
   4419  return MConstant::NewString(alloc, name);
   4420 }
   4421 
   4422 MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left,
   4423                      MDefinition* right, MIRType type) {
   4424  MUrsh* ins = new (alloc) MUrsh(left, right, type);
   4425 
   4426  // Since Ion has no UInt32 type, we use Int32 and we have a special
   4427  // exception to the type rules: we can return values in
   4428  // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
   4429  // without bailing out. This is necessary because Ion has no UInt32
   4430  // type and we can't have bailouts in wasm code.
   4431  ins->bailoutsDisabled_ = true;
   4432 
   4433  return ins;
   4434 }
   4435 
   4436 MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block,
   4437                                jsbytecode* pc, ResumeMode mode) {
   4438  MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode);
   4439  if (!resume->init(alloc)) {
   4440    block->discardPreAllocatedResumePoint(resume);
   4441    return nullptr;
   4442  }
   4443  resume->inherit(block);
   4444  return resume;
   4445 }
   4446 
   4447 MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode)
   4448    : MNode(block, Kind::ResumePoint),
   4449      pc_(pc),
   4450      instruction_(nullptr),
   4451      mode_(mode) {
   4452  block->addResumePoint(this);
   4453 }
   4454 
   4455 bool MResumePoint::init(TempAllocator& alloc) {
   4456  return operands_.init(alloc, block()->stackDepth());
   4457 }
   4458 
   4459 MResumePoint* MResumePoint::caller() const {
   4460  return block()->callerResumePoint();
   4461 }
   4462 
   4463 void MResumePoint::inherit(MBasicBlock* block) {
   4464  // FixedList doesn't initialize its elements, so do unchecked inits.
   4465  for (size_t i = 0; i < stackDepth(); i++) {
   4466    initOperand(i, block->getSlot(i));
   4467  }
   4468 }
   4469 
   4470 void MResumePoint::addStore(TempAllocator& alloc, MDefinition* store,
   4471                            const MResumePoint* cache) {
   4472  MOZ_ASSERT(block()->outerResumePoint() != this);
   4473  MOZ_ASSERT_IF(cache, !cache->stores_.empty());
   4474 
   4475  if (cache && cache->stores_.begin()->operand == store) {
   4476    // If the last resume point had the same side-effect stack, then we can
   4477    // reuse the current side effect without cloning it. This is a simple
   4478    // way to share common context by making a spaghetti stack.
   4479    if (++cache->stores_.begin() == stores_.begin()) {
   4480      stores_.copy(cache->stores_);
   4481      return;
   4482    }
   4483  }
   4484 
   4485  // Ensure that the store would not be deleted by DCE.
   4486  MOZ_ASSERT(store->isEffectful());
   4487 
   4488  MStoreToRecover* top = new (alloc) MStoreToRecover(store);
   4489  stores_.push(top);
   4490 }
   4491 
   4492 #ifdef JS_JITSPEW
   4493 void MResumePoint::dump(GenericPrinter& out) const {
   4494  out.printf("resumepoint mode=");
   4495 
   4496  switch (mode()) {
   4497    case ResumeMode::ResumeAt:
   4498      if (instruction_) {
   4499        out.printf("ResumeAt(%u)", instruction_->id());
   4500      } else {
   4501        out.printf("ResumeAt");
   4502      }
   4503      break;
   4504    default:
   4505      out.put(ResumeModeToString(mode()));
   4506      break;
   4507  }
   4508 
   4509  if (MResumePoint* c = caller()) {
   4510    out.printf(" (caller in block%u)", c->block()->id());
   4511  }
   4512 
   4513  for (size_t i = 0; i < numOperands(); i++) {
   4514    out.printf(" ");
   4515    if (operands_[i].hasProducer()) {
   4516      getOperand(i)->printName(out);
   4517    } else {
   4518      out.printf("(null)");
   4519    }
   4520  }
   4521  out.printf("\n");
   4522 }
   4523 
   4524 void MResumePoint::dump() const {
   4525  Fprinter out(stderr);
   4526  dump(out);
   4527  out.finish();
   4528 }
   4529 #endif
   4530 
   4531 bool MResumePoint::isObservableOperand(MUse* u) const {
   4532  return isObservableOperand(indexOf(u));
   4533 }
   4534 
   4535 bool MResumePoint::isObservableOperand(size_t index) const {
   4536  return block()->info().isObservableSlot(index);
   4537 }
   4538 
   4539 bool MResumePoint::isRecoverableOperand(MUse* u) const {
   4540  return block()->info().isRecoverableOperand(indexOf(u));
   4541 }
   4542 
   4543 MDefinition* MBigIntToIntPtr::foldsTo(TempAllocator& alloc) {
   4544  MDefinition* def = input();
   4545 
   4546  // If the operand converts an IntPtr to BigInt, drop both conversions.
   4547  if (def->isIntPtrToBigInt()) {
   4548    return def->toIntPtrToBigInt()->input();
   4549  }
   4550 
   4551  // Fold this operation if the input operand is constant.
   4552  if (def->isConstant()) {
   4553    BigInt* bigInt = def->toConstant()->toBigInt();
   4554    intptr_t i;
   4555    if (BigInt::isIntPtr(bigInt, &i)) {
   4556      return MConstant::NewIntPtr(alloc, i);
   4557    }
   4558  }
   4559 
   4560  // Fold BigIntToIntPtr(Int64ToBigInt(int64)) to Int64ToIntPtr(int64)
   4561  if (def->isInt64ToBigInt()) {
   4562    auto* toBigInt = def->toInt64ToBigInt();
   4563    return MInt64ToIntPtr::New(alloc, toBigInt->input(), toBigInt->isSigned());
   4564  }
   4565 
   4566  return this;
   4567 }
   4568 
   4569 MDefinition* MIntPtrToBigInt::foldsTo(TempAllocator& alloc) {
   4570  MDefinition* def = input();
   4571 
   4572  // If the operand converts a BigInt to IntPtr, drop both conversions.
   4573  if (def->isBigIntToIntPtr()) {
   4574    return def->toBigIntToIntPtr()->input();
   4575  }
   4576 
   4577  return this;
   4578 }
   4579 
   4580 MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) {
   4581  MDefinition* input = this->input();
   4582  MOZ_ASSERT(input->type() == MIRType::BigInt);
   4583 
   4584  // If the operand converts an I64 to BigInt, drop both conversions.
   4585  if (input->isInt64ToBigInt()) {
   4586    return input->toInt64ToBigInt()->input();
   4587  }
   4588 
   4589  // If the operand is an IntPtr, extend the IntPtr to I64.
   4590  if (input->isIntPtrToBigInt()) {
   4591    auto* intPtr = input->toIntPtrToBigInt()->input();
   4592    if (intPtr->isConstant()) {
   4593      intptr_t c = intPtr->toConstant()->toIntPtr();
   4594      return MConstant::NewInt64(alloc, int64_t(c));
   4595    }
   4596    return MIntPtrToInt64::New(alloc, intPtr);
   4597  }
   4598 
   4599  // Fold this operation if the input operand is constant.
   4600  if (input->isConstant()) {
   4601    return MConstant::NewInt64(
   4602        alloc, BigInt::toInt64(input->toConstant()->toBigInt()));
   4603  }
   4604 
   4605  return this;
   4606 }
   4607 
   4608 MDefinition* MToInt64::foldsTo(TempAllocator& alloc) {
   4609  MDefinition* input = getOperand(0);
   4610 
   4611  if (input->isBox()) {
   4612    input = input->getOperand(0);
   4613  }
   4614 
   4615  // Unwrap MInt64ToBigInt: MToInt64(MInt64ToBigInt(int64)) = int64.
   4616  if (input->isInt64ToBigInt()) {
   4617    return input->getOperand(0);
   4618  }
   4619 
   4620  // Unwrap IntPtrToBigInt:
   4621  // MToInt64(MIntPtrToBigInt(intptr)) = MIntPtrToInt64(intptr).
   4622  if (input->isIntPtrToBigInt()) {
   4623    auto* intPtr = input->toIntPtrToBigInt()->input();
   4624    if (intPtr->isConstant()) {
   4625      intptr_t c = intPtr->toConstant()->toIntPtr();
   4626      return MConstant::NewInt64(alloc, int64_t(c));
   4627    }
   4628    return MIntPtrToInt64::New(alloc, intPtr);
   4629  }
   4630 
   4631  // When the input is an Int64 already, just return it.
   4632  if (input->type() == MIRType::Int64) {
   4633    return input;
   4634  }
   4635 
   4636  // Fold this operation if the input operand is constant.
   4637  if (input->isConstant()) {
   4638    switch (input->type()) {
   4639      case MIRType::Boolean:
   4640        return MConstant::NewInt64(alloc, input->toConstant()->toBoolean());
   4641      default:
   4642        break;
   4643    }
   4644  }
   4645 
   4646  return this;
   4647 }
   4648 
   4649 MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) {
   4650  // Fold this operation if the input operand is constant.
   4651  if (MConstant* cst = input()->maybeConstantValue()) {
   4652    switch (cst->type()) {
   4653      case MIRType::Null:
   4654        if (conversion() == IntConversionInputKind::Any) {
   4655          return MConstant::NewInt32(alloc, 0);
   4656        }
   4657        break;
   4658      case MIRType::Boolean:
   4659        if (conversion() == IntConversionInputKind::Any) {
   4660          return MConstant::NewInt32(alloc, cst->toBoolean());
   4661        }
   4662        break;
   4663      case MIRType::Int32:
   4664        return MConstant::NewInt32(alloc, cst->toInt32());
   4665      case MIRType::Float32:
   4666      case MIRType::Double:
   4667        int32_t ival;
   4668        // Only the value within the range of Int32 can be substituted as
   4669        // constant.
   4670        if (mozilla::NumberIsInt32(cst->numberToDouble(), &ival)) {
   4671          return MConstant::NewInt32(alloc, ival);
   4672        }
   4673        break;
   4674      default:
   4675        break;
   4676    }
   4677  }
   4678 
   4679  MDefinition* input = getOperand(0);
   4680  if (input->isBox()) {
   4681    input = input->toBox()->input();
   4682  }
   4683 
   4684  // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
   4685  // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
   4686  // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
   4687  // is folded to a MTruncateToInt32 node, which will result in this MIR:
   4688  // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
   4689  // the MUrsh node's type is int32 (since uint32 is not implemented), and
   4690  // that would fold the MTruncateToInt32 node. This will make the modulo
   4691  // unsigned, while is should have been signed.
   4692  if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
   4693    return input;
   4694  }
   4695 
   4696  return this;
   4697 }
   4698 
   4699 MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) {
   4700  MDefinition* input = getOperand(0);
   4701  MOZ_ASSERT(input->type() == MIRType::Boolean);
   4702 
   4703  if (input->isConstant()) {
   4704    return MConstant::NewInt32(alloc, input->toConstant()->toBoolean());
   4705  }
   4706 
   4707  return this;
   4708 }
   4709 
   4710 void MToNumberInt32::analyzeEdgeCasesBackward() {
   4711  if (!NeedNegativeZeroCheck(this)) {
   4712    setNeedsNegativeZeroCheck(false);
   4713  }
   4714 }
   4715 
   4716 MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) {
   4717  MDefinition* input = getOperand(0);
   4718  if (input->isBox()) {
   4719    input = input->getOperand(0);
   4720  }
   4721 
   4722  // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
   4723  // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
   4724  // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
   4725  // is folded to a MTruncateToInt32 node, which will result in this MIR:
   4726  // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
   4727  // the MUrsh node's type is int32 (since uint32 is not implemented), and
   4728  // that would fold the MTruncateToInt32 node. This will make the modulo
   4729  // unsigned, while is should have been signed.
   4730  if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
   4731    return input;
   4732  }
   4733 
   4734  if (input->type() == MIRType::Double && input->isConstant()) {
   4735    int32_t ret = ToInt32(input->toConstant()->toDouble());
   4736    return MConstant::NewInt32(alloc, ret);
   4737  }
   4738 
   4739  return this;
   4740 }
   4741 
   4742 MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) {
   4743  MDefinition* input = this->input();
   4744  if (input->isConstant()) {
   4745    uint64_t c = input->toConstant()->toInt64();
   4746    int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32);
   4747    return MConstant::NewInt32(alloc, output);
   4748  }
   4749 
   4750  return this;
   4751 }
   4752 
   4753 MDefinition* MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) {
   4754  MDefinition* input = this->input();
   4755  if (input->isConstant()) {
   4756    int32_t c = input->toConstant()->toInt32();
   4757    int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c);
   4758    return MConstant::NewInt64(alloc, res);
   4759  }
   4760 
   4761  return this;
   4762 }
   4763 
   4764 MDefinition* MSignExtendInt32::foldsTo(TempAllocator& alloc) {
   4765  MDefinition* input = this->input();
   4766  if (input->isConstant()) {
   4767    int32_t c = input->toConstant()->toInt32();
   4768    int32_t res;
   4769    switch (mode_) {
   4770      case Byte:
   4771        res = int32_t(int8_t(c & 0xFF));
   4772        break;
   4773      case Half:
   4774        res = int32_t(int16_t(c & 0xFFFF));
   4775        break;
   4776    }
   4777    return MConstant::NewInt32(alloc, res);
   4778  }
   4779 
   4780  return this;
   4781 }
   4782 
   4783 MDefinition* MSignExtendInt64::foldsTo(TempAllocator& alloc) {
   4784  MDefinition* input = this->input();
   4785  if (input->isConstant()) {
   4786    int64_t c = input->toConstant()->toInt64();
   4787    int64_t res;
   4788    switch (mode_) {
   4789      case Byte:
   4790        res = int64_t(int8_t(c & 0xFF));
   4791        break;
   4792      case Half:
   4793        res = int64_t(int16_t(c & 0xFFFF));
   4794        break;
   4795      case Word:
   4796        res = int64_t(int32_t(c & 0xFFFFFFFFU));
   4797        break;
   4798    }
   4799    return MConstant::NewInt64(alloc, res);
   4800  }
   4801 
   4802  return this;
   4803 }
   4804 
   4805 MDefinition* MSignExtendIntPtr::foldsTo(TempAllocator& alloc) {
   4806  MDefinition* input = this->input();
   4807  if (input->isConstant()) {
   4808    intptr_t c = input->toConstant()->toIntPtr();
   4809    intptr_t res;
   4810    switch (mode_) {
   4811      case Byte:
   4812        res = intptr_t(int8_t(c & 0xFF));
   4813        break;
   4814      case Half:
   4815        res = intptr_t(int16_t(c & 0xFFFF));
   4816        break;
   4817      case Word:
   4818        res = intptr_t(int32_t(c & 0xFFFFFFFFU));
   4819        break;
   4820    }
   4821    return MConstant::NewIntPtr(alloc, res);
   4822  }
   4823 
   4824  return this;
   4825 }
   4826 
   4827 MDefinition* MToDouble::foldsTo(TempAllocator& alloc) {
   4828  MDefinition* input = getOperand(0);
   4829  if (input->isBox()) {
   4830    input = input->getOperand(0);
   4831  }
   4832 
   4833  if (input->type() == MIRType::Double) {
   4834    return input;
   4835  }
   4836 
   4837  if (input->isConstant() &&
   4838      input->toConstant()->isTypeRepresentableAsDouble()) {
   4839    return MConstant::NewDouble(alloc, input->toConstant()->numberToDouble());
   4840  }
   4841 
   4842  return this;
   4843 }
   4844 
   4845 MDefinition* MToFloat32::foldsTo(TempAllocator& alloc) {
   4846  MDefinition* input = getOperand(0);
   4847  if (input->isBox()) {
   4848    input = input->getOperand(0);
   4849  }
   4850 
   4851  if (input->type() == MIRType::Float32) {
   4852    return input;
   4853  }
   4854 
   4855  // If x is a Float32, Float32(Double(x)) == x
   4856  if (!mustPreserveNaN_ && input->isToDouble() &&
   4857      input->toToDouble()->input()->type() == MIRType::Float32) {
   4858    return input->toToDouble()->input();
   4859  }
   4860 
   4861  if (input->isConstant() &&
   4862      input->toConstant()->isTypeRepresentableAsDouble()) {
   4863    return MConstant::NewFloat32(alloc,
   4864                                 float(input->toConstant()->numberToDouble()));
   4865  }
   4866 
   4867  // Fold ToFloat32(ToDouble(int32)) to ToFloat32(int32).
   4868  if (input->isToDouble() &&
   4869      input->toToDouble()->input()->type() == MIRType::Int32) {
   4870    return MToFloat32::New(alloc, input->toToDouble()->input());
   4871  }
   4872 
   4873  return this;
   4874 }
   4875 
   4876 MDefinition* MToFloat16::foldsTo(TempAllocator& alloc) {
   4877  MDefinition* in = input();
   4878  if (in->isBox()) {
   4879    in = in->toBox()->input();
   4880  }
   4881 
   4882  if (in->isConstant()) {
   4883    auto* cst = in->toConstant();
   4884    if (cst->isTypeRepresentableAsDouble()) {
   4885      double num = cst->numberToDouble();
   4886      return MConstant::NewFloat32(alloc, static_cast<float>(js::float16{num}));
   4887    }
   4888  }
   4889 
   4890  auto isFloat16 = [](auto* def) -> MDefinition* {
   4891    // ToFloat16(ToDouble(float16)) => float16
   4892    // ToFloat16(ToFloat32(float16)) => float16
   4893    if (def->isToDouble()) {
   4894      def = def->toToDouble()->input();
   4895    } else if (def->isToFloat32()) {
   4896      def = def->toToFloat32()->input();
   4897    }
   4898 
   4899    // ToFloat16(ToFloat16(x)) => ToFloat16(x)
   4900    if (def->isToFloat16()) {
   4901      return def;
   4902    }
   4903 
   4904    // ToFloat16(LoadFloat16(x)) => LoadFloat16(x)
   4905    if (def->isLoadUnboxedScalar() &&
   4906        def->toLoadUnboxedScalar()->storageType() == Scalar::Float16) {
   4907      return def;
   4908    }
   4909    if (def->isLoadDataViewElement() &&
   4910        def->toLoadDataViewElement()->storageType() == Scalar::Float16) {
   4911      return def;
   4912    }
   4913    return nullptr;
   4914  };
   4915 
   4916  // Fold loads which are guaranteed to return Float16.
   4917  if (auto* f16 = isFloat16(in)) {
   4918    return f16;
   4919  }
   4920 
   4921  // Fold ToFloat16(ToDouble(float32)) to ToFloat16(float32).
   4922  // Fold ToFloat16(ToDouble(int32)) to ToFloat16(int32).
   4923  if (in->isToDouble()) {
   4924    auto* toDoubleInput = in->toToDouble()->input();
   4925    if (toDoubleInput->type() == MIRType::Float32 ||
   4926        toDoubleInput->type() == MIRType::Int32) {
   4927      return MToFloat16::New(alloc, toDoubleInput);
   4928    }
   4929  }
   4930 
   4931  return this;
   4932 }
   4933 
   4934 MDefinition* MToString::foldsTo(TempAllocator& alloc) {
   4935  MDefinition* in = input();
   4936  if (in->isBox()) {
   4937    in = in->getOperand(0);
   4938  }
   4939 
   4940  if (in->type() == MIRType::String) {
   4941    return in;
   4942  }
   4943  return this;
   4944 }
   4945 
   4946 MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) {
   4947  if (MConstant* inputConst = input()->maybeConstantValue()) {
   4948    if (inputConst->isTypeRepresentableAsDouble()) {
   4949      int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble());
   4950      return MConstant::NewInt32(alloc, clamped);
   4951    }
   4952  }
   4953  return this;
   4954 }
   4955 
   4956 bool MCompare::tryFoldEqualOperands(bool* result) {
   4957  if (lhs() != rhs()) {
   4958    return false;
   4959  }
   4960 
   4961  // Intuitively somebody would think that if lhs === rhs,
   4962  // then we can just return true. (Or false for !==)
   4963  // However NaN !== NaN is true! So we spend some time trying
   4964  // to eliminate this case.
   4965 
   4966  if (!IsEqualityOp(jsop())) {
   4967    return false;
   4968  }
   4969 
   4970  switch (compareType_) {
   4971    case Compare_Int32:
   4972    case Compare_UInt32:
   4973    case Compare_Int64:
   4974    case Compare_UInt64:
   4975    case Compare_IntPtr:
   4976    case Compare_UIntPtr:
   4977    case Compare_Float32:
   4978    case Compare_Double:
   4979    case Compare_String:
   4980    case Compare_Object:
   4981    case Compare_Symbol:
   4982    case Compare_BigInt:
   4983    case Compare_WasmAnyRef:
   4984    case Compare_Null:
   4985    case Compare_Undefined:
   4986      break;
   4987    case Compare_BigInt_Int32:
   4988    case Compare_BigInt_String:
   4989    case Compare_BigInt_Double:
   4990      MOZ_CRASH("Expecting different operands for lhs and rhs");
   4991  }
   4992 
   4993  if (isDoubleComparison() || isFloat32Comparison()) {
   4994    if (!operandsAreNeverNaN()) {
   4995      return false;
   4996    }
   4997  } else {
   4998    MOZ_ASSERT(!IsFloatingPointType(lhs()->type()));
   4999  }
   5000 
   5001  lhs()->setGuardRangeBailoutsUnchecked();
   5002 
   5003  *result = (jsop() == JSOp::StrictEq || jsop() == JSOp::Eq);
   5004  return true;
   5005 }
   5006 
   5007 static JSType TypeOfName(const JSOffThreadAtom* str) {
   5008  static constexpr std::array types = {
   5009      JSTYPE_UNDEFINED, JSTYPE_OBJECT,  JSTYPE_FUNCTION, JSTYPE_STRING,
   5010      JSTYPE_NUMBER,    JSTYPE_BOOLEAN, JSTYPE_SYMBOL,   JSTYPE_BIGINT,
   5011  };
   5012  static_assert(types.size() == JSTYPE_LIMIT);
   5013 
   5014  const JSAtomState& names = GetJitContext()->runtime->names();
   5015  for (auto type : types) {
   5016    // Both sides are atoms, so we can simply compare pointer identity.
   5017    if (TypeName(type, names) == str->unwrap()) {
   5018      return type;
   5019    }
   5020  }
   5021  return JSTYPE_LIMIT;
   5022 }
   5023 
   5024 struct TypeOfCompareInput {
   5025  // The `typeof expr` side of the comparison.
   5026  // MTypeOfName for JSOp::Typeof/JSOp::TypeofExpr, and
   5027  // MTypeOf for JSOp::TypeofEq (same pointer as typeOf).
   5028  MDefinition* typeOfSide;
   5029 
   5030  // The actual `typeof` operation.
   5031  MTypeOf* typeOf;
   5032 
   5033  // The string side of the comparison.
   5034  JSType type;
   5035 
   5036  // True if the comparison uses raw JSType (Generated for JSOp::TypeofEq).
   5037  bool isIntComparison;
   5038 
   5039  TypeOfCompareInput(MDefinition* typeOfSide, MTypeOf* typeOf, JSType type,
   5040                     bool isIntComparison)
   5041      : typeOfSide(typeOfSide),
   5042        typeOf(typeOf),
   5043        type(type),
   5044        isIntComparison(isIntComparison) {}
   5045 };
   5046 
   5047 static mozilla::Maybe<TypeOfCompareInput> IsTypeOfCompare(MCompare* ins) {
   5048  if (!IsEqualityOp(ins->jsop())) {
   5049    return mozilla::Nothing();
   5050  }
   5051 
   5052  if (ins->compareType() == MCompare::Compare_Int32) {
   5053    auto* lhs = ins->lhs();
   5054    auto* rhs = ins->rhs();
   5055 
   5056    // NOTE: The comparison is generated inside JIT, and typeof should always
   5057    //       be in the LHS.
   5058    if (!lhs->isTypeOf() || !rhs->isConstant()) {
   5059      return mozilla::Nothing();
   5060    }
   5061 
   5062    MOZ_ASSERT(ins->type() == MIRType::Boolean);
   5063    MOZ_ASSERT(lhs->type() == MIRType::Int32);
   5064    MOZ_ASSERT(rhs->type() == MIRType::Int32);
   5065 
   5066    auto* typeOf = lhs->toTypeOf();
   5067    auto* constant = rhs->toConstant();
   5068 
   5069    JSType type = JSType(constant->toInt32());
   5070    return mozilla::Some(TypeOfCompareInput(typeOf, typeOf, type, true));
   5071  }
   5072 
   5073  if (ins->compareType() != MCompare::Compare_String) {
   5074    return mozilla::Nothing();
   5075  }
   5076 
   5077  auto* lhs = ins->lhs();
   5078  auto* rhs = ins->rhs();
   5079 
   5080  MOZ_ASSERT(ins->type() == MIRType::Boolean);
   5081  MOZ_ASSERT(lhs->type() == MIRType::String);
   5082  MOZ_ASSERT(rhs->type() == MIRType::String);
   5083 
   5084  if (!lhs->isTypeOfName() && !rhs->isTypeOfName()) {
   5085    return mozilla::Nothing();
   5086  }
   5087  if (!lhs->isConstant() && !rhs->isConstant()) {
   5088    return mozilla::Nothing();
   5089  }
   5090 
   5091  auto* typeOfName =
   5092      lhs->isTypeOfName() ? lhs->toTypeOfName() : rhs->toTypeOfName();
   5093  auto* typeOf = typeOfName->input()->toTypeOf();
   5094 
   5095  auto* constant = lhs->isConstant() ? lhs->toConstant() : rhs->toConstant();
   5096 
   5097  JSType type = TypeOfName(constant->toString());
   5098  return mozilla::Some(TypeOfCompareInput(typeOfName, typeOf, type, false));
   5099 }
   5100 
   5101 bool MCompare::tryFoldTypeOf(bool* result) {
   5102  auto typeOfCompare = IsTypeOfCompare(this);
   5103  if (!typeOfCompare) {
   5104    return false;
   5105  }
   5106  auto* typeOf = typeOfCompare->typeOf;
   5107  JSType type = typeOfCompare->type;
   5108 
   5109  // Can't fold if the input is boxed. (Unless the typeof string is bogus.)
   5110  MIRType inputType = typeOf->input()->type();
   5111  if (inputType == MIRType::Value && type != JSTYPE_LIMIT) {
   5112    return false;
   5113  }
   5114 
   5115  bool matchesInputType;
   5116  switch (type) {
   5117    case JSTYPE_BOOLEAN:
   5118      matchesInputType = (inputType == MIRType::Boolean);
   5119      break;
   5120    case JSTYPE_NUMBER:
   5121      matchesInputType = IsTypeRepresentableAsDouble(inputType);
   5122      break;
   5123    case JSTYPE_STRING:
   5124      matchesInputType = (inputType == MIRType::String);
   5125      break;
   5126    case JSTYPE_SYMBOL:
   5127      matchesInputType = (inputType == MIRType::Symbol);
   5128      break;
   5129    case JSTYPE_BIGINT:
   5130      matchesInputType = (inputType == MIRType::BigInt);
   5131      break;
   5132    case JSTYPE_OBJECT:
   5133      // Watch out for `object-emulating-undefined` and callable objects.
   5134      if (inputType == MIRType::Object) {
   5135        return false;
   5136      }
   5137      matchesInputType = (inputType == MIRType::Null);
   5138      break;
   5139    case JSTYPE_UNDEFINED:
   5140      // Watch out for `object-emulating-undefined`.
   5141      if (inputType == MIRType::Object) {
   5142        return false;
   5143      }
   5144      matchesInputType = (inputType == MIRType::Undefined);
   5145      break;
   5146    case JSTYPE_FUNCTION:
   5147      // Can't decide at compile-time if an object is callable.
   5148      if (inputType == MIRType::Object) {
   5149        return false;
   5150      }
   5151      matchesInputType = false;
   5152      break;
   5153    case JSTYPE_LIMIT:
   5154      matchesInputType = false;
   5155      break;
   5156  }
   5157 
   5158  if (matchesInputType) {
   5159    *result = (jsop() == JSOp::StrictEq || jsop() == JSOp::Eq);
   5160  } else {
   5161    *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
   5162  }
   5163  return true;
   5164 }
   5165 
   5166 bool MCompare::tryFold(bool* result) {
   5167  JSOp op = jsop();
   5168 
   5169  if (tryFoldEqualOperands(result)) {
   5170    return true;
   5171  }
   5172 
   5173  if (tryFoldTypeOf(result)) {
   5174    return true;
   5175  }
   5176 
   5177  if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
   5178    // The LHS is the value we want to test against null or undefined.
   5179    if (IsStrictEqualityOp(op)) {
   5180      MIRType expectedType =
   5181          compareType_ == Compare_Null ? MIRType::Null : MIRType::Undefined;
   5182      if (lhs()->type() == expectedType) {
   5183        *result = (op == JSOp::StrictEq);
   5184        return true;
   5185      }
   5186      if (lhs()->type() != MIRType::Value) {
   5187        *result = (op == JSOp::StrictNe);
   5188        return true;
   5189      }
   5190    } else {
   5191      MOZ_ASSERT(IsLooseEqualityOp(op));
   5192      if (IsNullOrUndefined(lhs()->type())) {
   5193        *result = (op == JSOp::Eq);
   5194        return true;
   5195      }
   5196      if (lhs()->type() != MIRType::Object && lhs()->type() != MIRType::Value) {
   5197        *result = (op == JSOp::Ne);
   5198        return true;
   5199      }
   5200    }
   5201    return false;
   5202  }
   5203 
   5204  return false;
   5205 }
   5206 
   5207 template <typename T>
   5208 static bool FoldComparison(JSOp op, T left, T right) {
   5209  switch (op) {
   5210    case JSOp::Lt:
   5211      return left < right;
   5212    case JSOp::Le:
   5213      return left <= right;
   5214    case JSOp::Gt:
   5215      return left > right;
   5216    case JSOp::Ge:
   5217      return left >= right;
   5218    case JSOp::StrictEq:
   5219    case JSOp::Eq:
   5220      return left == right;
   5221    case JSOp::StrictNe:
   5222    case JSOp::Ne:
   5223      return left != right;
   5224    default:
   5225      MOZ_CRASH("Unexpected op.");
   5226  }
   5227 }
   5228 
   5229 static bool FoldBigIntComparison(JSOp op, const BigInt* left, double right) {
   5230  switch (op) {
   5231    case JSOp::Lt:
   5232      return BigInt::lessThan(left, right).valueOr(false);
   5233    case JSOp::Le:
   5234      return !BigInt::lessThan(right, left).valueOr(true);
   5235    case JSOp::Gt:
   5236      return BigInt::lessThan(right, left).valueOr(false);
   5237    case JSOp::Ge:
   5238      return !BigInt::lessThan(left, right).valueOr(true);
   5239    case JSOp::StrictEq:
   5240    case JSOp::Eq:
   5241      return BigInt::equal(left, right);
   5242    case JSOp::StrictNe:
   5243    case JSOp::Ne:
   5244      return !BigInt::equal(left, right);
   5245    default:
   5246      MOZ_CRASH("Unexpected op.");
   5247  }
   5248 }
   5249 
   5250 bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) {
   5251  if (type() != MIRType::Boolean && type() != MIRType::Int32) {
   5252    return false;
   5253  }
   5254 
   5255  MDefinition* left = getOperand(0);
   5256  MDefinition* right = getOperand(1);
   5257 
   5258  if (compareType() == Compare_Double) {
   5259    // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range).
   5260    // In most cases the MToDouble was added, because the constant is
   5261    // a double.
   5262    // e.g. v < 9007199254740991, where v is an int32 is always true.
   5263    if (!lhs()->isConstant() && !rhs()->isConstant()) {
   5264      return false;
   5265    }
   5266 
   5267    MDefinition* operand = left->isConstant() ? right : left;
   5268    MConstant* constant =
   5269        left->isConstant() ? left->toConstant() : right->toConstant();
   5270    MOZ_ASSERT(constant->type() == MIRType::Double);
   5271    double cte = constant->toDouble();
   5272 
   5273    if (operand->isToDouble() &&
   5274        operand->getOperand(0)->type() == MIRType::Int32) {
   5275      bool replaced = false;
   5276      switch (jsop_) {
   5277        case JSOp::Lt:
   5278          if (cte > INT32_MAX || cte < INT32_MIN) {
   5279            *result = !((constant == lhs()) ^ (cte < INT32_MIN));
   5280            replaced = true;
   5281          }
   5282          break;
   5283        case JSOp::Le:
   5284          if (constant == lhs()) {
   5285            if (cte > INT32_MAX || cte <= INT32_MIN) {
   5286              *result = (cte <= INT32_MIN);
   5287              replaced = true;
   5288            }
   5289          } else {
   5290            if (cte >= INT32_MAX || cte < INT32_MIN) {
   5291              *result = (cte >= INT32_MIN);
   5292              replaced = true;
   5293            }
   5294          }
   5295          break;
   5296        case JSOp::Gt:
   5297          if (cte > INT32_MAX || cte < INT32_MIN) {
   5298            *result = !((constant == rhs()) ^ (cte < INT32_MIN));
   5299            replaced = true;
   5300          }
   5301          break;
   5302        case JSOp::Ge:
   5303          if (constant == lhs()) {
   5304            if (cte >= INT32_MAX || cte < INT32_MIN) {
   5305              *result = (cte >= INT32_MAX);
   5306              replaced = true;
   5307            }
   5308          } else {
   5309            if (cte > INT32_MAX || cte <= INT32_MIN) {
   5310              *result = (cte <= INT32_MIN);
   5311              replaced = true;
   5312            }
   5313          }
   5314          break;
   5315        case JSOp::StrictEq:  // Fall through.
   5316        case JSOp::Eq:
   5317          if (cte > INT32_MAX || cte < INT32_MIN) {
   5318            *result = false;
   5319            replaced = true;
   5320          }
   5321          break;
   5322        case JSOp::StrictNe:  // Fall through.
   5323        case JSOp::Ne:
   5324          if (cte > INT32_MAX || cte < INT32_MIN) {
   5325            *result = true;
   5326            replaced = true;
   5327          }
   5328          break;
   5329        default:
   5330          MOZ_CRASH("Unexpected op.");
   5331      }
   5332      if (replaced) {
   5333        MLimitedTruncate* limit = MLimitedTruncate::New(
   5334            alloc, operand->getOperand(0), TruncateKind::NoTruncate);
   5335        limit->setGuardUnchecked();
   5336        block()->insertBefore(this, limit);
   5337        return true;
   5338      }
   5339    }
   5340 
   5341    // Optimize comparison against NaN.
   5342    if (std::isnan(cte)) {
   5343      switch (jsop_) {
   5344        case JSOp::Lt:
   5345        case JSOp::Le:
   5346        case JSOp::Gt:
   5347        case JSOp::Ge:
   5348        case JSOp::Eq:
   5349        case JSOp::StrictEq:
   5350          *result = false;
   5351          break;
   5352        case JSOp::Ne:
   5353        case JSOp::StrictNe:
   5354          *result = true;
   5355          break;
   5356        default:
   5357          MOZ_CRASH("Unexpected op.");
   5358      }
   5359      return true;
   5360    }
   5361  }
   5362 
   5363  if (!left->isConstant() || !right->isConstant()) {
   5364    return false;
   5365  }
   5366 
   5367  MConstant* lhs = left->toConstant();
   5368  MConstant* rhs = right->toConstant();
   5369 
   5370  switch (compareType()) {
   5371    case Compare_Int32:
   5372    case Compare_Double:
   5373    case Compare_Float32: {
   5374      *result =
   5375          FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble());
   5376      return true;
   5377    }
   5378    case Compare_UInt32: {
   5379      *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()),
   5380                               uint32_t(rhs->toInt32()));
   5381      return true;
   5382    }
   5383    case Compare_Int64: {
   5384      *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64());
   5385      return true;
   5386    }
   5387    case Compare_UInt64: {
   5388      *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()),
   5389                               uint64_t(rhs->toInt64()));
   5390      return true;
   5391    }
   5392    case Compare_IntPtr: {
   5393      *result = FoldComparison(jsop_, lhs->toIntPtr(), rhs->toIntPtr());
   5394      return true;
   5395    }
   5396    case Compare_UIntPtr: {
   5397      *result = FoldComparison(jsop_, uintptr_t(lhs->toIntPtr()),
   5398                               uintptr_t(rhs->toIntPtr()));
   5399      return true;
   5400    }
   5401    case Compare_String: {
   5402      int32_t comp = CompareStrings(lhs->toString(), rhs->toString());
   5403      *result = FoldComparison(jsop_, comp, 0);
   5404      return true;
   5405    }
   5406    case Compare_BigInt: {
   5407      int32_t comp = BigInt::compare(lhs->toBigInt(), rhs->toBigInt());
   5408      *result = FoldComparison(jsop_, comp, 0);
   5409      return true;
   5410    }
   5411    case Compare_BigInt_Int32:
   5412    case Compare_BigInt_Double: {
   5413      *result =
   5414          FoldBigIntComparison(jsop_, lhs->toBigInt(), rhs->numberToDouble());
   5415      return true;
   5416    }
   5417    case Compare_BigInt_String: {
   5418      JSOffThreadAtom* str = rhs->toString();
   5419      if (!str->hasIndexValue()) {
   5420        return false;
   5421      }
   5422      *result =
   5423          FoldBigIntComparison(jsop_, lhs->toBigInt(), str->getIndexValue());
   5424      return true;
   5425    }
   5426 
   5427    case Compare_Undefined:
   5428    case Compare_Null:
   5429    case Compare_Symbol:
   5430    case Compare_Object:
   5431    case Compare_WasmAnyRef:
   5432      return false;
   5433  }
   5434 
   5435  MOZ_CRASH("unexpected compare type");
   5436 }
   5437 
   5438 MDefinition* MCompare::tryFoldTypeOf(TempAllocator& alloc) {
   5439  auto typeOfCompare = IsTypeOfCompare(this);
   5440  if (!typeOfCompare) {
   5441    return this;
   5442  }
   5443  auto* typeOf = typeOfCompare->typeOf;
   5444  JSType type = typeOfCompare->type;
   5445 
   5446  auto* input = typeOf->input();
   5447  MOZ_ASSERT(input->type() == MIRType::Value ||
   5448             input->type() == MIRType::Object);
   5449 
   5450  // Constant typeof folding handles the other cases.
   5451  MOZ_ASSERT_IF(input->type() == MIRType::Object, type == JSTYPE_UNDEFINED ||
   5452                                                      type == JSTYPE_OBJECT ||
   5453                                                      type == JSTYPE_FUNCTION);
   5454 
   5455  MOZ_ASSERT(type != JSTYPE_LIMIT, "unknown typeof strings folded earlier");
   5456 
   5457  // If there's only a single use, assume this |typeof| is used in a simple
   5458  // comparison context.
   5459  //
   5460  // if (typeof thing === "number") { ... }
   5461  //
   5462  // It'll be compiled into something similar to:
   5463  //
   5464  // if (IsNumber(thing)) { ... }
   5465  //
   5466  // This heuristic can go wrong when repeated |typeof| are used in consecutive
   5467  // if-statements.
   5468  //
   5469  // if (typeof thing === "number") { ... }
   5470  // else if (typeof thing === "string") { ... }
   5471  // ... repeated for all possible types
   5472  //
   5473  // In that case it'd more efficient to emit MTypeOf compared to MTypeOfIs. We
   5474  // don't yet handle that case, because it'd require a separate optimization
   5475  // pass to correctly detect it.
   5476  if (typeOfCompare->typeOfSide->hasOneUse()) {
   5477    return MTypeOfIs::New(alloc, input, jsop(), type);
   5478  }
   5479 
   5480  if (typeOfCompare->isIntComparison) {
   5481    // Already optimized.
   5482    return this;
   5483  }
   5484 
   5485  MConstant* cst = MConstant::NewInt32(alloc, type);
   5486  block()->insertBefore(this, cst);
   5487 
   5488  return MCompare::New(alloc, typeOf, cst, jsop(), MCompare::Compare_Int32);
   5489 }
   5490 
   5491 MDefinition* MCompare::tryFoldCharCompare(TempAllocator& alloc) {
   5492  if (compareType() != Compare_String) {
   5493    return this;
   5494  }
   5495 
   5496  MDefinition* left = lhs();
   5497  MOZ_ASSERT(left->type() == MIRType::String);
   5498 
   5499  MDefinition* right = rhs();
   5500  MOZ_ASSERT(right->type() == MIRType::String);
   5501 
   5502  // |str[i]| is compiled as |MFromCharCode(MCharCodeAt(str, i))|.
   5503  // Out-of-bounds access is compiled as
   5504  // |FromCharCodeEmptyIfNegative(CharCodeAtOrNegative(str, i))|.
   5505  auto isCharAccess = [](MDefinition* ins) {
   5506    if (ins->isFromCharCode()) {
   5507      return ins->toFromCharCode()->code()->isCharCodeAt();
   5508    }
   5509    if (ins->isFromCharCodeEmptyIfNegative()) {
   5510      auto* fromCharCode = ins->toFromCharCodeEmptyIfNegative();
   5511      return fromCharCode->code()->isCharCodeAtOrNegative();
   5512    }
   5513    return false;
   5514  };
   5515 
   5516  auto charAccessCode = [](MDefinition* ins) {
   5517    if (ins->isFromCharCode()) {
   5518      return ins->toFromCharCode()->code();
   5519    }
   5520    return ins->toFromCharCodeEmptyIfNegative()->code();
   5521  };
   5522 
   5523  if (left->isConstant() || right->isConstant()) {
   5524    // Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)|
   5525    // as |MConstant(charcode) <compare> MCharCodeAt|.
   5526    MConstant* constant;
   5527    MDefinition* operand;
   5528    if (left->isConstant()) {
   5529      constant = left->toConstant();
   5530      operand = right;
   5531    } else {
   5532      constant = right->toConstant();
   5533      operand = left;
   5534    }
   5535 
   5536    if (constant->toString()->length() != 1 || !isCharAccess(operand)) {
   5537      return this;
   5538    }
   5539 
   5540    char16_t charCode = constant->toString()->latin1OrTwoByteChar(0);
   5541    MConstant* charCodeConst = MConstant::NewInt32(alloc, charCode);
   5542    block()->insertBefore(this, charCodeConst);
   5543 
   5544    MDefinition* charCodeAt = charAccessCode(operand);
   5545 
   5546    if (left->isConstant()) {
   5547      left = charCodeConst;
   5548      right = charCodeAt;
   5549    } else {
   5550      left = charCodeAt;
   5551      right = charCodeConst;
   5552    }
   5553  } else if (isCharAccess(left) && isCharAccess(right)) {
   5554    // Try to optimize |(MFromCharCode MCharCodeAt) <compare> (MFromCharCode
   5555    // MCharCodeAt)| as |MCharCodeAt <compare> MCharCodeAt|.
   5556 
   5557    left = charAccessCode(left);
   5558    right = charAccessCode(right);
   5559  } else {
   5560    return this;
   5561  }
   5562 
   5563  return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
   5564 }
   5565 
   5566 MDefinition* MCompare::tryFoldStringCompare(TempAllocator& alloc) {
   5567  if (compareType() != Compare_String) {
   5568    return this;
   5569  }
   5570 
   5571  MDefinition* left = lhs();
   5572  MOZ_ASSERT(left->type() == MIRType::String);
   5573 
   5574  MDefinition* right = rhs();
   5575  MOZ_ASSERT(right->type() == MIRType::String);
   5576 
   5577  if (!left->isConstant() && !right->isConstant()) {
   5578    return this;
   5579  }
   5580 
   5581  // Try to optimize |string <compare> MConstant("")| as |MStringLength(string)
   5582  // <compare> MConstant(0)|.
   5583 
   5584  MConstant* constant =
   5585      left->isConstant() ? left->toConstant() : right->toConstant();
   5586  if (!constant->toString()->empty()) {
   5587    return this;
   5588  }
   5589 
   5590  MDefinition* operand = left->isConstant() ? right : left;
   5591 
   5592  auto* strLength = MStringLength::New(alloc, operand);
   5593  block()->insertBefore(this, strLength);
   5594 
   5595  auto* zero = MConstant::NewInt32(alloc, 0);
   5596  block()->insertBefore(this, zero);
   5597 
   5598  if (left->isConstant()) {
   5599    left = zero;
   5600    right = strLength;
   5601  } else {
   5602    left = strLength;
   5603    right = zero;
   5604  }
   5605 
   5606  return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
   5607 }
   5608 
   5609 MDefinition* MCompare::tryFoldStringSubstring(TempAllocator& alloc) {
   5610  if (compareType() != Compare_String) {
   5611    return this;
   5612  }
   5613  if (!IsEqualityOp(jsop())) {
   5614    return this;
   5615  }
   5616 
   5617  auto* left = lhs();
   5618  MOZ_ASSERT(left->type() == MIRType::String);
   5619 
   5620  auto* right = rhs();
   5621  MOZ_ASSERT(right->type() == MIRType::String);
   5622 
   5623  // One operand must be a constant string.
   5624  if (!left->isConstant() && !right->isConstant()) {
   5625    return this;
   5626  }
   5627 
   5628  // The constant string must be non-empty.
   5629  auto* constant =
   5630      left->isConstant() ? left->toConstant() : right->toConstant();
   5631  if (constant->toString()->empty()) {
   5632    return this;
   5633  }
   5634 
   5635  // The other operand must be a substring operation.
   5636  auto* operand = left->isConstant() ? right : left;
   5637  if (!operand->isSubstr()) {
   5638    return this;
   5639  }
   5640  auto* substr = operand->toSubstr();
   5641 
   5642  static_assert(JSString::MAX_LENGTH < INT32_MAX,
   5643                "string length can be casted to int32_t");
   5644 
   5645  int32_t stringLength = int32_t(constant->toString()->length());
   5646 
   5647  MInstruction* replacement;
   5648  if (IsSubstrTo(substr, stringLength)) {
   5649    // Fold |str.substring(0, 2) == "aa"| to |str.startsWith("aa")|.
   5650    replacement = MStringStartsWith::New(alloc, substr->string(), constant);
   5651  } else if (IsSubstrLast(substr, -stringLength)) {
   5652    // Fold |str.slice(-2) == "aa"| to |str.endsWith("aa")|.
   5653    replacement = MStringEndsWith::New(alloc, substr->string(), constant);
   5654  } else {
   5655    return this;
   5656  }
   5657 
   5658  if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
   5659    return replacement;
   5660  }
   5661 
   5662  // Invert for inequality.
   5663  MOZ_ASSERT(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe);
   5664 
   5665  block()->insertBefore(this, replacement);
   5666  return MNot::New(alloc, replacement);
   5667 }
   5668 
   5669 MDefinition* MCompare::tryFoldStringIndexOf(TempAllocator& alloc) {
   5670  if (compareType() != Compare_Int32) {
   5671    return this;
   5672  }
   5673  if (!IsEqualityOp(jsop())) {
   5674    return this;
   5675  }
   5676 
   5677  auto* left = lhs();
   5678  MOZ_ASSERT(left->type() == MIRType::Int32);
   5679 
   5680  auto* right = rhs();
   5681  MOZ_ASSERT(right->type() == MIRType::Int32);
   5682 
   5683  // One operand must be a constant integer.
   5684  if (!left->isConstant() && !right->isConstant()) {
   5685    return this;
   5686  }
   5687 
   5688  // The constant must be zero.
   5689  auto* constant =
   5690      left->isConstant() ? left->toConstant() : right->toConstant();
   5691  if (!constant->isInt32(0)) {
   5692    return this;
   5693  }
   5694 
   5695  // The other operand must be an indexOf operation.
   5696  auto* operand = left->isConstant() ? right : left;
   5697  if (!operand->isStringIndexOf()) {
   5698    return this;
   5699  }
   5700 
   5701  // Fold |str.indexOf(searchStr) == 0| to |str.startsWith(searchStr)|.
   5702 
   5703  auto* indexOf = operand->toStringIndexOf();
   5704  auto* startsWith =
   5705      MStringStartsWith::New(alloc, indexOf->string(), indexOf->searchString());
   5706  if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
   5707    return startsWith;
   5708  }
   5709 
   5710  // Invert for inequality.
   5711  MOZ_ASSERT(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe);
   5712 
   5713  block()->insertBefore(this, startsWith);
   5714  return MNot::New(alloc, startsWith);
   5715 }
   5716 
   5717 MDefinition* MCompare::tryFoldBigInt64(TempAllocator& alloc) {
   5718  if (compareType() == Compare_BigInt) {
   5719    auto* left = lhs();
   5720    MOZ_ASSERT(left->type() == MIRType::BigInt);
   5721 
   5722    auto* right = rhs();
   5723    MOZ_ASSERT(right->type() == MIRType::BigInt);
   5724 
   5725    // At least one operand must be MInt64ToBigInt.
   5726    if (!left->isInt64ToBigInt() && !right->isInt64ToBigInt()) {
   5727      return this;
   5728    }
   5729 
   5730    // Unwrap MInt64ToBigInt on both sides and perform a Int64 comparison.
   5731    if (left->isInt64ToBigInt() && right->isInt64ToBigInt()) {
   5732      auto* lhsInt64 = left->toInt64ToBigInt();
   5733      auto* rhsInt64 = right->toInt64ToBigInt();
   5734 
   5735      // Don't optimize if Int64 against Uint64 comparison.
   5736      if (lhsInt64->isSigned() != rhsInt64->isSigned()) {
   5737        return this;
   5738      }
   5739 
   5740      bool isSigned = lhsInt64->isSigned();
   5741      auto compareType =
   5742          isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
   5743      return MCompare::New(alloc, lhsInt64->input(), rhsInt64->input(), jsop_,
   5744                           compareType);
   5745    }
   5746 
   5747    // Optimize IntPtr x Int64 comparison to Int64 x Int64 comparison.
   5748    if (left->isIntPtrToBigInt() || right->isIntPtrToBigInt()) {
   5749      auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt()
   5750                                                    : right->toInt64ToBigInt();
   5751 
   5752      // Can't optimize when comparing Uint64 against IntPtr.
   5753      if (!int64ToBigInt->isSigned()) {
   5754        return this;
   5755      }
   5756 
   5757      auto* intPtrToBigInt = left->isIntPtrToBigInt()
   5758                                 ? left->toIntPtrToBigInt()
   5759                                 : right->toIntPtrToBigInt();
   5760 
   5761      auto* intPtrToInt64 = MIntPtrToInt64::New(alloc, intPtrToBigInt->input());
   5762      block()->insertBefore(this, intPtrToInt64);
   5763 
   5764      if (left == int64ToBigInt) {
   5765        left = int64ToBigInt->input();
   5766        right = intPtrToInt64;
   5767      } else {
   5768        left = intPtrToInt64;
   5769        right = int64ToBigInt->input();
   5770      }
   5771      return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_Int64);
   5772    }
   5773 
   5774    // The other operand must be a constant.
   5775    if (!left->isConstant() && !right->isConstant()) {
   5776      return this;
   5777    }
   5778 
   5779    auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt()
   5780                                                  : right->toInt64ToBigInt();
   5781    bool isSigned = int64ToBigInt->isSigned();
   5782 
   5783    auto* constant =
   5784        left->isConstant() ? left->toConstant() : right->toConstant();
   5785    auto* bigInt = constant->toBigInt();
   5786 
   5787    // Extract the BigInt value if representable as Int64/Uint64.
   5788    mozilla::Maybe<int64_t> value;
   5789    if (isSigned) {
   5790      int64_t x;
   5791      if (BigInt::isInt64(bigInt, &x)) {
   5792        value = mozilla::Some(x);
   5793      }
   5794    } else {
   5795      uint64_t x;
   5796      if (BigInt::isUint64(bigInt, &x)) {
   5797        value = mozilla::Some(static_cast<int64_t>(x));
   5798      }
   5799    }
   5800 
   5801    // The comparison is a constant if the BigInt has too many digits.
   5802    if (!value) {
   5803      int32_t repr = bigInt->isNegative() ? -1 : 1;
   5804 
   5805      bool result;
   5806      if (left == int64ToBigInt) {
   5807        result = FoldComparison(jsop_, 0, repr);
   5808      } else {
   5809        result = FoldComparison(jsop_, repr, 0);
   5810      }
   5811      return MConstant::NewBoolean(alloc, result);
   5812    }
   5813 
   5814    auto* cst = MConstant::NewInt64(alloc, *value);
   5815    block()->insertBefore(this, cst);
   5816 
   5817    auto compareType =
   5818        isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
   5819    if (left == int64ToBigInt) {
   5820      return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_,
   5821                           compareType);
   5822    }
   5823    return MCompare::New(alloc, cst, int64ToBigInt->input(), jsop_,
   5824                         compareType);
   5825  }
   5826 
   5827  if (compareType() == Compare_BigInt_Int32) {
   5828    auto* left = lhs();
   5829    MOZ_ASSERT(left->type() == MIRType::BigInt);
   5830 
   5831    auto* right = rhs();
   5832    MOZ_ASSERT(right->type() == MIRType::Int32);
   5833 
   5834    // Optimize MInt64ToBigInt against a constant int32.
   5835    if (!left->isInt64ToBigInt() || !right->isConstant()) {
   5836      return this;
   5837    }
   5838 
   5839    auto* int64ToBigInt = left->toInt64ToBigInt();
   5840    bool isSigned = int64ToBigInt->isSigned();
   5841 
   5842    int32_t constInt32 = right->toConstant()->toInt32();
   5843 
   5844    // The unsigned comparison against a negative operand is a constant.
   5845    if (!isSigned && constInt32 < 0) {
   5846      bool result = FoldComparison(jsop_, 0, constInt32);
   5847      return MConstant::NewBoolean(alloc, result);
   5848    }
   5849 
   5850    auto* cst = MConstant::NewInt64(alloc, int64_t(constInt32));
   5851    block()->insertBefore(this, cst);
   5852 
   5853    auto compareType =
   5854        isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
   5855    return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_,
   5856                         compareType);
   5857  }
   5858 
   5859  return this;
   5860 }
   5861 
   5862 MDefinition* MCompare::tryFoldBigIntPtr(TempAllocator& alloc) {
   5863  if (compareType() == Compare_BigInt) {
   5864    auto* left = lhs();
   5865    MOZ_ASSERT(left->type() == MIRType::BigInt);
   5866 
   5867    auto* right = rhs();
   5868    MOZ_ASSERT(right->type() == MIRType::BigInt);
   5869 
   5870    // At least one operand must be MIntPtrToBigInt.
   5871    if (!left->isIntPtrToBigInt() && !right->isIntPtrToBigInt()) {
   5872      return this;
   5873    }
   5874 
   5875    // Unwrap MIntPtrToBigInt on both sides and perform an IntPtr comparison.
   5876    if (left->isIntPtrToBigInt() && right->isIntPtrToBigInt()) {
   5877      auto* lhsIntPtr = left->toIntPtrToBigInt();
   5878      auto* rhsIntPtr = right->toIntPtrToBigInt();
   5879 
   5880      return MCompare::New(alloc, lhsIntPtr->input(), rhsIntPtr->input(), jsop_,
   5881                           MCompare::Compare_IntPtr);
   5882    }
   5883 
   5884    // The other operand must be a constant.
   5885    if (!left->isConstant() && !right->isConstant()) {
   5886      return this;
   5887    }
   5888 
   5889    auto* intPtrToBigInt = left->isIntPtrToBigInt() ? left->toIntPtrToBigInt()
   5890                                                    : right->toIntPtrToBigInt();
   5891 
   5892    auto* constant =
   5893        left->isConstant() ? left->toConstant() : right->toConstant();
   5894    auto* bigInt = constant->toBigInt();
   5895 
   5896    // Extract the BigInt value if representable as intptr_t.
   5897    intptr_t value;
   5898    if (!BigInt::isIntPtr(bigInt, &value)) {
   5899      // The comparison is a constant if the BigInt has too many digits.
   5900      int32_t repr = bigInt->isNegative() ? -1 : 1;
   5901 
   5902      bool result;
   5903      if (left == intPtrToBigInt) {
   5904        result = FoldComparison(jsop_, 0, repr);
   5905      } else {
   5906        result = FoldComparison(jsop_, repr, 0);
   5907      }
   5908      return MConstant::NewBoolean(alloc, result);
   5909    }
   5910 
   5911    auto* cst = MConstant::NewIntPtr(alloc, value);
   5912    block()->insertBefore(this, cst);
   5913 
   5914    if (left == intPtrToBigInt) {
   5915      left = intPtrToBigInt->input();
   5916      right = cst;
   5917    } else {
   5918      left = cst;
   5919      right = intPtrToBigInt->input();
   5920    }
   5921    return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_IntPtr);
   5922  }
   5923 
   5924  if (compareType() == Compare_BigInt_Int32) {
   5925    auto* left = lhs();
   5926    MOZ_ASSERT(left->type() == MIRType::BigInt);
   5927 
   5928    auto* right = rhs();
   5929    MOZ_ASSERT(right->type() == MIRType::Int32);
   5930 
   5931    // Optimize MIntPtrToBigInt against a constant int32.
   5932    if (!left->isIntPtrToBigInt() || !right->isConstant()) {
   5933      return this;
   5934    }
   5935 
   5936    auto* cst =
   5937        MConstant::NewIntPtr(alloc, intptr_t(right->toConstant()->toInt32()));
   5938    block()->insertBefore(this, cst);
   5939 
   5940    return MCompare::New(alloc, left->toIntPtrToBigInt()->input(), cst, jsop_,
   5941                         MCompare::Compare_IntPtr);
   5942  }
   5943 
   5944  return this;
   5945 }
   5946 
   5947 MDefinition* MCompare::tryFoldBigInt(TempAllocator& alloc) {
   5948  if (compareType() != Compare_BigInt) {
   5949    return this;
   5950  }
   5951 
   5952  auto* left = lhs();
   5953  MOZ_ASSERT(left->type() == MIRType::BigInt);
   5954 
   5955  auto* right = rhs();
   5956  MOZ_ASSERT(right->type() == MIRType::BigInt);
   5957 
   5958  // One operand must be a constant.
   5959  if (!left->isConstant() && !right->isConstant()) {
   5960    return this;
   5961  }
   5962 
   5963  auto* constant =
   5964      left->isConstant() ? left->toConstant() : right->toConstant();
   5965  auto* operand = left->isConstant() ? right : left;
   5966 
   5967  // The constant must be representable as an Int32.
   5968  int32_t x;
   5969  if (!BigInt::isInt32(constant->toBigInt(), &x)) {
   5970    return this;
   5971  }
   5972 
   5973  MConstant* int32Const = MConstant::NewInt32(alloc, x);
   5974  block()->insertBefore(this, int32Const);
   5975 
   5976  auto op = jsop();
   5977  if (IsStrictEqualityOp(op)) {
   5978    // Compare_BigInt_Int32 is only valid for loose comparison.
   5979    op = op == JSOp::StrictEq ? JSOp::Eq : JSOp::Ne;
   5980  } else if (operand == right) {
   5981    // Reverse the comparison operator if the operands were reordered.
   5982    op = ReverseCompareOp(op);
   5983  }
   5984 
   5985  return MCompare::New(alloc, operand, int32Const, op,
   5986                       MCompare::Compare_BigInt_Int32);
   5987 }
   5988 
   5989 MDefinition* MCompare::foldsTo(TempAllocator& alloc) {
   5990  bool result;
   5991 
   5992  if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) {
   5993    if (type() == MIRType::Int32) {
   5994      return MConstant::NewInt32(alloc, result);
   5995    }
   5996 
   5997    MOZ_ASSERT(type() == MIRType::Boolean);
   5998    return MConstant::NewBoolean(alloc, result);
   5999  }
   6000 
   6001  if (MDefinition* folded = tryFoldTypeOf(alloc); folded != this) {
   6002    return folded;
   6003  }
   6004 
   6005  if (MDefinition* folded = tryFoldCharCompare(alloc); folded != this) {
   6006    return folded;
   6007  }
   6008 
   6009  if (MDefinition* folded = tryFoldStringCompare(alloc); folded != this) {
   6010    return folded;
   6011  }
   6012 
   6013  if (MDefinition* folded = tryFoldStringSubstring(alloc); folded != this) {
   6014    return folded;
   6015  }
   6016 
   6017  if (MDefinition* folded = tryFoldStringIndexOf(alloc); folded != this) {
   6018    return folded;
   6019  }
   6020 
   6021  if (MDefinition* folded = tryFoldBigInt64(alloc); folded != this) {
   6022    return folded;
   6023  }
   6024 
   6025  if (MDefinition* folded = tryFoldBigIntPtr(alloc); folded != this) {
   6026    return folded;
   6027  }
   6028 
   6029  if (MDefinition* folded = tryFoldBigInt(alloc); folded != this) {
   6030    return folded;
   6031  }
   6032 
   6033  return this;
   6034 }
   6035 
   6036 void MCompare::trySpecializeFloat32(TempAllocator& alloc) {
   6037  if (AllOperandsCanProduceFloat32(this) && compareType_ == Compare_Double) {
   6038    compareType_ = Compare_Float32;
   6039  } else {
   6040    ConvertOperandsToDouble(this, alloc);
   6041  }
   6042 }
   6043 
   6044 MDefinition* MStrictConstantCompareInt32::foldsTo(TempAllocator& alloc) {
   6045  if (!value()->isBox()) {
   6046    return this;
   6047  }
   6048  MDefinition* unboxed = value()->toBox()->input();
   6049 
   6050  if (unboxed->type() == MIRType::Int32) {
   6051    if (unboxed->isConstant()) {
   6052      bool result =
   6053          FoldComparison(jsop(), unboxed->toConstant()->toInt32(), constant());
   6054      return MConstant::NewBoolean(alloc, result);
   6055    }
   6056 
   6057    auto* cst = MConstant::NewInt32(alloc, constant());
   6058    block()->insertBefore(this, cst);
   6059 
   6060    return MCompare::New(alloc, unboxed, cst, jsop(), MCompare::Compare_Int32);
   6061  }
   6062 
   6063  if (unboxed->type() == MIRType::Double) {
   6064    if (unboxed->isConstant()) {
   6065      bool result = FoldComparison(jsop(), unboxed->toConstant()->toDouble(),
   6066                                   double(constant()));
   6067      return MConstant::NewBoolean(alloc, result);
   6068    }
   6069 
   6070    auto* cst = MConstant::NewDouble(alloc, constant());
   6071    block()->insertBefore(this, cst);
   6072 
   6073    return MCompare::New(alloc, unboxed, cst, jsop(), MCompare::Compare_Double);
   6074  }
   6075 
   6076  MOZ_ASSERT(!IsNumberType(unboxed->type()));
   6077  return MConstant::NewBoolean(alloc, jsop() == JSOp::StrictNe);
   6078 }
   6079 
   6080 MDefinition* MStrictConstantCompareBoolean::foldsTo(TempAllocator& alloc) {
   6081  if (!value()->isBox()) {
   6082    return this;
   6083  }
   6084  MDefinition* unboxed = value()->toBox()->input();
   6085 
   6086  if (unboxed->type() == MIRType::Boolean) {
   6087    if (unboxed->isConstant()) {
   6088      bool result = (jsop() == JSOp::StrictEq) ==
   6089                    (unboxed->toConstant()->toBoolean() == constant());
   6090      return MConstant::NewBoolean(alloc, result);
   6091    }
   6092 
   6093    auto* inputI32 = MBooleanToInt32::New(alloc, unboxed);
   6094    block()->insertBefore(this, inputI32);
   6095 
   6096    auto* cst = MConstant::NewInt32(alloc, int32_t(constant()));
   6097    block()->insertBefore(this, cst);
   6098 
   6099    return MCompare::New(alloc, inputI32, cst, jsop(), MCompare::Compare_Int32);
   6100  }
   6101 
   6102  return MConstant::NewBoolean(alloc, jsop() == JSOp::StrictNe);
   6103 }
   6104 
   6105 MDefinition* MSameValue::foldsTo(TempAllocator& alloc) {
   6106  MDefinition* lhs = left();
   6107  if (lhs->isBox()) {
   6108    lhs = lhs->toBox()->input();
   6109  }
   6110 
   6111  MDefinition* rhs = right();
   6112  if (rhs->isBox()) {
   6113    rhs = rhs->toBox()->input();
   6114  }
   6115 
   6116  // Trivially true if both operands are the same.
   6117  if (lhs == rhs) {
   6118    return MConstant::NewBoolean(alloc, true);
   6119  }
   6120 
   6121  // CacheIR optimizes the following cases, so don't bother to handle them here:
   6122  // 1. Both inputs are numbers (int32 or double).
   6123  // 2. Both inputs are strictly different types.
   6124  // 3. Both inputs are the same type.
   6125 
   6126  // Optimize when one operand is guaranteed to be |null|.
   6127  if (lhs->type() == MIRType::Null || rhs->type() == MIRType::Null) {
   6128    // The `null` value must be the right-hand side operand.
   6129    auto* input = lhs->type() == MIRType::Null ? rhs : lhs;
   6130    auto* cst = lhs->type() == MIRType::Null ? lhs : rhs;
   6131    return MCompare::New(alloc, input, cst, JSOp::StrictEq,
   6132                         MCompare::Compare_Null);
   6133  }
   6134 
   6135  // Optimize when one operand is guaranteed to be |undefined|.
   6136  if (lhs->type() == MIRType::Undefined || rhs->type() == MIRType::Undefined) {
   6137    // The `undefined` value must be the right-hand side operand.
   6138    auto* input = lhs->type() == MIRType::Undefined ? rhs : lhs;
   6139    auto* cst = lhs->type() == MIRType::Undefined ? lhs : rhs;
   6140    return MCompare::New(alloc, input, cst, JSOp::StrictEq,
   6141                         MCompare::Compare_Undefined);
   6142  }
   6143 
   6144  return this;
   6145 }
   6146 
   6147 MDefinition* MSameValueDouble::foldsTo(TempAllocator& alloc) {
   6148  // Trivially true if both operands are the same.
   6149  if (left() == right()) {
   6150    return MConstant::NewBoolean(alloc, true);
   6151  }
   6152 
   6153  // At least one operand must be a constant.
   6154  if (!left()->isConstant() && !right()->isConstant()) {
   6155    return this;
   6156  }
   6157 
   6158  auto* input = left()->isConstant() ? right() : left();
   6159  auto* cst = left()->isConstant() ? left() : right();
   6160  double dbl = cst->toConstant()->toDouble();
   6161 
   6162  // Use bitwise comparison for +/-0.
   6163  if (dbl == 0.0) {
   6164    auto* reinterp = MReinterpretCast::New(alloc, input, MIRType::Int64);
   6165    block()->insertBefore(this, reinterp);
   6166 
   6167    auto* zeroBitsCst =
   6168        MConstant::NewInt64(alloc, mozilla::BitwiseCast<int64_t>(dbl));
   6169    block()->insertBefore(this, zeroBitsCst);
   6170 
   6171    return MCompare::New(alloc, reinterp, zeroBitsCst, JSOp::StrictEq,
   6172                         MCompare::Compare_Int64);
   6173  }
   6174 
   6175  // Fold `Object.is(d, NaN)` to `d !== d`.
   6176  if (std::isnan(dbl)) {
   6177    return MCompare::New(alloc, input, input, JSOp::StrictNe,
   6178                         MCompare::Compare_Double);
   6179  }
   6180 
   6181  // Otherwise fold to MCompare.
   6182  return MCompare::New(alloc, left(), right(), JSOp::StrictEq,
   6183                       MCompare::Compare_Double);
   6184 }
   6185 
   6186 MDefinition* MNot::foldsTo(TempAllocator& alloc) {
   6187  auto foldConstant = [&alloc](MDefinition* input, MIRType type) -> MConstant* {
   6188    MConstant* inputConst = input->maybeConstantValue();
   6189    if (!inputConst) {
   6190      return nullptr;
   6191    }
   6192    bool b;
   6193    if (!inputConst->valueToBoolean(&b)) {
   6194      return nullptr;
   6195    }
   6196    if (type == MIRType::Int32) {
   6197      return MConstant::NewInt32(alloc, !b);
   6198    }
   6199    MOZ_ASSERT(type == MIRType::Boolean);
   6200    return MConstant::NewBoolean(alloc, !b);
   6201  };
   6202 
   6203  // Fold if the input is constant.
   6204  if (MConstant* folded = foldConstant(input(), type())) {
   6205    return folded;
   6206  }
   6207 
   6208  // If the operand of the Not is itself a Not, they cancel out. But we can't
   6209  // always convert Not(Not(x)) to x because that may loose the conversion to
   6210  // boolean. We can simplify Not(Not(Not(x))) to Not(x) though.
   6211  MDefinition* op = getOperand(0);
   6212  if (op->isNot()) {
   6213    MDefinition* opop = op->getOperand(0);
   6214    if (opop->isNot()) {
   6215      return opop;
   6216    }
   6217  }
   6218 
   6219  // Not of an undefined or null value is always true
   6220  if (input()->type() == MIRType::Undefined ||
   6221      input()->type() == MIRType::Null) {
   6222    return MConstant::NewBoolean(alloc, true);
   6223  }
   6224 
   6225  // Not of a symbol is always false.
   6226  if (input()->type() == MIRType::Symbol) {
   6227    return MConstant::NewBoolean(alloc, false);
   6228  }
   6229 
   6230  // Drop the conversion in `Not(Int64ToBigInt(int64))` to `Not(int64)`.
   6231  if (input()->isInt64ToBigInt()) {
   6232    MDefinition* int64 = input()->toInt64ToBigInt()->input();
   6233    if (MConstant* folded = foldConstant(int64, type())) {
   6234      return folded;
   6235    }
   6236    return MNot::New(alloc, int64);
   6237  }
   6238 
   6239  // Drop the conversion in `Not(IntPtrToBigInt(intptr))` to `Not(intptr)`.
   6240  if (input()->isIntPtrToBigInt()) {
   6241    MDefinition* intPtr = input()->toIntPtrToBigInt()->input();
   6242    if (MConstant* folded = foldConstant(intPtr, type())) {
   6243      return folded;
   6244    }
   6245    return MNot::New(alloc, intPtr);
   6246  }
   6247 
   6248  return this;
   6249 }
   6250 
   6251 void MNot::trySpecializeFloat32(TempAllocator& alloc) {
   6252  (void)EnsureFloatInputOrConvert(this, alloc);
   6253 }
   6254 
   6255 #ifdef JS_JITSPEW
   6256 void MBeta::printOpcode(GenericPrinter& out) const {
   6257  MDefinition::printOpcode(out);
   6258 
   6259  out.printf(" ");
   6260  comparison_->dump(out);
   6261 }
   6262 #endif
   6263 
   6264 AliasSet MCreateThis::getAliasSet() const {
   6265  return AliasSet::Load(AliasSet::Any);
   6266 }
   6267 
   6268 bool MGetArgumentsObjectArg::congruentTo(const MDefinition* ins) const {
   6269  if (!ins->isGetArgumentsObjectArg()) {
   6270    return false;
   6271  }
   6272  if (ins->toGetArgumentsObjectArg()->argno() != argno()) {
   6273    return false;
   6274  }
   6275  return congruentIfOperandsEqual(ins);
   6276 }
   6277 
   6278 AliasSet MGetArgumentsObjectArg::getAliasSet() const {
   6279  return AliasSet::Load(AliasSet::Any);
   6280 }
   6281 
   6282 AliasSet MSetArgumentsObjectArg::getAliasSet() const {
   6283  return AliasSet::Store(AliasSet::Any);
   6284 }
   6285 
   6286 MObjectState::MObjectState(MObjectState* state)
   6287    : MVariadicInstruction(classOpcode),
   6288      numSlots_(state->numSlots_),
   6289      numFixedSlots_(state->numFixedSlots_) {
   6290  // This instruction is only used as a summary for bailout paths.
   6291  setResultType(MIRType::Object);
   6292  setRecoveredOnBailout();
   6293 }
   6294 
   6295 MObjectState::MObjectState(JSObject* templateObject)
   6296    : MObjectState(templateObject->as<NativeObject>().shape()) {}
   6297 
   6298 MObjectState::MObjectState(const Shape* shape)
   6299    : MVariadicInstruction(classOpcode) {
   6300  // This instruction is only used as a summary for bailout paths.
   6301  setResultType(MIRType::Object);
   6302  setRecoveredOnBailout();
   6303 
   6304  numSlots_ = shape->asShared().slotSpan();
   6305  numFixedSlots_ = shape->asShared().numFixedSlots();
   6306 }
   6307 
   6308 /* static */
   6309 JSObject* MObjectState::templateObjectOf(MDefinition* obj) {
   6310  // MNewPlainObject uses a shape constant, not an object.
   6311  MOZ_ASSERT(!obj->isNewPlainObject());
   6312 
   6313  if (obj->isNewObject()) {
   6314    return obj->toNewObject()->templateObject();
   6315  } else if (obj->isNewCallObject()) {
   6316    return obj->toNewCallObject()->templateObject();
   6317  } else if (obj->isNewIterator()) {
   6318    return obj->toNewIterator()->templateObject();
   6319  }
   6320 
   6321  MOZ_CRASH("unreachable");
   6322 }
   6323 
   6324 bool MObjectState::init(TempAllocator& alloc, MDefinition* obj) {
   6325  if (!MVariadicInstruction::init(alloc, numSlots() + 1)) {
   6326    return false;
   6327  }
   6328  // +1, for the Object.
   6329  initOperand(0, obj);
   6330  return true;
   6331 }
   6332 
   6333 void MObjectState::initFromTemplateObject(TempAllocator& alloc,
   6334                                          MDefinition* undefinedVal) {
   6335  if (object()->isNewPlainObject()) {
   6336    MOZ_ASSERT(object()->toNewPlainObject()->shape()->asShared().slotSpan() ==
   6337               numSlots());
   6338    for (size_t i = 0; i < numSlots(); i++) {
   6339      initSlot(i, undefinedVal);
   6340    }
   6341    return;
   6342  }
   6343 
   6344  JSObject* templateObject = templateObjectOf(object());
   6345 
   6346  // Initialize all the slots of the object state with the value contained in
   6347  // the template object. This is needed to account values which are baked in
   6348  // the template objects and not visible in IonMonkey, such as the
   6349  // uninitialized-lexical magic value of call objects.
   6350 
   6351  MOZ_ASSERT(templateObject->is<NativeObject>());
   6352  NativeObject& nativeObject = templateObject->as<NativeObject>();
   6353  MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
   6354 
   6355  for (size_t i = 0; i < numSlots(); i++) {
   6356    Value val = nativeObject.getSlot(i);
   6357    MDefinition* def = undefinedVal;
   6358    if (!val.isUndefined()) {
   6359      MConstant* ins = MConstant::New(alloc, val);
   6360      block()->insertBefore(this, ins);
   6361      def = ins;
   6362    }
   6363    initSlot(i, def);
   6364  }
   6365 }
   6366 
   6367 MObjectState* MObjectState::New(TempAllocator& alloc, MDefinition* obj) {
   6368  MObjectState* res;
   6369  if (obj->isNewPlainObject()) {
   6370    const Shape* shape = obj->toNewPlainObject()->shape();
   6371    res = new (alloc) MObjectState(shape);
   6372  } else {
   6373    JSObject* templateObject = templateObjectOf(obj);
   6374    MOZ_ASSERT(templateObject, "Unexpected object creation.");
   6375    res = new (alloc) MObjectState(templateObject);
   6376  }
   6377 
   6378  if (!res || !res->init(alloc, obj)) {
   6379    return nullptr;
   6380  }
   6381  return res;
   6382 }
   6383 
   6384 MObjectState* MObjectState::Copy(TempAllocator& alloc, MObjectState* state) {
   6385  MObjectState* res = new (alloc) MObjectState(state);
   6386  if (!res || !res->init(alloc, state->object())) {
   6387    return nullptr;
   6388  }
   6389  for (size_t i = 0; i < res->numSlots(); i++) {
   6390    res->initSlot(i, state->getSlot(i));
   6391  }
   6392  return res;
   6393 }
   6394 
   6395 MArrayState::MArrayState(MDefinition* arr) : MVariadicInstruction(classOpcode) {
   6396  // This instruction is only used as a summary for bailout paths.
   6397  setResultType(MIRType::Object);
   6398  setRecoveredOnBailout();
   6399  if (arr->isNewArrayObject()) {
   6400    numElements_ = arr->toNewArrayObject()->length();
   6401  } else {
   6402    numElements_ = arr->toNewArray()->length();
   6403  }
   6404 }
   6405 
   6406 bool MArrayState::init(TempAllocator& alloc, MDefinition* obj,
   6407                       MDefinition* len) {
   6408  if (!MVariadicInstruction::init(alloc, numElements() + 2)) {
   6409    return false;
   6410  }
   6411  // +1, for the Array object.
   6412  initOperand(0, obj);
   6413  // +1, for the length value of the array.
   6414  initOperand(1, len);
   6415  return true;
   6416 }
   6417 
   6418 void MArrayState::initFromTemplateObject(TempAllocator& alloc,
   6419                                         MDefinition* undefinedVal) {
   6420  for (size_t i = 0; i < numElements(); i++) {
   6421    initElement(i, undefinedVal);
   6422  }
   6423 }
   6424 
   6425 MArrayState* MArrayState::New(TempAllocator& alloc, MDefinition* arr,
   6426                              MDefinition* initLength) {
   6427  MArrayState* res = new (alloc) MArrayState(arr);
   6428  if (!res || !res->init(alloc, arr, initLength)) {
   6429    return nullptr;
   6430  }
   6431  return res;
   6432 }
   6433 
   6434 MArrayState* MArrayState::Copy(TempAllocator& alloc, MArrayState* state) {
   6435  MDefinition* arr = state->array();
   6436  MDefinition* len = state->initializedLength();
   6437  MArrayState* res = new (alloc) MArrayState(arr);
   6438  if (!res || !res->init(alloc, arr, len)) {
   6439    return nullptr;
   6440  }
   6441  for (size_t i = 0; i < res->numElements(); i++) {
   6442    res->initElement(i, state->getElement(i));
   6443  }
   6444  return res;
   6445 }
   6446 
   6447 MNewArray::MNewArray(uint32_t length, MConstant* templateConst,
   6448                     gc::Heap initialHeap, bool vmCall)
   6449    : MUnaryInstruction(classOpcode, templateConst),
   6450      length_(length),
   6451      initialHeap_(initialHeap),
   6452      vmCall_(vmCall) {
   6453  setResultType(MIRType::Object);
   6454 }
   6455 
   6456 MDefinition::AliasType MLoadFixedSlot::mightAlias(
   6457    const MDefinition* def) const {
   6458  if (def->isStoreFixedSlot()) {
   6459    const MStoreFixedSlot* store = def->toStoreFixedSlot();
   6460    if (store->slot() != slot()) {
   6461      return AliasType::NoAlias;
   6462    }
   6463    if (store->object() != object()) {
   6464      return AliasType::MayAlias;
   6465    }
   6466    return AliasType::MustAlias;
   6467  }
   6468  return AliasType::MayAlias;
   6469 }
   6470 
   6471 HashNumber MLoadFixedSlot::valueHash() const {
   6472  HashNumber hash = MUnaryInstruction::valueHash();
   6473  hash = addU32ToHash(hash, slot());
   6474  return hash;
   6475 }
   6476 
   6477 MDefinition* MLoadFixedSlot::foldsTo(TempAllocator& alloc) {
   6478  if (MDefinition* def = foldsToStore(alloc)) {
   6479    return def;
   6480  }
   6481 
   6482  return this;
   6483 }
   6484 
   6485 MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias(
   6486    const MDefinition* def) const {
   6487  if (def->isStoreFixedSlot()) {
   6488    const MStoreFixedSlot* store = def->toStoreFixedSlot();
   6489    if (store->slot() != slot()) {
   6490      return AliasType::NoAlias;
   6491    }
   6492    if (store->object() != object()) {
   6493      return AliasType::MayAlias;
   6494    }
   6495    return AliasType::MustAlias;
   6496  }
   6497  return AliasType::MayAlias;
   6498 }
   6499 
   6500 MDefinition* MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc) {
   6501  if (MDefinition* def = foldsToStore(alloc)) {
   6502    return def;
   6503  }
   6504 
   6505  return this;
   6506 }
   6507 
   6508 MDefinition::AliasType MLoadDynamicSlot::mightAlias(
   6509    const MDefinition* def) const {
   6510  if (def->isStoreDynamicSlot()) {
   6511    const MStoreDynamicSlot* store = def->toStoreDynamicSlot();
   6512    if (store->slot() != slot()) {
   6513      return AliasType::NoAlias;
   6514    }
   6515 
   6516    if (store->slots() != slots()) {
   6517      return AliasType::MayAlias;
   6518    }
   6519 
   6520    return AliasType::MustAlias;
   6521  }
   6522  return AliasType::MayAlias;
   6523 }
   6524 
   6525 HashNumber MLoadDynamicSlot::valueHash() const {
   6526  HashNumber hash = MUnaryInstruction::valueHash();
   6527  hash = addU32ToHash(hash, slot_);
   6528  return hash;
   6529 }
   6530 
   6531 MDefinition* MLoadDynamicSlot::foldsTo(TempAllocator& alloc) {
   6532  if (MDefinition* def = foldsToStore(alloc)) {
   6533    return def;
   6534  }
   6535 
   6536  return this;
   6537 }
   6538 
   6539 #ifdef JS_JITSPEW
   6540 void MLoadDynamicSlot::printOpcode(GenericPrinter& out) const {
   6541  MDefinition::printOpcode(out);
   6542  out.printf(" (slot %u)", slot());
   6543 }
   6544 
   6545 void MLoadDynamicSlotAndUnbox::printOpcode(GenericPrinter& out) const {
   6546  MDefinition::printOpcode(out);
   6547  out.printf(" (slot %zu)", slot());
   6548 }
   6549 
   6550 void MStoreDynamicSlot::printOpcode(GenericPrinter& out) const {
   6551  MDefinition::printOpcode(out);
   6552  out.printf(" (slot %u)", slot());
   6553 }
   6554 
   6555 void MLoadFixedSlot::printOpcode(GenericPrinter& out) const {
   6556  MDefinition::printOpcode(out);
   6557  out.printf(" (slot %zu)", slot());
   6558 }
   6559 
   6560 void MLoadFixedSlotAndUnbox::printOpcode(GenericPrinter& out) const {
   6561  MDefinition::printOpcode(out);
   6562  out.printf(" (slot %zu)", slot());
   6563 }
   6564 
   6565 void MStoreFixedSlot::printOpcode(GenericPrinter& out) const {
   6566  MDefinition::printOpcode(out);
   6567  out.printf(" (slot %zu)", slot());
   6568 }
   6569 #endif
   6570 
   6571 MDefinition* MGuardFunctionScript::foldsTo(TempAllocator& alloc) {
   6572  MDefinition* in = input();
   6573  if (in->isLambda() &&
   6574      in->toLambda()->templateFunction()->baseScript() == expected()) {
   6575    return in;
   6576  }
   6577  return this;
   6578 }
   6579 
   6580 MDefinition* MFunctionEnvironment::foldsTo(TempAllocator& alloc) {
   6581  if (input()->isLambda()) {
   6582    return input()->toLambda()->environmentChain();
   6583  }
   6584  if (input()->isFunctionWithProto()) {
   6585    return input()->toFunctionWithProto()->environmentChain();
   6586  }
   6587  return this;
   6588 }
   6589 
   6590 static bool AddIsANonZeroAdditionOf(MAdd* add, MDefinition* ins) {
   6591  if (add->lhs() != ins && add->rhs() != ins) {
   6592    return false;
   6593  }
   6594  MDefinition* other = (add->lhs() == ins) ? add->rhs() : add->lhs();
   6595  if (!IsTypeRepresentableAsDouble(other->type())) {
   6596    return false;
   6597  }
   6598  if (!other->isConstant()) {
   6599    return false;
   6600  }
   6601  if (other->toConstant()->numberToDouble() == 0) {
   6602    return false;
   6603  }
   6604  return true;
   6605 }
   6606 
   6607 // Skip over instructions that usually appear between the actual index
   6608 // value being used and the MLoadElement.
   6609 // They don't modify the index value in a meaningful way.
   6610 static MDefinition* SkipUninterestingInstructions(MDefinition* ins) {
   6611  // Drop the MToNumberInt32 added by the TypePolicy for double and float
   6612  // values.
   6613  if (ins->isToNumberInt32()) {
   6614    return SkipUninterestingInstructions(ins->toToNumberInt32()->input());
   6615  }
   6616 
   6617  // Ignore the bounds check, which don't modify the index.
   6618  if (ins->isBoundsCheck()) {
   6619    return SkipUninterestingInstructions(ins->toBoundsCheck()->index());
   6620  }
   6621 
   6622  // Masking the index for Spectre-mitigation is not observable.
   6623  if (ins->isSpectreMaskIndex()) {
   6624    return SkipUninterestingInstructions(ins->toSpectreMaskIndex()->index());
   6625  }
   6626 
   6627  return ins;
   6628 }
   6629 
   6630 static bool DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2) {
   6631  ins1 = SkipUninterestingInstructions(ins1);
   6632  ins2 = SkipUninterestingInstructions(ins2);
   6633 
   6634  if (ins1 == ins2) {
   6635    return false;
   6636  }
   6637 
   6638  // For constants check they are not equal.
   6639  if (ins1->isConstant() && ins2->isConstant()) {
   6640    MConstant* cst1 = ins1->toConstant();
   6641    MConstant* cst2 = ins2->toConstant();
   6642 
   6643    if (!cst1->isTypeRepresentableAsDouble() ||
   6644        !cst2->isTypeRepresentableAsDouble()) {
   6645      return false;
   6646    }
   6647 
   6648    // Be conservative and only allow values that fit into int32.
   6649    int32_t n1, n2;
   6650    if (!mozilla::NumberIsInt32(cst1->numberToDouble(), &n1) ||
   6651        !mozilla::NumberIsInt32(cst2->numberToDouble(), &n2)) {
   6652      return false;
   6653    }
   6654 
   6655    return n1 != n2;
   6656  }
   6657 
   6658  // Check if "ins1 = ins2 + cte", which would make both instructions
   6659  // have different values.
   6660  if (ins1->isAdd()) {
   6661    if (AddIsANonZeroAdditionOf(ins1->toAdd(), ins2)) {
   6662      return true;
   6663    }
   6664  }
   6665  if (ins2->isAdd()) {
   6666    if (AddIsANonZeroAdditionOf(ins2->toAdd(), ins1)) {
   6667      return true;
   6668    }
   6669  }
   6670 
   6671  return false;
   6672 }
   6673 
   6674 MDefinition::AliasType MLoadElement::mightAlias(const MDefinition* def) const {
   6675  if (def->isStoreElement()) {
   6676    const MStoreElement* store = def->toStoreElement();
   6677    if (store->index() != index()) {
   6678      if (DefinitelyDifferentValue(store->index(), index())) {
   6679        return AliasType::NoAlias;
   6680      }
   6681      return AliasType::MayAlias;
   6682    }
   6683 
   6684    if (store->elements() != elements()) {
   6685      return AliasType::MayAlias;
   6686    }
   6687 
   6688    return AliasType::MustAlias;
   6689  }
   6690  return AliasType::MayAlias;
   6691 }
   6692 
   6693 MDefinition* MLoadElement::foldsTo(TempAllocator& alloc) {
   6694  if (MDefinition* def = foldsToStore(alloc)) {
   6695    return def;
   6696  }
   6697 
   6698  return this;
   6699 }
   6700 
   6701 void MSqrt::trySpecializeFloat32(TempAllocator& alloc) {
   6702  if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
   6703    setResultType(MIRType::Float32);
   6704    specialization_ = MIRType::Float32;
   6705  }
   6706 }
   6707 
   6708 MDefinition* MClz::foldsTo(TempAllocator& alloc) {
   6709  if (num()->isConstant()) {
   6710    MConstant* c = num()->toConstant();
   6711    if (type() == MIRType::Int32) {
   6712      int32_t n = c->toInt32();
   6713      if (n == 0) {
   6714        return MConstant::NewInt32(alloc, 32);
   6715      }
   6716      return MConstant::NewInt32(alloc, mozilla::CountLeadingZeroes32(n));
   6717    }
   6718    int64_t n = c->toInt64();
   6719    if (n == 0) {
   6720      return MConstant::NewInt64(alloc, int64_t(64));
   6721    }
   6722    return MConstant::NewInt64(alloc,
   6723                               int64_t(mozilla::CountLeadingZeroes64(n)));
   6724  }
   6725 
   6726  return this;
   6727 }
   6728 
   6729 MDefinition* MCtz::foldsTo(TempAllocator& alloc) {
   6730  if (num()->isConstant()) {
   6731    MConstant* c = num()->toConstant();
   6732    if (type() == MIRType::Int32) {
   6733      int32_t n = num()->toConstant()->toInt32();
   6734      if (n == 0) {
   6735        return MConstant::NewInt32(alloc, 32);
   6736      }
   6737      return MConstant::NewInt32(alloc, mozilla::CountTrailingZeroes32(n));
   6738    }
   6739    int64_t n = c->toInt64();
   6740    if (n == 0) {
   6741      return MConstant::NewInt64(alloc, int64_t(64));
   6742    }
   6743    return MConstant::NewInt64(alloc,
   6744                               int64_t(mozilla::CountTrailingZeroes64(n)));
   6745  }
   6746 
   6747  return this;
   6748 }
   6749 
   6750 MDefinition* MPopcnt::foldsTo(TempAllocator& alloc) {
   6751  if (num()->isConstant()) {
   6752    MConstant* c = num()->toConstant();
   6753    if (type() == MIRType::Int32) {
   6754      int32_t n = num()->toConstant()->toInt32();
   6755      return MConstant::NewInt32(alloc, mozilla::CountPopulation32(n));
   6756    }
   6757    int64_t n = c->toInt64();
   6758    return MConstant::NewInt64(alloc, int64_t(mozilla::CountPopulation64(n)));
   6759  }
   6760 
   6761  return this;
   6762 }
   6763 
   6764 MDefinition* MBoundsCheck::foldsTo(TempAllocator& alloc) {
   6765  if (type() == MIRType::Int32 && index()->isConstant() &&
   6766      length()->isConstant()) {
   6767    uint32_t len = length()->toConstant()->toInt32();
   6768    uint32_t idx = index()->toConstant()->toInt32();
   6769    if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) {
   6770      return index();
   6771    }
   6772  }
   6773 
   6774  return this;
   6775 }
   6776 
   6777 MDefinition* MTableSwitch::foldsTo(TempAllocator& alloc) {
   6778  MDefinition* op = getOperand(0);
   6779 
   6780  // If we only have one successor, convert to a plain goto to the only
   6781  // successor. TableSwitch indices are numeric; other types will always go to
   6782  // the only successor.
   6783  if (numSuccessors() == 1 ||
   6784      (op->type() != MIRType::Value && !IsNumberType(op->type()))) {
   6785    return MGoto::New(alloc, getDefault());
   6786  }
   6787 
   6788  if (MConstant* opConst = op->maybeConstantValue()) {
   6789    if (op->type() == MIRType::Int32) {
   6790      int32_t i = opConst->toInt32() - low_;
   6791      MBasicBlock* target;
   6792      if (size_t(i) < numCases()) {
   6793        target = getCase(size_t(i));
   6794      } else {
   6795        target = getDefault();
   6796      }
   6797      MOZ_ASSERT(target);
   6798      return MGoto::New(alloc, target);
   6799    }
   6800  }
   6801 
   6802  return this;
   6803 }
   6804 
   6805 MDefinition* MArrayJoin::foldsTo(TempAllocator& alloc) {
   6806  MDefinition* arr = array();
   6807 
   6808  if (!arr->isStringSplit()) {
   6809    return this;
   6810  }
   6811 
   6812  setRecoveredOnBailout();
   6813  if (arr->hasLiveDefUses()) {
   6814    setNotRecoveredOnBailout();
   6815    return this;
   6816  }
   6817 
   6818  // The MStringSplit won't generate any code.
   6819  arr->setRecoveredOnBailout();
   6820 
   6821  // We're replacing foo.split(bar).join(baz) by
   6822  // foo.replace(bar, baz).  MStringSplit could be recovered by
   6823  // a bailout.  As we are removing its last use, and its result
   6824  // could be captured by a resume point, this MStringSplit will
   6825  // be executed on the bailout path.
   6826  MDefinition* string = arr->toStringSplit()->string();
   6827  MDefinition* pattern = arr->toStringSplit()->separator();
   6828  MDefinition* replacement = separator();
   6829 
   6830  MStringReplace* substr =
   6831      MStringReplace::New(alloc, string, pattern, replacement);
   6832  substr->setFlatReplacement();
   6833  return substr;
   6834 }
   6835 
   6836 MDefinition* MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) {
   6837  MDefinition* strArg = str();
   6838  if (!strArg->isConstant()) {
   6839    return this;
   6840  }
   6841 
   6842  JSOffThreadAtom* str = strArg->toConstant()->toString();
   6843  int32_t index = GetFirstDollarIndexRawFlat(str);
   6844  return MConstant::NewInt32(alloc, index);
   6845 }
   6846 
   6847 AliasSet MThrowRuntimeLexicalError::getAliasSet() const {
   6848  return AliasSet::Store(AliasSet::ExceptionState);
   6849 }
   6850 
   6851 AliasSet MSlots::getAliasSet() const {
   6852  return AliasSet::Load(AliasSet::ObjectFields);
   6853 }
   6854 
   6855 MDefinition::AliasType MSlots::mightAlias(const MDefinition* store) const {
   6856  // ArrayPush only modifies object elements, but not object slots.
   6857  if (store->isArrayPush()) {
   6858    return AliasType::NoAlias;
   6859  }
   6860  return MInstruction::mightAlias(store);
   6861 }
   6862 
   6863 AliasSet MElements::getAliasSet() const {
   6864  return AliasSet::Load(AliasSet::ObjectFields);
   6865 }
   6866 
   6867 AliasSet MInitializedLength::getAliasSet() const {
   6868  return AliasSet::Load(AliasSet::ObjectFields);
   6869 }
   6870 
   6871 AliasSet MSetInitializedLength::getAliasSet() const {
   6872  return AliasSet::Store(AliasSet::ObjectFields);
   6873 }
   6874 
   6875 AliasSet MObjectKeysLength::getAliasSet() const {
   6876  return AliasSet::Load(AliasSet::ObjectFields);
   6877 }
   6878 
   6879 AliasSet MArrayLength::getAliasSet() const {
   6880  return AliasSet::Load(AliasSet::ObjectFields);
   6881 }
   6882 
   6883 AliasSet MSetArrayLength::getAliasSet() const {
   6884  return AliasSet::Store(AliasSet::ObjectFields);
   6885 }
   6886 
   6887 AliasSet MFunctionLength::getAliasSet() const {
   6888  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   6889                        AliasSet::DynamicSlot);
   6890 }
   6891 
   6892 AliasSet MFunctionName::getAliasSet() const {
   6893  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   6894                        AliasSet::DynamicSlot);
   6895 }
   6896 
   6897 AliasSet MArrayBufferByteLength::getAliasSet() const {
   6898  return AliasSet::Load(AliasSet::FixedSlot);
   6899 }
   6900 
   6901 AliasSet MArrayBufferViewLength::getAliasSet() const {
   6902  return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
   6903 }
   6904 
   6905 AliasSet MArrayBufferViewByteOffset::getAliasSet() const {
   6906  return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
   6907 }
   6908 
   6909 AliasSet MArrayBufferViewElements::getAliasSet() const {
   6910  return AliasSet::Load(AliasSet::ObjectFields);
   6911 }
   6912 
   6913 AliasSet MArrayBufferViewElementsWithOffset::getAliasSet() const {
   6914  return AliasSet::Load(AliasSet::ObjectFields);
   6915 }
   6916 
   6917 AliasSet MGuardHasAttachedArrayBuffer::getAliasSet() const {
   6918  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot);
   6919 }
   6920 
   6921 AliasSet MResizableTypedArrayLength::getAliasSet() const {
   6922  // Loads the length and byteOffset slots, the shared-elements flag, the
   6923  // auto-length fixed slot, and the shared raw-buffer length.
   6924  auto flags = AliasSet::ArrayBufferViewLengthOrOffset |
   6925               AliasSet::ObjectFields | AliasSet::FixedSlot |
   6926               AliasSet::SharedArrayRawBufferLength;
   6927 
   6928  // When a barrier is needed make the instruction effectful by giving it a
   6929  // "store" effect. Also prevent reordering LoadUnboxedScalar before this
   6930  // instruction by including |UnboxedElement| in the alias set.
   6931  if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
   6932    return AliasSet::Store(flags | AliasSet::UnboxedElement);
   6933  }
   6934  return AliasSet::Load(flags);
   6935 }
   6936 
   6937 bool MResizableTypedArrayLength::congruentTo(const MDefinition* ins) const {
   6938  if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
   6939    return false;
   6940  }
   6941  return congruentIfOperandsEqual(ins);
   6942 }
   6943 
   6944 AliasSet MResizableDataViewByteLength::getAliasSet() const {
   6945  // Loads the length and byteOffset slots, the shared-elements flag, the
   6946  // auto-length fixed slot, and the shared raw-buffer length.
   6947  auto flags = AliasSet::ArrayBufferViewLengthOrOffset |
   6948               AliasSet::ObjectFields | AliasSet::FixedSlot |
   6949               AliasSet::SharedArrayRawBufferLength;
   6950 
   6951  // When a barrier is needed make the instruction effectful by giving it a
   6952  // "store" effect. Also prevent reordering LoadUnboxedScalar before this
   6953  // instruction by including |UnboxedElement| in the alias set.
   6954  if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
   6955    return AliasSet::Store(flags | AliasSet::UnboxedElement);
   6956  }
   6957  return AliasSet::Load(flags);
   6958 }
   6959 
   6960 bool MResizableDataViewByteLength::congruentTo(const MDefinition* ins) const {
   6961  if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
   6962    return false;
   6963  }
   6964  return congruentIfOperandsEqual(ins);
   6965 }
   6966 
   6967 AliasSet MGrowableSharedArrayBufferByteLength::getAliasSet() const {
   6968  // Requires a barrier, so make the instruction effectful by giving it a
   6969  // "store" effect. Also prevent reordering LoadUnboxedScalar before this
   6970  // instruction by including |UnboxedElement| in the alias set.
   6971  return AliasSet::Store(AliasSet::FixedSlot |
   6972                         AliasSet::SharedArrayRawBufferLength |
   6973                         AliasSet::UnboxedElement);
   6974 }
   6975 
   6976 AliasSet MGuardResizableArrayBufferViewInBounds::getAliasSet() const {
   6977  // Additionally reads the |initialLength| and |initialByteOffset| slots, but
   6978  // since these can't change after construction, we don't need to track them.
   6979  return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
   6980 }
   6981 
   6982 AliasSet MGuardResizableArrayBufferViewInBoundsOrDetached::getAliasSet() const {
   6983  // Loads the byteOffset and additionally checks for detached buffers, so the
   6984  // alias set also has to include |ObjectFields| and |FixedSlot|.
   6985  return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
   6986                        AliasSet::ObjectFields | AliasSet::FixedSlot);
   6987 }
   6988 
   6989 AliasSet MTypedArraySet::getAliasSet() const {
   6990  // Loads typed array length and elements.
   6991  constexpr auto load =
   6992      AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
   6993                     AliasSet::ObjectFields | AliasSet::UnboxedElement);
   6994 
   6995  // Stores into typed array elements.
   6996  constexpr auto store = AliasSet::Store(AliasSet::UnboxedElement);
   6997 
   6998  return load | store;
   6999 }
   7000 
   7001 AliasSet MTypedArraySetFromSubarray::getAliasSet() const {
   7002  // Loads typed array length and elements.
   7003  constexpr auto load =
   7004      AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
   7005                     AliasSet::ObjectFields | AliasSet::UnboxedElement);
   7006 
   7007  // Stores into typed array elements.
   7008  constexpr auto store = AliasSet::Store(AliasSet::UnboxedElement);
   7009 
   7010  return load | store;
   7011 }
   7012 
   7013 AliasSet MArrayPush::getAliasSet() const {
   7014  return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
   7015 }
   7016 
   7017 MDefinition* MGuardNumberToIntPtrIndex::foldsTo(TempAllocator& alloc) {
   7018  MDefinition* input = this->input();
   7019 
   7020  if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) {
   7021    return MInt32ToIntPtr::New(alloc, input->getOperand(0));
   7022  }
   7023 
   7024  if (!input->isConstant()) {
   7025    return this;
   7026  }
   7027 
   7028  // Fold constant double representable as intptr to intptr.
   7029  int64_t ival;
   7030  if (!mozilla::NumberEqualsInt64(input->toConstant()->toDouble(), &ival)) {
   7031    // If not representable as an int64, this access is equal to an OOB access.
   7032    // So replace it with a known int64/intptr value which also produces an OOB
   7033    // access. If we don't support OOB accesses we have to bail out.
   7034    if (!supportOOB()) {
   7035      return this;
   7036    }
   7037    ival = -1;
   7038  }
   7039 
   7040  if (ival < INTPTR_MIN || ival > INTPTR_MAX) {
   7041    return this;
   7042  }
   7043 
   7044  return MConstant::NewIntPtr(alloc, intptr_t(ival));
   7045 }
   7046 
   7047 MDefinition* MIsObject::foldsTo(TempAllocator& alloc) {
   7048  MDefinition* input = object();
   7049  if (!input->isBox()) {
   7050    return this;
   7051  }
   7052 
   7053  MDefinition* unboxed = input->toBox()->input();
   7054  return MConstant::NewBoolean(alloc, unboxed->type() == MIRType::Object);
   7055 }
   7056 
   7057 MDefinition* MIsNullOrUndefined::foldsTo(TempAllocator& alloc) {
   7058  // MIsNullOrUndefined doesn't have a type-policy, so the value can already be
   7059  // unboxed.
   7060  MDefinition* unboxed = value();
   7061  if (unboxed->type() == MIRType::Value) {
   7062    if (!unboxed->isBox()) {
   7063      return this;
   7064    }
   7065    unboxed = unboxed->toBox()->input();
   7066  }
   7067 
   7068  return MConstant::NewBoolean(alloc, IsNullOrUndefined(unboxed->type()));
   7069 }
   7070 
   7071 AliasSet MHomeObjectSuperBase::getAliasSet() const {
   7072  return AliasSet::Load(AliasSet::ObjectFields);
   7073 }
   7074 
   7075 MDefinition* MGuardValue::foldsTo(TempAllocator& alloc) {
   7076  if (MConstant* cst = value()->maybeConstantValue()) {
   7077    if (expected().isValue() && cst->toJSValue() == expected().toValue()) {
   7078      return value();
   7079    }
   7080  }
   7081 
   7082  return this;
   7083 }
   7084 
   7085 MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) {
   7086  MDefinition* input = value();
   7087  if (!input->isBox()) {
   7088    return this;
   7089  }
   7090 
   7091  MDefinition* unboxed = input->toBox()->input();
   7092  if (IsNullOrUndefined(unboxed->type())) {
   7093    return input;
   7094  }
   7095 
   7096  return this;
   7097 }
   7098 
   7099 MDefinition* MGuardIsNotObject::foldsTo(TempAllocator& alloc) {
   7100  MDefinition* input = value();
   7101  if (!input->isBox()) {
   7102    return this;
   7103  }
   7104 
   7105  MDefinition* unboxed = input->toBox()->input();
   7106  if (unboxed->type() == MIRType::Object) {
   7107    return this;
   7108  }
   7109 
   7110  return input;
   7111 }
   7112 
   7113 MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) {
   7114  if (object()->isConstant() && expected()->isConstant()) {
   7115    JSObject* obj = &object()->toConstant()->toObject();
   7116    JSObject* other = &expected()->toConstant()->toObject();
   7117    if (!bailOnEquality()) {
   7118      if (obj == other) {
   7119        return object();
   7120      }
   7121    } else {
   7122      if (obj != other) {
   7123        return object();
   7124      }
   7125    }
   7126  }
   7127 
   7128  if (!bailOnEquality() && object()->isNurseryObject() &&
   7129      expected()->isNurseryObject()) {
   7130    uint32_t objIndex = object()->toNurseryObject()->nurseryObjectIndex();
   7131    uint32_t otherIndex = expected()->toNurseryObject()->nurseryObjectIndex();
   7132    if (objIndex == otherIndex) {
   7133      return object();
   7134    }
   7135  }
   7136 
   7137  return this;
   7138 }
   7139 
   7140 MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) {
   7141  if (function()->isConstant() && expected()->isConstant()) {
   7142    JSObject* fun = &function()->toConstant()->toObject();
   7143    JSObject* other = &expected()->toConstant()->toObject();
   7144    if (fun == other) {
   7145      return function();
   7146    }
   7147  }
   7148 
   7149  if (function()->isNurseryObject() && expected()->isNurseryObject()) {
   7150    uint32_t funIndex = function()->toNurseryObject()->nurseryObjectIndex();
   7151    uint32_t otherIndex = expected()->toNurseryObject()->nurseryObjectIndex();
   7152    if (funIndex == otherIndex) {
   7153      return function();
   7154    }
   7155  }
   7156 
   7157  return this;
   7158 }
   7159 
   7160 MDefinition* MGuardSpecificAtom::foldsTo(TempAllocator& alloc) {
   7161  if (str()->isConstant()) {
   7162    JSOffThreadAtom* s = str()->toConstant()->toString();
   7163    if (s == atom()) {
   7164      return str();
   7165    }
   7166  }
   7167 
   7168  return this;
   7169 }
   7170 
   7171 MDefinition* MGuardSpecificSymbol::foldsTo(TempAllocator& alloc) {
   7172  if (symbol()->isConstant()) {
   7173    if (symbol()->toConstant()->toSymbol() == expected()) {
   7174      return symbol();
   7175    }
   7176  }
   7177 
   7178  return this;
   7179 }
   7180 
   7181 MDefinition* MGuardSpecificInt32::foldsTo(TempAllocator& alloc) {
   7182  if (num()->isConstant() && num()->toConstant()->isInt32(expected())) {
   7183    return num();
   7184  }
   7185  return this;
   7186 }
   7187 
   7188 MDefinition* MGuardShape::foldsTo(TempAllocator& alloc) {
   7189  if (object()->isGuardShape() &&
   7190      shape() == object()->toGuardShape()->shape() && dependency() &&
   7191      object()->dependency() == dependency()) {
   7192    return object();
   7193  }
   7194  return this;
   7195 }
   7196 
   7197 bool MGuardShape::congruentTo(const MDefinition* ins) const {
   7198  return congruentIfOperandsEqual(ins) &&
   7199         shape() == ins->toGuardShape()->shape();
   7200 }
   7201 
   7202 AliasSet MGuardShape::getAliasSet() const {
   7203  return AliasSet::Load(AliasSet::ObjectFields);
   7204 }
   7205 
   7206 bool MGuardShapeList::congruentTo(const MDefinition* ins) const {
   7207  if (!congruentIfOperandsEqual(ins)) {
   7208    return false;
   7209  }
   7210 
   7211  // Returns true iff all non-nullptr shapes in |a| are also in |b|.
   7212  auto hasAllShapes = [](const auto& a, const auto& b) {
   7213    for (Shape* shape : a) {
   7214      if (!shape) {
   7215        continue;
   7216      }
   7217      auto isSameShape = [shape](Shape* other) { return shape == other; };
   7218      if (!std::any_of(b.begin(), b.end(), isSameShape)) {
   7219        return false;
   7220      }
   7221    }
   7222    return true;
   7223  };
   7224 
   7225  // Return true if all shapes in |shapesA| are also in |shapesB| and vice
   7226  // versa.
   7227  const auto& shapesA = this->shapeList()->shapes();
   7228  const auto& shapesB = ins->toGuardShapeList()->shapeList()->shapes();
   7229  return hasAllShapes(shapesA, shapesB) && hasAllShapes(shapesB, shapesA);
   7230 }
   7231 
   7232 AliasSet MGuardShapeList::getAliasSet() const {
   7233  return AliasSet::Load(AliasSet::ObjectFields);
   7234 }
   7235 
   7236 bool MGuardShapeListToOffset::congruentTo(const MDefinition* ins) const {
   7237  if (!congruentIfOperandsEqual(ins)) {
   7238    return false;
   7239  }
   7240 
   7241  const auto& shapesA = this->shapeList()->shapes();
   7242  const auto& shapesB = ins->toGuardShapeListToOffset()->shapeList()->shapes();
   7243  if (!std::equal(shapesA.begin(), shapesA.end(), shapesB.begin(),
   7244                  shapesB.end()))
   7245    return false;
   7246 
   7247  const auto& offsetsA = this->shapeList()->offsets();
   7248  const auto& offsetsB =
   7249      ins->toGuardShapeListToOffset()->shapeList()->offsets();
   7250  return std::equal(offsetsA.begin(), offsetsA.end(), offsetsB.begin(),
   7251                    offsetsB.end());
   7252 }
   7253 
   7254 AliasSet MGuardShapeListToOffset::getAliasSet() const {
   7255  return AliasSet::Load(AliasSet::ObjectFields);
   7256 }
   7257 
   7258 bool MHasShape::congruentTo(const MDefinition* ins) const {
   7259  if (!ins->isHasShape()) {
   7260    return false;
   7261  }
   7262  if (shape() != ins->toHasShape()->shape()) {
   7263    return false;
   7264  }
   7265  return congruentIfOperandsEqual(ins);
   7266 }
   7267 
   7268 AliasSet MHasShape::getAliasSet() const {
   7269  return AliasSet::Load(AliasSet::ObjectFields);
   7270 }
   7271 
   7272 MDefinition::AliasType MGuardShape::mightAlias(const MDefinition* store) const {
   7273  // These instructions only modify object elements, but not the shape.
   7274  if (store->isStoreElementHole() || store->isArrayPush()) {
   7275    return AliasType::NoAlias;
   7276  }
   7277  if (object()->isConstantProto()) {
   7278    const MDefinition* receiverObject =
   7279        object()->toConstantProto()->getReceiverObject();
   7280    switch (store->op()) {
   7281      case MDefinition::Opcode::StoreFixedSlot:
   7282        if (store->toStoreFixedSlot()->object()->skipObjectGuards() ==
   7283            receiverObject) {
   7284          return AliasType::NoAlias;
   7285        }
   7286        break;
   7287      case MDefinition::Opcode::StoreDynamicSlot:
   7288        if (store->toStoreDynamicSlot()
   7289                ->slots()
   7290                ->toSlots()
   7291                ->object()
   7292                ->skipObjectGuards() == receiverObject) {
   7293          return AliasType::NoAlias;
   7294        }
   7295        break;
   7296      case MDefinition::Opcode::AddAndStoreSlot:
   7297        if (store->toAddAndStoreSlot()->object()->skipObjectGuards() ==
   7298            receiverObject) {
   7299          return AliasType::NoAlias;
   7300        }
   7301        break;
   7302      case MDefinition::Opcode::AllocateAndStoreSlot:
   7303        if (store->toAllocateAndStoreSlot()->object()->skipObjectGuards() ==
   7304            receiverObject) {
   7305          return AliasType::NoAlias;
   7306        }
   7307        break;
   7308      default:
   7309        break;
   7310    }
   7311  }
   7312  return MInstruction::mightAlias(store);
   7313 }
   7314 
   7315 bool MGuardFuse::congruentTo(const MDefinition* ins) const {
   7316  if (!ins->isGuardFuse()) {
   7317    return false;
   7318  }
   7319  if (fuseIndex() != ins->toGuardFuse()->fuseIndex()) {
   7320    return false;
   7321  }
   7322  return congruentIfOperandsEqual(ins);
   7323 }
   7324 
   7325 AliasSet MGuardFuse::getAliasSet() const {
   7326  // The alias set below reflects the set of operations which could cause a fuse
   7327  // to be popped, and therefore MGuardFuse aliases with.
   7328  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::DynamicSlot |
   7329                        AliasSet::FixedSlot |
   7330                        AliasSet::GlobalGenerationCounter);
   7331 }
   7332 
   7333 AliasSet MGuardMultipleShapes::getAliasSet() const {
   7334  // Note: This instruction loads the elements of the ListObject used to
   7335  // store the list of shapes, but that object is internal and not exposed
   7336  // to script, so it doesn't have to be in the alias set.
   7337  return AliasSet::Load(AliasSet::ObjectFields);
   7338 }
   7339 
   7340 AliasSet MGuardMultipleShapesToOffset::getAliasSet() const {
   7341  return AliasSet::Load(AliasSet::ObjectFields);
   7342 }
   7343 
   7344 AliasSet MLoadFixedSlotFromOffset::getAliasSet() const {
   7345  return AliasSet::Load(AliasSet::FixedSlot);
   7346 }
   7347 
   7348 AliasSet MLoadDynamicSlotFromOffset::getAliasSet() const {
   7349  MOZ_ASSERT(slots()->type() == MIRType::Slots);
   7350  return AliasSet::Load(AliasSet::DynamicSlot);
   7351 }
   7352 
   7353 AliasSet MGuardGlobalGeneration::getAliasSet() const {
   7354  return AliasSet::Load(AliasSet::GlobalGenerationCounter);
   7355 }
   7356 
   7357 bool MGuardGlobalGeneration::congruentTo(const MDefinition* ins) const {
   7358  return ins->isGuardGlobalGeneration() &&
   7359         ins->toGuardGlobalGeneration()->expected() == expected() &&
   7360         ins->toGuardGlobalGeneration()->generationAddr() == generationAddr();
   7361 }
   7362 
   7363 MDefinition* MGuardIsNotProxy::foldsTo(TempAllocator& alloc) {
   7364  KnownClass known = GetObjectKnownClass(object());
   7365  if (known == KnownClass::None) {
   7366    return this;
   7367  }
   7368 
   7369  MOZ_ASSERT(!GetObjectKnownJSClass(object())->isProxyObject());
   7370  AssertKnownClass(alloc, this, object());
   7371  return object();
   7372 }
   7373 
   7374 AliasSet MMegamorphicLoadSlotByValue::getAliasSet() const {
   7375  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7376                        AliasSet::DynamicSlot);
   7377 }
   7378 
   7379 static PropertyKey ToNonIntPropertyKey(MDefinition* idval) {
   7380  MConstant* constant = idval->maybeConstantValue();
   7381  if (!constant) {
   7382    return PropertyKey::Void();
   7383  }
   7384  if (constant->type() == MIRType::String) {
   7385    JSOffThreadAtom* str = constant->toString();
   7386    if (str->isIndex()) {
   7387      return PropertyKey::Void();
   7388    }
   7389    return PropertyKey::NonIntAtom(str->unwrap());
   7390  }
   7391  if (constant->type() == MIRType::Symbol) {
   7392    return PropertyKey::Symbol(constant->toSymbol());
   7393  }
   7394  return PropertyKey::Void();
   7395 }
   7396 
   7397 MDefinition* MMegamorphicLoadSlotByValue::foldsTo(TempAllocator& alloc) {
   7398  PropertyKey id = ToNonIntPropertyKey(idVal());
   7399  if (id.isVoid()) {
   7400    return this;
   7401  }
   7402 
   7403  auto* result = MMegamorphicLoadSlot::New(alloc, object(), id);
   7404  result->setDependency(dependency());
   7405  return result;
   7406 }
   7407 
   7408 MDefinition* MMegamorphicLoadSlotByValuePermissive::foldsTo(
   7409    TempAllocator& alloc) {
   7410  PropertyKey id = ToNonIntPropertyKey(idVal());
   7411  if (id.isVoid()) {
   7412    return this;
   7413  }
   7414 
   7415  auto* result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id);
   7416  result->stealResumePoint(this);
   7417  return result;
   7418 }
   7419 
   7420 bool MMegamorphicLoadSlot::congruentTo(const MDefinition* ins) const {
   7421  if (!ins->isMegamorphicLoadSlot()) {
   7422    return false;
   7423  }
   7424  if (ins->toMegamorphicLoadSlot()->name() != name()) {
   7425    return false;
   7426  }
   7427  return congruentIfOperandsEqual(ins);
   7428 }
   7429 
   7430 AliasSet MMegamorphicLoadSlot::getAliasSet() const {
   7431  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7432                        AliasSet::DynamicSlot);
   7433 }
   7434 
   7435 bool MSmallObjectVariableKeyHasProp::congruentTo(const MDefinition* ins) const {
   7436  if (!ins->isSmallObjectVariableKeyHasProp()) {
   7437    return false;
   7438  }
   7439  if (ins->toSmallObjectVariableKeyHasProp()->shape() != shape()) {
   7440    return false;
   7441  }
   7442  return congruentIfOperandsEqual(ins);
   7443 }
   7444 
   7445 AliasSet MSmallObjectVariableKeyHasProp::getAliasSet() const {
   7446  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7447                        AliasSet::DynamicSlot);
   7448 }
   7449 
   7450 bool MMegamorphicHasProp::congruentTo(const MDefinition* ins) const {
   7451  if (!ins->isMegamorphicHasProp()) {
   7452    return false;
   7453  }
   7454  if (ins->toMegamorphicHasProp()->hasOwn() != hasOwn()) {
   7455    return false;
   7456  }
   7457  return congruentIfOperandsEqual(ins);
   7458 }
   7459 
   7460 AliasSet MMegamorphicHasProp::getAliasSet() const {
   7461  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7462                        AliasSet::DynamicSlot);
   7463 }
   7464 
   7465 HashNumber MNurseryObject::valueHash() const {
   7466  HashNumber hash = MNullaryInstruction::valueHash();
   7467  hash = addU32ToHash(hash, nurseryObjectIndex());
   7468  return hash;
   7469 }
   7470 
   7471 bool MNurseryObject::congruentTo(const MDefinition* ins) const {
   7472  if (!ins->isNurseryObject()) {
   7473    return false;
   7474  }
   7475  return nurseryObjectIndex() == ins->toNurseryObject()->nurseryObjectIndex();
   7476 }
   7477 
   7478 AliasSet MGuardFunctionIsNonBuiltinCtor::getAliasSet() const {
   7479  return AliasSet::Load(AliasSet::ObjectFields);
   7480 }
   7481 
   7482 bool MGuardFunctionKind::congruentTo(const MDefinition* ins) const {
   7483  if (!ins->isGuardFunctionKind()) {
   7484    return false;
   7485  }
   7486  if (expected() != ins->toGuardFunctionKind()->expected()) {
   7487    return false;
   7488  }
   7489  if (bailOnEquality() != ins->toGuardFunctionKind()->bailOnEquality()) {
   7490    return false;
   7491  }
   7492  return congruentIfOperandsEqual(ins);
   7493 }
   7494 
   7495 AliasSet MGuardFunctionKind::getAliasSet() const {
   7496  return AliasSet::Load(AliasSet::ObjectFields);
   7497 }
   7498 
   7499 bool MGuardFunctionScript::congruentTo(const MDefinition* ins) const {
   7500  if (!ins->isGuardFunctionScript()) {
   7501    return false;
   7502  }
   7503  if (expected() != ins->toGuardFunctionScript()->expected()) {
   7504    return false;
   7505  }
   7506  return congruentIfOperandsEqual(ins);
   7507 }
   7508 
   7509 AliasSet MGuardFunctionScript::getAliasSet() const {
   7510  // A JSFunction's BaseScript pointer is immutable. Relazification of
   7511  // top-level/named self-hosted functions is an exception to this, but we don't
   7512  // use this guard for those self-hosted functions.
   7513  // See IRGenerator::emitCalleeGuard.
   7514  MOZ_ASSERT_IF(flags_.isSelfHostedOrIntrinsic(), flags_.isLambda());
   7515  return AliasSet::None();
   7516 }
   7517 
   7518 bool MGuardSpecificAtom::congruentTo(const MDefinition* ins) const {
   7519  if (!ins->isGuardSpecificAtom()) {
   7520    return false;
   7521  }
   7522  if (atom() != ins->toGuardSpecificAtom()->atom()) {
   7523    return false;
   7524  }
   7525  return congruentIfOperandsEqual(ins);
   7526 }
   7527 
   7528 MDefinition* MGuardStringToIndex::foldsTo(TempAllocator& alloc) {
   7529  if (!string()->isConstant()) {
   7530    return this;
   7531  }
   7532 
   7533  JSOffThreadAtom* str = string()->toConstant()->toString();
   7534 
   7535  uint32_t index = UINT32_MAX;
   7536  if (!str->isIndex(&index) || index > INT32_MAX) {
   7537    return this;
   7538  }
   7539 
   7540  return MConstant::NewInt32(alloc, index);
   7541 }
   7542 
   7543 MDefinition* MGuardStringToInt32::foldsTo(TempAllocator& alloc) {
   7544  if (!string()->isConstant()) {
   7545    return this;
   7546  }
   7547 
   7548  JSOffThreadAtom* str = string()->toConstant()->toString();
   7549  double number = OffThreadAtomToNumber(str);
   7550 
   7551  int32_t n;
   7552  if (!mozilla::NumberIsInt32(number, &n)) {
   7553    return this;
   7554  }
   7555 
   7556  return MConstant::NewInt32(alloc, n);
   7557 }
   7558 
   7559 MDefinition* MGuardStringToDouble::foldsTo(TempAllocator& alloc) {
   7560  if (!string()->isConstant()) {
   7561    return this;
   7562  }
   7563 
   7564  JSOffThreadAtom* str = string()->toConstant()->toString();
   7565  double number = OffThreadAtomToNumber(str);
   7566  return MConstant::NewDouble(alloc, number);
   7567 }
   7568 
   7569 AliasSet MGuardNoDenseElements::getAliasSet() const {
   7570  return AliasSet::Load(AliasSet::ObjectFields);
   7571 }
   7572 
   7573 AliasSet MIteratorHasIndices::getAliasSet() const {
   7574  return AliasSet::Load(AliasSet::ObjectFields);
   7575 }
   7576 
   7577 AliasSet MIteratorsMatchAndHaveIndices::getAliasSet() const {
   7578  return AliasSet::Load(AliasSet::ObjectFields);
   7579 }
   7580 
   7581 AliasSet MAllocateAndStoreSlot::getAliasSet() const {
   7582  return AliasSet::Store(AliasSet::ObjectFields | AliasSet::DynamicSlot);
   7583 }
   7584 
   7585 AliasSet MLoadDOMExpandoValue::getAliasSet() const {
   7586  return AliasSet::Load(AliasSet::DOMProxyExpando);
   7587 }
   7588 
   7589 AliasSet MLoadDOMExpandoValueIgnoreGeneration::getAliasSet() const {
   7590  return AliasSet::Load(AliasSet::DOMProxyExpando);
   7591 }
   7592 
   7593 bool MGuardDOMExpandoMissingOrGuardShape::congruentTo(
   7594    const MDefinition* ins) const {
   7595  if (!ins->isGuardDOMExpandoMissingOrGuardShape()) {
   7596    return false;
   7597  }
   7598  if (shape() != ins->toGuardDOMExpandoMissingOrGuardShape()->shape()) {
   7599    return false;
   7600  }
   7601  return congruentIfOperandsEqual(ins);
   7602 }
   7603 
   7604 AliasSet MGuardDOMExpandoMissingOrGuardShape::getAliasSet() const {
   7605  return AliasSet::Load(AliasSet::ObjectFields);
   7606 }
   7607 
   7608 MDefinition* MGuardToClass::foldsTo(TempAllocator& alloc) {
   7609  const JSClass* clasp = GetObjectKnownJSClass(object());
   7610  if (!clasp || getClass() != clasp) {
   7611    return this;
   7612  }
   7613 
   7614  AssertKnownClass(alloc, this, object());
   7615  return object();
   7616 }
   7617 
   7618 MDefinition* MGuardToFunction::foldsTo(TempAllocator& alloc) {
   7619  if (GetObjectKnownClass(object()) != KnownClass::Function) {
   7620    return this;
   7621  }
   7622 
   7623  AssertKnownClass(alloc, this, object());
   7624  return object();
   7625 }
   7626 
   7627 MDefinition* MHasClass::foldsTo(TempAllocator& alloc) {
   7628  const JSClass* clasp = GetObjectKnownJSClass(object());
   7629  if (!clasp) {
   7630    return this;
   7631  }
   7632 
   7633  AssertKnownClass(alloc, this, object());
   7634  return MConstant::NewBoolean(alloc, getClass() == clasp);
   7635 }
   7636 
   7637 MDefinition* MIsCallable::foldsTo(TempAllocator& alloc) {
   7638  if (input()->type() != MIRType::Object) {
   7639    return this;
   7640  }
   7641 
   7642  KnownClass known = GetObjectKnownClass(input());
   7643  if (known == KnownClass::None) {
   7644    return this;
   7645  }
   7646 
   7647  AssertKnownClass(alloc, this, input());
   7648  return MConstant::NewBoolean(alloc, known == KnownClass::Function);
   7649 }
   7650 
   7651 MDefinition* MIsArray::foldsTo(TempAllocator& alloc) {
   7652  if (input()->type() != MIRType::Object) {
   7653    return this;
   7654  }
   7655 
   7656  KnownClass known = GetObjectKnownClass(input());
   7657  if (known == KnownClass::None) {
   7658    return this;
   7659  }
   7660 
   7661  AssertKnownClass(alloc, this, input());
   7662  return MConstant::NewBoolean(alloc, known == KnownClass::Array);
   7663 }
   7664 
   7665 AliasSet MObjectClassToString::getAliasSet() const {
   7666  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7667                        AliasSet::DynamicSlot);
   7668 }
   7669 
   7670 MDefinition* MGuardIsNotArrayBufferMaybeShared::foldsTo(TempAllocator& alloc) {
   7671  switch (GetObjectKnownClass(object())) {
   7672    case KnownClass::PlainObject:
   7673    case KnownClass::Array:
   7674    case KnownClass::Function:
   7675    case KnownClass::RegExp:
   7676    case KnownClass::ArrayIterator:
   7677    case KnownClass::StringIterator:
   7678    case KnownClass::RegExpStringIterator: {
   7679      AssertKnownClass(alloc, this, object());
   7680      return object();
   7681    }
   7682    case KnownClass::None:
   7683      break;
   7684  }
   7685 
   7686  return this;
   7687 }
   7688 
   7689 MDefinition* MCheckIsObj::foldsTo(TempAllocator& alloc) {
   7690  if (!input()->isBox()) {
   7691    return this;
   7692  }
   7693 
   7694  MDefinition* unboxed = input()->toBox()->input();
   7695  if (unboxed->type() == MIRType::Object) {
   7696    return unboxed;
   7697  }
   7698 
   7699  return this;
   7700 }
   7701 
   7702 AliasSet MCheckIsObj::getAliasSet() const {
   7703  return AliasSet::Store(AliasSet::ExceptionState);
   7704 }
   7705 
   7706 #ifdef JS_PUNBOX64
   7707 AliasSet MCheckScriptedProxyGetResult::getAliasSet() const {
   7708  return AliasSet::Store(AliasSet::ExceptionState);
   7709 }
   7710 #endif
   7711 
   7712 static bool IsBoxedObject(MDefinition* def) {
   7713  MOZ_ASSERT(def->type() == MIRType::Value);
   7714 
   7715  if (def->isBox()) {
   7716    return def->toBox()->input()->type() == MIRType::Object;
   7717  }
   7718 
   7719  // Construct calls are always returning a boxed object.
   7720  //
   7721  // TODO: We should consider encoding this directly in the graph instead of
   7722  // having to special case it here.
   7723  if (def->isCall()) {
   7724    return def->toCall()->isConstructing();
   7725  }
   7726  if (def->isConstructArray()) {
   7727    return true;
   7728  }
   7729  if (def->isConstructArgs()) {
   7730    return true;
   7731  }
   7732 
   7733  return false;
   7734 }
   7735 
   7736 MDefinition* MCheckReturn::foldsTo(TempAllocator& alloc) {
   7737  auto* returnVal = returnValue();
   7738  if (!returnVal->isBox()) {
   7739    return this;
   7740  }
   7741 
   7742  auto* unboxedReturnVal = returnVal->toBox()->input();
   7743  if (unboxedReturnVal->type() == MIRType::Object) {
   7744    return returnVal;
   7745  }
   7746 
   7747  if (unboxedReturnVal->type() != MIRType::Undefined) {
   7748    return this;
   7749  }
   7750 
   7751  auto* thisVal = thisValue();
   7752  if (IsBoxedObject(thisVal)) {
   7753    return thisVal;
   7754  }
   7755 
   7756  return this;
   7757 }
   7758 
   7759 MDefinition* MCheckThis::foldsTo(TempAllocator& alloc) {
   7760  MDefinition* input = thisValue();
   7761  if (!input->isBox()) {
   7762    return this;
   7763  }
   7764 
   7765  MDefinition* unboxed = input->toBox()->input();
   7766  if (IsMagicType(unboxed->type())) {
   7767    return this;
   7768  }
   7769 
   7770  return input;
   7771 }
   7772 
   7773 MDefinition* MCheckThisReinit::foldsTo(TempAllocator& alloc) {
   7774  MDefinition* input = thisValue();
   7775  if (!input->isBox()) {
   7776    return this;
   7777  }
   7778 
   7779  MDefinition* unboxed = input->toBox()->input();
   7780  if (unboxed->type() != MIRType::MagicUninitializedLexical) {
   7781    return this;
   7782  }
   7783 
   7784  return input;
   7785 }
   7786 
   7787 MDefinition* MCheckObjCoercible::foldsTo(TempAllocator& alloc) {
   7788  MDefinition* input = checkValue();
   7789  if (!input->isBox()) {
   7790    return this;
   7791  }
   7792 
   7793  MDefinition* unboxed = input->toBox()->input();
   7794  if (IsNullOrUndefined(unboxed->type())) {
   7795    return this;
   7796  }
   7797 
   7798  return input;
   7799 }
   7800 
   7801 AliasSet MCheckObjCoercible::getAliasSet() const {
   7802  return AliasSet::Store(AliasSet::ExceptionState);
   7803 }
   7804 
   7805 AliasSet MCheckReturn::getAliasSet() const {
   7806  return AliasSet::Store(AliasSet::ExceptionState);
   7807 }
   7808 
   7809 AliasSet MCheckThis::getAliasSet() const {
   7810  return AliasSet::Store(AliasSet::ExceptionState);
   7811 }
   7812 
   7813 AliasSet MCheckThisReinit::getAliasSet() const {
   7814  return AliasSet::Store(AliasSet::ExceptionState);
   7815 }
   7816 
   7817 AliasSet MIsPackedArray::getAliasSet() const {
   7818  return AliasSet::Load(AliasSet::ObjectFields);
   7819 }
   7820 
   7821 AliasSet MGuardArrayIsPacked::getAliasSet() const {
   7822  return AliasSet::Load(AliasSet::ObjectFields);
   7823 }
   7824 
   7825 AliasSet MGuardElementsArePacked::getAliasSet() const {
   7826  return AliasSet::Load(AliasSet::ObjectFields);
   7827 }
   7828 
   7829 AliasSet MSuperFunction::getAliasSet() const {
   7830  return AliasSet::Load(AliasSet::ObjectFields);
   7831 }
   7832 
   7833 AliasSet MSuperFunctionAndUnbox::getAliasSet() const {
   7834  return AliasSet::Load(AliasSet::ObjectFields);
   7835 }
   7836 
   7837 AliasSet MInitHomeObject::getAliasSet() const {
   7838  return AliasSet::Store(AliasSet::ObjectFields);
   7839 }
   7840 
   7841 AliasSet MLoadWrapperTarget::getAliasSet() const {
   7842  return AliasSet::Load(AliasSet::Any);
   7843 }
   7844 
   7845 bool MLoadWrapperTarget::congruentTo(const MDefinition* ins) const {
   7846  if (!ins->isLoadWrapperTarget()) {
   7847    return false;
   7848  }
   7849  if (ins->toLoadWrapperTarget()->fallible() != fallible()) {
   7850    return false;
   7851  }
   7852  return congruentIfOperandsEqual(ins);
   7853 }
   7854 
   7855 AliasSet MGuardHasGetterSetter::getAliasSet() const {
   7856  return AliasSet::Load(AliasSet::ObjectFields);
   7857 }
   7858 
   7859 bool MGuardHasGetterSetter::congruentTo(const MDefinition* ins) const {
   7860  if (!ins->isGuardHasGetterSetter()) {
   7861    return false;
   7862  }
   7863  if (ins->toGuardHasGetterSetter()->propId() != propId()) {
   7864    return false;
   7865  }
   7866  if (ins->toGuardHasGetterSetter()->getterSetterValue() !=
   7867      getterSetterValue()) {
   7868    return false;
   7869  }
   7870  return congruentIfOperandsEqual(ins);
   7871 }
   7872 
   7873 AliasSet MGuardIsExtensible::getAliasSet() const {
   7874  return AliasSet::Load(AliasSet::ObjectFields);
   7875 }
   7876 
   7877 AliasSet MGuardIndexIsNotDenseElement::getAliasSet() const {
   7878  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Element);
   7879 }
   7880 
   7881 AliasSet MGuardIndexIsValidUpdateOrAdd::getAliasSet() const {
   7882  return AliasSet::Load(AliasSet::ObjectFields);
   7883 }
   7884 
   7885 AliasSet MCallObjectHasSparseElement::getAliasSet() const {
   7886  return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields |
   7887                        AliasSet::FixedSlot | AliasSet::DynamicSlot);
   7888 }
   7889 
   7890 AliasSet MLoadSlotByIteratorIndex::getAliasSet() const {
   7891  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7892                        AliasSet::DynamicSlot | AliasSet::Element);
   7893 }
   7894 
   7895 AliasSet MStoreSlotByIteratorIndex::getAliasSet() const {
   7896  return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7897                         AliasSet::DynamicSlot | AliasSet::Element);
   7898 }
   7899 
   7900 AliasSet MLoadSlotByIteratorIndexIndexed::getAliasSet() const {
   7901  return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7902                        AliasSet::DynamicSlot | AliasSet::Element);
   7903 }
   7904 
   7905 AliasSet MStoreSlotByIteratorIndexIndexed::getAliasSet() const {
   7906  return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot |
   7907                         AliasSet::DynamicSlot | AliasSet::Element);
   7908 }
   7909 
   7910 MDefinition* MGuardInt32IsNonNegative::foldsTo(TempAllocator& alloc) {
   7911  MOZ_ASSERT(index()->type() == MIRType::Int32);
   7912 
   7913  MDefinition* input = index();
   7914  if (!input->isConstant() || input->toConstant()->toInt32() < 0) {
   7915    return this;
   7916  }
   7917  return input;
   7918 }
   7919 
   7920 MDefinition* MGuardIntPtrIsNonNegative::foldsTo(TempAllocator& alloc) {
   7921  MOZ_ASSERT(index()->type() == MIRType::IntPtr);
   7922 
   7923  MDefinition* input = index();
   7924  if (!input->isConstant() || input->toConstant()->toIntPtr() < 0) {
   7925    return this;
   7926  }
   7927  return input;
   7928 }
   7929 
   7930 MDefinition* MGuardInt32Range::foldsTo(TempAllocator& alloc) {
   7931  MOZ_ASSERT(input()->type() == MIRType::Int32);
   7932  MOZ_ASSERT(minimum() <= maximum());
   7933 
   7934  MDefinition* in = input();
   7935  if (!in->isConstant()) {
   7936    return this;
   7937  }
   7938  int32_t cst = in->toConstant()->toInt32();
   7939  if (cst < minimum() || cst > maximum()) {
   7940    return this;
   7941  }
   7942  return in;
   7943 }
   7944 
   7945 MDefinition* MGuardNonGCThing::foldsTo(TempAllocator& alloc) {
   7946  if (!input()->isBox()) {
   7947    return this;
   7948  }
   7949 
   7950  MDefinition* unboxed = input()->toBox()->input();
   7951  if (!IsNonGCThing(unboxed->type())) {
   7952    return this;
   7953  }
   7954  return input();
   7955 }
   7956 
   7957 AliasSet MSetObjectHasNonBigInt::getAliasSet() const {
   7958  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7959 }
   7960 
   7961 AliasSet MSetObjectHasBigInt::getAliasSet() const {
   7962  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7963 }
   7964 
   7965 AliasSet MSetObjectHasValue::getAliasSet() const {
   7966  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7967 }
   7968 
   7969 AliasSet MSetObjectHasValueVMCall::getAliasSet() const {
   7970  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7971 }
   7972 
   7973 AliasSet MSetObjectSize::getAliasSet() const {
   7974  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7975 }
   7976 
   7977 AliasSet MMapObjectHasNonBigInt::getAliasSet() const {
   7978  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7979 }
   7980 
   7981 AliasSet MMapObjectHasBigInt::getAliasSet() const {
   7982  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7983 }
   7984 
   7985 AliasSet MMapObjectHasValue::getAliasSet() const {
   7986  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7987 }
   7988 
   7989 AliasSet MMapObjectHasValueVMCall::getAliasSet() const {
   7990  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7991 }
   7992 
   7993 AliasSet MMapObjectGetNonBigInt::getAliasSet() const {
   7994  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7995 }
   7996 
   7997 AliasSet MMapObjectGetBigInt::getAliasSet() const {
   7998  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   7999 }
   8000 
   8001 AliasSet MMapObjectGetValue::getAliasSet() const {
   8002  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   8003 }
   8004 
   8005 AliasSet MMapObjectGetValueVMCall::getAliasSet() const {
   8006  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   8007 }
   8008 
   8009 AliasSet MMapObjectSize::getAliasSet() const {
   8010  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   8011 }
   8012 
   8013 AliasSet MWeakMapGetObject::getAliasSet() const {
   8014  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   8015 }
   8016 
   8017 AliasSet MWeakMapHasObject::getAliasSet() const {
   8018  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   8019 }
   8020 
   8021 AliasSet MWeakSetHasObject::getAliasSet() const {
   8022  return AliasSet::Load(AliasSet::MapOrSetHashTable);
   8023 }
   8024 
   8025 AliasSet MDateFillLocalTimeSlots::getAliasSet() const {
   8026  // Reads and stores fixed slots. Additional reads from DateTimeInfo don't need
   8027  // to be tracked, because they don't interact with other alias set states.
   8028  return AliasSet::Store(AliasSet::FixedSlot);
   8029 }
   8030 
   8031 MBindFunction* MBindFunction::New(TempAllocator& alloc, MDefinition* target,
   8032                                  uint32_t argc, JSObject* templateObj) {
   8033  auto* ins = new (alloc) MBindFunction(templateObj);
   8034  if (!ins->init(alloc, NumNonArgumentOperands + argc)) {
   8035    return nullptr;
   8036  }
   8037  ins->initOperand(0, target);
   8038  return ins;
   8039 }
   8040 
   8041 MCreateInlinedArgumentsObject* MCreateInlinedArgumentsObject::New(
   8042    TempAllocator& alloc, MDefinition* callObj, MDefinition* callee,
   8043    MDefinitionVector& args, ArgumentsObject* templateObj) {
   8044  MCreateInlinedArgumentsObject* ins =
   8045      new (alloc) MCreateInlinedArgumentsObject(templateObj);
   8046 
   8047  uint32_t argc = args.length();
   8048  MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs);
   8049 
   8050  if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
   8051    return nullptr;
   8052  }
   8053 
   8054  ins->initOperand(0, callObj);
   8055  ins->initOperand(1, callee);
   8056  for (uint32_t i = 0; i < argc; i++) {
   8057    ins->initOperand(i + NumNonArgumentOperands, args[i]);
   8058  }
   8059 
   8060  return ins;
   8061 }
   8062 
   8063 MGetInlinedArgument* MGetInlinedArgument::New(
   8064    TempAllocator& alloc, MDefinition* index,
   8065    MCreateInlinedArgumentsObject* args) {
   8066  MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument();
   8067 
   8068  uint32_t argc = args->numActuals();
   8069  MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs);
   8070 
   8071  if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
   8072    return nullptr;
   8073  }
   8074 
   8075  ins->initOperand(0, index);
   8076  for (uint32_t i = 0; i < argc; i++) {
   8077    ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
   8078  }
   8079 
   8080  return ins;
   8081 }
   8082 
   8083 MGetInlinedArgument* MGetInlinedArgument::New(TempAllocator& alloc,
   8084                                              MDefinition* index,
   8085                                              const CallInfo& callInfo) {
   8086  MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument();
   8087 
   8088  uint32_t argc = callInfo.argc();
   8089  MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs);
   8090 
   8091  if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
   8092    return nullptr;
   8093  }
   8094 
   8095  ins->initOperand(0, index);
   8096  for (uint32_t i = 0; i < argc; i++) {
   8097    ins->initOperand(i + NumNonArgumentOperands, callInfo.getArg(i));
   8098  }
   8099 
   8100  return ins;
   8101 }
   8102 
   8103 MDefinition* MGetInlinedArgument::foldsTo(TempAllocator& alloc) {
   8104  MDefinition* indexDef = SkipUninterestingInstructions(index());
   8105  if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) {
   8106    return this;
   8107  }
   8108 
   8109  int32_t indexConst = indexDef->toConstant()->toInt32();
   8110  if (indexConst < 0 || uint32_t(indexConst) >= numActuals()) {
   8111    return this;
   8112  }
   8113 
   8114  MDefinition* arg = getArg(indexConst);
   8115  if (arg->type() != MIRType::Value) {
   8116    arg = MBox::New(alloc, arg);
   8117  }
   8118 
   8119  return arg;
   8120 }
   8121 
   8122 MGetInlinedArgumentHole* MGetInlinedArgumentHole::New(
   8123    TempAllocator& alloc, MDefinition* index,
   8124    MCreateInlinedArgumentsObject* args) {
   8125  auto* ins = new (alloc) MGetInlinedArgumentHole();
   8126 
   8127  uint32_t argc = args->numActuals();
   8128  MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs);
   8129 
   8130  if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
   8131    return nullptr;
   8132  }
   8133 
   8134  ins->initOperand(0, index);
   8135  for (uint32_t i = 0; i < argc; i++) {
   8136    ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
   8137  }
   8138 
   8139  return ins;
   8140 }
   8141 
   8142 MDefinition* MGetInlinedArgumentHole::foldsTo(TempAllocator& alloc) {
   8143  MDefinition* indexDef = SkipUninterestingInstructions(index());
   8144  if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) {
   8145    return this;
   8146  }
   8147 
   8148  int32_t indexConst = indexDef->toConstant()->toInt32();
   8149  if (indexConst < 0) {
   8150    return this;
   8151  }
   8152 
   8153  MDefinition* arg;
   8154  if (uint32_t(indexConst) < numActuals()) {
   8155    arg = getArg(indexConst);
   8156 
   8157    if (arg->type() != MIRType::Value) {
   8158      arg = MBox::New(alloc, arg);
   8159    }
   8160  } else {
   8161    auto* undefined = MConstant::NewUndefined(alloc);
   8162    block()->insertBefore(this, undefined);
   8163 
   8164    arg = MBox::New(alloc, undefined);
   8165  }
   8166 
   8167  return arg;
   8168 }
   8169 
   8170 MInlineArgumentsSlice* MInlineArgumentsSlice::New(
   8171    TempAllocator& alloc, MDefinition* begin, MDefinition* count,
   8172    MCreateInlinedArgumentsObject* args, JSObject* templateObj,
   8173    gc::Heap initialHeap) {
   8174  auto* ins = new (alloc) MInlineArgumentsSlice(templateObj, initialHeap);
   8175 
   8176  uint32_t argc = args->numActuals();
   8177  MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs);
   8178 
   8179  if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
   8180    return nullptr;
   8181  }
   8182 
   8183  ins->initOperand(0, begin);
   8184  ins->initOperand(1, count);
   8185  for (uint32_t i = 0; i < argc; i++) {
   8186    ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
   8187  }
   8188 
   8189  return ins;
   8190 }
   8191 
   8192 MDefinition* MArrayLength::foldsTo(TempAllocator& alloc) {
   8193  // Object.keys() is potentially effectful, in case of Proxies. Otherwise, when
   8194  // it is only computed for its length property, there is no need to
   8195  // materialize the Array which results from it and it can be marked as
   8196  // recovered on bailout as long as no properties are added to / removed from
   8197  // the object.
   8198  MDefinition* elems = elements();
   8199  if (!elems->isElements()) {
   8200    return this;
   8201  }
   8202 
   8203  MDefinition* guardshape = elems->toElements()->object();
   8204  if (!guardshape->isGuardShape()) {
   8205    return this;
   8206  }
   8207 
   8208  // The Guard shape is guarding the shape of the object returned by
   8209  // Object.keys, this guard can be removed as knowing the function is good
   8210  // enough to infer that we are returning an array.
   8211  MDefinition* keys = guardshape->toGuardShape()->object();
   8212  if (!keys->isObjectKeys()) {
   8213    return this;
   8214  }
   8215 
   8216  // Object.keys() inline cache guards against proxies when creating the IC. We
   8217  // rely on this here as we are looking to elide `Object.keys(...)` call, which
   8218  // is only possible if we know for sure that no side-effect might have
   8219  // happened.
   8220  MDefinition* noproxy = keys->toObjectKeys()->object();
   8221  if (!noproxy->isGuardIsNotProxy()) {
   8222    // The guard might have been replaced by an assertion, in case the class is
   8223    // known at compile time. IF the guard has been removed check whether check
   8224    // has been removed.
   8225    MOZ_RELEASE_ASSERT(GetObjectKnownClass(noproxy) != KnownClass::None);
   8226    MOZ_RELEASE_ASSERT(!GetObjectKnownJSClass(noproxy)->isProxyObject());
   8227  }
   8228 
   8229  // Check if both the elements and the Object.keys() have a single use. We only
   8230  // check for live uses, and are ok if a branch which was previously using the
   8231  // keys array has been removed since.
   8232  if (!elems->hasOneLiveDefUse() || !guardshape->hasOneLiveDefUse() ||
   8233      !keys->hasOneLiveDefUse()) {
   8234    return this;
   8235  }
   8236 
   8237  // Check that the latest active resume point is the one from Object.keys(), in
   8238  // order to steal it. If this is not the latest active resume point then some
   8239  // side-effect might happen which updates the content of the object, making
   8240  // any recovery of the keys exhibit a different behavior than expected.
   8241  if (keys->toObjectKeys()->resumePoint() != block()->activeResumePoint(this)) {
   8242    return this;
   8243  }
   8244 
   8245  // Verify whether any resume point captures the keys array after any aliasing
   8246  // mutations. If this were to be the case the recovery of ObjectKeys on
   8247  // bailout might compute a version which might not match with the elided
   8248  // result.
   8249  //
   8250  // Iterate over the resume point uses of ObjectKeys, and check whether the
   8251  // instructions they are attached to are aliasing Object fields. If so, skip
   8252  // this optimization.
   8253  AliasSet enumKeysAliasSet = AliasSet::Load(AliasSet::Flag::ObjectFields);
   8254  for (auto* use : UsesIterator(keys)) {
   8255    if (!use->consumer()->isResumePoint()) {
   8256      // There is only a single use, and this is the length computation as
   8257      // asserted with `hasOneLiveDefUse`.
   8258      continue;
   8259    }
   8260 
   8261    MResumePoint* rp = use->consumer()->toResumePoint();
   8262    if (!rp->instruction()) {
   8263      // If there is no instruction, this is a resume point which is attached to
   8264      // the entry of a block. Thus no risk of mutating the object on which the
   8265      // keys are queried.
   8266      continue;
   8267    }
   8268 
   8269    MInstruction* ins = rp->instruction();
   8270    if (ins == keys) {
   8271      continue;
   8272    }
   8273 
   8274    // Check whether the instruction can potentially alias the object fields of
   8275    // the object from which we are querying the keys.
   8276    AliasSet mightAlias = ins->getAliasSet() & enumKeysAliasSet;
   8277    if (!mightAlias.isNone()) {
   8278      return this;
   8279    }
   8280  }
   8281 
   8282  // Flag every instructions since Object.keys(..) as recovered on bailout, and
   8283  // make Object.keys(..) be the recovered value in-place of the shape guard.
   8284  setRecoveredOnBailout();
   8285  elems->setRecoveredOnBailout();
   8286  guardshape->replaceAllUsesWith(keys);
   8287  guardshape->block()->discard(guardshape->toGuardShape());
   8288  keys->setRecoveredOnBailout();
   8289 
   8290  // Steal the resume point from Object.keys, which is ok as we confirmed that
   8291  // there is no other resume point in-between.
   8292  MObjectKeysLength* keysLength = MObjectKeysLength::New(alloc, noproxy);
   8293  keysLength->stealResumePoint(keys->toObjectKeys());
   8294 
   8295  // Set the dependency of the newly created instruction. Unfortunately
   8296  // MObjectKeys (keys) is an instruction with a Store(Any) alias set, as it
   8297  // could be used with proxies which can re-enter JavaScript.
   8298  //
   8299  // Thus, the loadDependency field of MObjectKeys is null. On the other hand
   8300  // MObjectKeysLength has a Load alias set. Thus, instead of reconstructing the
   8301  // Alias Analysis by updating every instructions which depends on MObjectKeys
   8302  // and finding the matching store instruction, we reuse the MObjectKeys as any
   8303  // store instruction, despite it being marked as recovered-on-bailout.
   8304  keysLength->setDependency(keys);
   8305 
   8306  return keysLength;
   8307 }
   8308 
   8309 MDefinition* MNormalizeSliceTerm::foldsTo(TempAllocator& alloc) {
   8310  auto* length = this->length();
   8311  if (!length->isConstant() && !length->isArgumentsLength()) {
   8312    return this;
   8313  }
   8314 
   8315  if (length->isConstant()) {
   8316    int32_t lengthConst = length->toConstant()->toInt32();
   8317    MOZ_ASSERT(lengthConst >= 0);
   8318 
   8319    // Result is always zero when |length| is zero.
   8320    if (lengthConst == 0) {
   8321      return length;
   8322    }
   8323 
   8324    auto* value = this->value();
   8325    if (value->isConstant()) {
   8326      int32_t valueConst = value->toConstant()->toInt32();
   8327 
   8328      int32_t normalized;
   8329      if (valueConst < 0) {
   8330        normalized = std::max(valueConst + lengthConst, 0);
   8331      } else {
   8332        normalized = std::min(valueConst, lengthConst);
   8333      }
   8334 
   8335      if (normalized == valueConst) {
   8336        return value;
   8337      }
   8338      if (normalized == lengthConst) {
   8339        return length;
   8340      }
   8341      return MConstant::NewInt32(alloc, normalized);
   8342    }
   8343 
   8344    return this;
   8345  }
   8346 
   8347  auto* value = this->value();
   8348  if (value->isConstant()) {
   8349    int32_t valueConst = value->toConstant()->toInt32();
   8350 
   8351    // Minimum of |value| and |length|.
   8352    if (valueConst > 0) {
   8353      return MMinMax::NewMin(alloc, value, length, MIRType::Int32);
   8354    }
   8355 
   8356    // Maximum of |value + length| and zero.
   8357    if (valueConst < 0) {
   8358      // Safe to truncate because |length| is never negative.
   8359      auto* add = MAdd::New(alloc, value, length, TruncateKind::Truncate);
   8360      block()->insertBefore(this, add);
   8361 
   8362      auto* zero = MConstant::NewInt32(alloc, 0);
   8363      block()->insertBefore(this, zero);
   8364 
   8365      return MMinMax::NewMax(alloc, add, zero, MIRType::Int32);
   8366    }
   8367 
   8368    // Directly return the value when it's zero.
   8369    return value;
   8370  }
   8371 
   8372  // Normalizing MArgumentsLength is a no-op.
   8373  if (value->isArgumentsLength()) {
   8374    return value;
   8375  }
   8376 
   8377  return this;
   8378 }
   8379 
   8380 MDefinition* MToIntegerIndex::foldsTo(TempAllocator& alloc) {
   8381  // |length| is guaranteed to be a non-negative value.
   8382 
   8383  auto* index = this->index();
   8384  auto* length = this->length();
   8385 
   8386  if (index == length) {
   8387    return index;
   8388  }
   8389 
   8390  if (index->isConstant()) {
   8391    intptr_t indexConst = index->toConstant()->toIntPtr();
   8392 
   8393    // Minimum of |index| and |length|.
   8394    if (indexConst > 0) {
   8395      return MMinMax::NewMin(alloc, index, length, MIRType::IntPtr);
   8396    }
   8397 
   8398    // Maximum of |value + length| and zero.
   8399    if (indexConst < 0) {
   8400      auto* add = MAdd::New(alloc, index, length, MIRType::IntPtr);
   8401      block()->insertBefore(this, add);
   8402 
   8403      auto* zero = MConstant::NewIntPtr(alloc, 0);
   8404      block()->insertBefore(this, zero);
   8405 
   8406      return MMinMax::NewMax(alloc, add, zero, MIRType::IntPtr);
   8407    }
   8408 
   8409    // Directly return the index when it's zero.
   8410    return index;
   8411  }
   8412 
   8413  return this;
   8414 }
   8415 
   8416 bool MInt32ToStringWithBase::congruentTo(const MDefinition* ins) const {
   8417  if (!ins->isInt32ToStringWithBase()) {
   8418    return false;
   8419  }
   8420  if (ins->toInt32ToStringWithBase()->lowerCase() != lowerCase()) {
   8421    return false;
   8422  }
   8423  return congruentIfOperandsEqual(ins);
   8424 }
   8425 
   8426 // Returns `false` if it can be proven that (1) both `mtyA` and `mtyB` are
   8427 // struct types and (2) they are not related by inheritance.  Returns `true` in
   8428 // all other cases.  `true` is the safe-but-possibly-suboptimal return value.
   8429 static bool StructTypesMightBeRelatedByInheritance(wasm::MaybeRefType mtyA,
   8430                                                   wasm::MaybeRefType mtyB) {
   8431  if (!mtyA.isSome() || !mtyB.isSome()) {
   8432    // The "Track Wasm ref types" pass couldn't establish that both `mtyA` and
   8433    // `mtyB` are ref types.  Give up.
   8434    return true;
   8435  }
   8436 
   8437  wasm::RefType tyA = mtyA.value();
   8438  wasm::RefType tyB = mtyB.value();
   8439  if (!tyA.isTypeRef() || !tyA.typeDef()->isStructType() || !tyB.isTypeRef() ||
   8440      !tyB.typeDef()->isStructType()) {
   8441    // They aren't both struct types.  Give up.
   8442    return true;
   8443  }
   8444 
   8445  // They are both struct types.  So they are related by inheritance if one is
   8446  // a subtype of the other.  (Which is also the case if they are the same
   8447  // type.)
   8448  return wasm::RefType::valuesMightAlias(tyA, tyB);
   8449 }
   8450 
   8451 MDefinition::AliasType MWasmLoadField::mightAlias(
   8452    const MDefinition* ins) const {
   8453  if (!(getAliasSet().flags() & ins->getAliasSet().flags())) {
   8454    return AliasType::NoAlias;
   8455  }
   8456  MOZ_ASSERT(!isEffectful() && ins->isEffectful());
   8457 
   8458  // Pick off cases where we can easily prove non-aliasing.  The idea is that
   8459  // two struct field accesses can't alias if either they are at different
   8460  // offsets, or the struct types are unrelated (which implies that the struct
   8461  // base pointer for one of the accesses could not validly be handed to the
   8462  // other access).
   8463  if (ins->isWasmStoreField()) {
   8464    const MWasmStoreField* store = ins->toWasmStoreField();
   8465    if (offset() != store->offset() ||
   8466        !StructTypesMightBeRelatedByInheritance(base()->wasmRefType(),
   8467                                                store->base()->wasmRefType())) {
   8468      return AliasType::NoAlias;
   8469    }
   8470  } else if (ins->isWasmStoreFieldRef()) {
   8471    const MWasmStoreFieldRef* store = ins->toWasmStoreFieldRef();
   8472    if (offset() != store->offset() ||
   8473        !StructTypesMightBeRelatedByInheritance(base()->wasmRefType(),
   8474                                                store->base()->wasmRefType())) {
   8475      return AliasType::NoAlias;
   8476    }
   8477  }
   8478 
   8479  return AliasType::MayAlias;
   8480 }