LCOV - code coverage report
Current view: top level - js/src/jit - MIR.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1138 3467 32.8 %
Date: 2017-07-14 16:53:18 Functions: 157 351 44.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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/CheckedInt.h"
      10             : #include "mozilla/FloatingPoint.h"
      11             : #include "mozilla/IntegerPrintfMacros.h"
      12             : #include "mozilla/MathAlgorithms.h"
      13             : #include "mozilla/SizePrintfMacros.h"
      14             : 
      15             : #include <ctype.h>
      16             : 
      17             : #include "jslibmath.h"
      18             : #include "jsstr.h"
      19             : 
      20             : #include "builtin/RegExp.h"
      21             : #include "jit/AtomicOperations.h"
      22             : #include "jit/BaselineInspector.h"
      23             : #include "jit/IonBuilder.h"
      24             : #include "jit/JitSpewer.h"
      25             : #include "jit/MIRGraph.h"
      26             : #include "jit/RangeAnalysis.h"
      27             : #include "js/Conversions.h"
      28             : 
      29             : #include "jsatominlines.h"
      30             : #include "jsboolinlines.h"
      31             : #include "jsobjinlines.h"
      32             : #include "jsscriptinlines.h"
      33             : 
      34             : using namespace js;
      35             : using namespace js::jit;
      36             : 
      37             : using JS::ToInt32;
      38             : 
      39             : using mozilla::CheckedInt;
      40             : using mozilla::NumbersAreIdentical;
      41             : using mozilla::IsFloat32Representable;
      42             : using mozilla::IsNaN;
      43             : using mozilla::IsPowerOfTwo;
      44             : using mozilla::Maybe;
      45             : using mozilla::DebugOnly;
      46             : 
      47             : #ifdef DEBUG
      48      478023 : size_t MUse::index() const
      49             : {
      50      478023 :     return consumer()->indexOf(this);
      51             : }
      52             : #endif
      53             : 
      54             : template<size_t Op> static void
      55           0 : ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def, MInstruction* consumer)
      56             : {
      57           0 :     MInstruction* replace = MToDouble::New(alloc, def);
      58           0 :     consumer->replaceOperand(Op, replace);
      59           0 :     consumer->block()->insertBefore(consumer, replace);
      60           0 : }
      61             : 
      62             : static bool
      63           0 : CheckUsesAreFloat32Consumers(const MInstruction* ins)
      64             : {
      65           0 :     bool allConsumerUses = true;
      66           0 :     for (MUseDefIterator use(ins); allConsumerUses && use; use++)
      67           0 :         allConsumerUses &= use.def()->canConsumeFloat32(use.use());
      68           0 :     return allConsumerUses;
      69             : }
      70             : 
      71             : void
      72           0 : MDefinition::PrintOpcodeName(GenericPrinter& out, MDefinition::Opcode op)
      73             : {
      74             :     static const char * const names[] =
      75             :     {
      76             : #define NAME(x) #x,
      77             :         MIR_OPCODE_LIST(NAME)
      78             : #undef NAME
      79             :     };
      80           0 :     const char* name = names[op];
      81           0 :     size_t len = strlen(name);
      82           0 :     for (size_t i = 0; i < len; i++)
      83           0 :         out.printf("%c", tolower(name[i]));
      84           0 : }
      85             : 
      86             : static MConstant*
      87         173 : EvaluateConstantOperands(TempAllocator& alloc, MBinaryInstruction* ins, bool* ptypeChange = nullptr)
      88             : {
      89         173 :     MDefinition* left = ins->getOperand(0);
      90         173 :     MDefinition* right = ins->getOperand(1);
      91             : 
      92         173 :     MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()));
      93         173 :     MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()));
      94             : 
      95         173 :     if (!left->isConstant() || !right->isConstant())
      96         168 :         return nullptr;
      97             : 
      98           5 :     MConstant* lhs = left->toConstant();
      99           5 :     MConstant* rhs = right->toConstant();
     100           5 :     double ret = JS::GenericNaN();
     101             : 
     102           5 :     switch (ins->op()) {
     103             :       case MDefinition::Op_BitAnd:
     104           0 :         ret = double(lhs->toInt32() & rhs->toInt32());
     105           0 :         break;
     106             :       case MDefinition::Op_BitOr:
     107           0 :         ret = double(lhs->toInt32() | rhs->toInt32());
     108           0 :         break;
     109             :       case MDefinition::Op_BitXor:
     110           0 :         ret = double(lhs->toInt32() ^ rhs->toInt32());
     111           0 :         break;
     112             :       case MDefinition::Op_Lsh:
     113           0 :         ret = double(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F));
     114           0 :         break;
     115             :       case MDefinition::Op_Rsh:
     116           0 :         ret = double(lhs->toInt32() >> (rhs->toInt32() & 0x1F));
     117           0 :         break;
     118             :       case MDefinition::Op_Ursh:
     119           0 :         ret = double(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F));
     120           0 :         break;
     121             :       case MDefinition::Op_Add:
     122           5 :         ret = lhs->numberToDouble() + rhs->numberToDouble();
     123           5 :         break;
     124             :       case MDefinition::Op_Sub:
     125           0 :         ret = lhs->numberToDouble() - rhs->numberToDouble();
     126           0 :         break;
     127             :       case MDefinition::Op_Mul:
     128           0 :         ret = lhs->numberToDouble() * rhs->numberToDouble();
     129           0 :         break;
     130             :       case MDefinition::Op_Div:
     131           0 :         if (ins->toDiv()->isUnsigned()) {
     132           0 :             if (rhs->isInt32(0)) {
     133           0 :                 if (ins->toDiv()->trapOnError())
     134           0 :                     return nullptr;
     135           0 :                 ret = 0.0;
     136             :             } else {
     137           0 :                 ret = double(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32()));
     138             :             }
     139             :         } else {
     140           0 :             ret = NumberDiv(lhs->numberToDouble(), rhs->numberToDouble());
     141             :         }
     142           0 :         break;
     143             :       case MDefinition::Op_Mod:
     144           0 :         if (ins->toMod()->isUnsigned()) {
     145           0 :             if (rhs->isInt32(0)) {
     146           0 :                 if (ins->toMod()->trapOnError())
     147           0 :                     return nullptr;
     148           0 :                 ret = 0.0;
     149             :             } else {
     150           0 :                 ret = double(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32()));
     151             :             }
     152             :         } else {
     153           0 :             ret = NumberMod(lhs->numberToDouble(), rhs->numberToDouble());
     154             :         }
     155           0 :         break;
     156             :       default:
     157           0 :         MOZ_CRASH("NYI");
     158             :     }
     159             : 
     160           5 :     if (ins->type() == MIRType::Float32)
     161           0 :         return MConstant::NewFloat32(alloc, float(ret));
     162           5 :     if (ins->type() == MIRType::Double)
     163           4 :         return MConstant::New(alloc, DoubleValue(ret));
     164             : 
     165           1 :     Value retVal;
     166           1 :     retVal.setNumber(JS::CanonicalizeNaN(ret));
     167             : 
     168             :     // If this was an int32 operation but the result isn't an int32 (for
     169             :     // example, a division where the numerator isn't evenly divisible by the
     170             :     // denominator), decline folding.
     171           1 :     MOZ_ASSERT(ins->type() == MIRType::Int32);
     172           1 :     if (!retVal.isInt32()) {
     173           0 :         if (ptypeChange)
     174           0 :             *ptypeChange = true;
     175           0 :         return nullptr;
     176             :     }
     177             : 
     178           1 :     return MConstant::New(alloc, retVal);
     179             : }
     180             : 
     181             : static MMul*
     182           0 : EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins)
     183             : {
     184             :     // we should fold only when it is a floating point operation
     185           0 :     if (!IsFloatingPointType(ins->type()))
     186           0 :         return nullptr;
     187             : 
     188           0 :     MDefinition* left = ins->getOperand(0);
     189           0 :     MDefinition* right = ins->getOperand(1);
     190             : 
     191           0 :     if (!right->isConstant())
     192           0 :         return nullptr;
     193             : 
     194             :     int32_t num;
     195           0 :     if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num))
     196           0 :         return nullptr;
     197             : 
     198             :     // check if rhs is a power of two
     199           0 :     if (mozilla::Abs(num) & (mozilla::Abs(num) - 1))
     200           0 :         return nullptr;
     201             : 
     202           0 :     Value ret;
     203           0 :     ret.setDouble(1.0 / double(num));
     204             : 
     205             :     MConstant* foldedRhs;
     206           0 :     if (ins->type() == MIRType::Float32)
     207           0 :         foldedRhs = MConstant::NewFloat32(alloc, ret.toDouble());
     208             :     else
     209           0 :         foldedRhs = MConstant::New(alloc, ret);
     210             : 
     211           0 :     MOZ_ASSERT(foldedRhs->type() == ins->type());
     212           0 :     ins->block()->insertBefore(ins, foldedRhs);
     213             : 
     214           0 :     MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type());
     215           0 :     mul->setCommutative();
     216           0 :     mul->setMustPreserveNaN(ins->mustPreserveNaN());
     217           0 :     return mul;
     218             : }
     219             : 
     220             : void
     221           0 : MDefinition::printName(GenericPrinter& out) const
     222             : {
     223           0 :     PrintOpcodeName(out, op());
     224           0 :     out.printf("%u", id());
     225           0 : }
     226             : 
     227             : HashNumber
     228        2626 : MDefinition::addU32ToHash(HashNumber hash, uint32_t data)
     229             : {
     230        2626 :     return data + (hash << 6) + (hash << 16) - hash;
     231             : }
     232             : 
     233             : HashNumber
     234        1525 : MDefinition::valueHash() const
     235             : {
     236        1525 :     HashNumber out = op();
     237        3914 :     for (size_t i = 0, e = numOperands(); i < e; i++)
     238        2389 :         out = addU32ToHash(out, getOperand(i)->id());
     239        1525 :     if (MDefinition* dep = dependency())
     240         217 :         out = addU32ToHash(out, dep->id());
     241        1525 :     return out;
     242             : }
     243             : 
     244             : bool
     245        1568 : MDefinition::congruentIfOperandsEqual(const MDefinition* ins) const
     246             : {
     247        1568 :     if (op() != ins->op())
     248           0 :         return false;
     249             : 
     250        1568 :     if (type() != ins->type())
     251           0 :         return false;
     252             : 
     253        1568 :     if (isEffectful() || ins->isEffectful())
     254           0 :         return false;
     255             : 
     256        1568 :     if (numOperands() != ins->numOperands())
     257           0 :         return false;
     258             : 
     259        3744 :     for (size_t i = 0, e = numOperands(); i < e; i++) {
     260        2176 :         if (getOperand(i) != ins->getOperand(i))
     261           0 :             return false;
     262             :     }
     263             : 
     264        1568 :     return true;
     265             : }
     266             : 
     267             : MDefinition*
     268        1992 : MDefinition::foldsTo(TempAllocator& alloc)
     269             : {
     270             :     // In the default case, there are no constants to fold.
     271        1992 :     return this;
     272             : }
     273             : 
     274             : bool
     275          34 : MDefinition::mightBeMagicType() const
     276             : {
     277          34 :     if (IsMagicType(type()))
     278           0 :         return true;
     279             : 
     280          34 :     if (MIRType::Value != type())
     281          15 :         return false;
     282             : 
     283          19 :     return !resultTypeSet() || resultTypeSet()->hasType(TypeSet::MagicArgType());
     284             : }
     285             : 
     286             : MDefinition*
     287          84 : MInstruction::foldsToStore(TempAllocator& alloc)
     288             : {
     289          84 :     if (!dependency())
     290           0 :         return nullptr;
     291             : 
     292          84 :     MDefinition* store = dependency();
     293          84 :     if (mightAlias(store) != AliasType::MustAlias)
     294          84 :         return nullptr;
     295             : 
     296           0 :     if (!store->block()->dominates(block()))
     297           0 :         return nullptr;
     298             : 
     299             :     MDefinition* value;
     300           0 :     switch (store->op()) {
     301             :       case Op_StoreFixedSlot:
     302           0 :         value = store->toStoreFixedSlot()->value();
     303           0 :         break;
     304             :       case Op_StoreSlot:
     305           0 :         value = store->toStoreSlot()->value();
     306           0 :         break;
     307             :       case Op_StoreElement:
     308           0 :         value = store->toStoreElement()->value();
     309           0 :         break;
     310             :       case Op_StoreUnboxedObjectOrNull:
     311           0 :         value = store->toStoreUnboxedObjectOrNull()->value();
     312           0 :         break;
     313             :       default:
     314           0 :         MOZ_CRASH("unknown store");
     315             :     }
     316             : 
     317             :     // If the type are matching then we return the value which is used as
     318             :     // argument of the store.
     319           0 :     if (value->type() != type()) {
     320             :         // If we expect to read a type which is more generic than the type seen
     321             :         // by the store, then we box the value used by the store.
     322           0 :         if (type() != MIRType::Value)
     323           0 :             return nullptr;
     324             :         // We cannot unbox ObjectOrNull yet.
     325           0 :         if (value->type() == MIRType::ObjectOrNull)
     326           0 :             return nullptr;
     327             : 
     328           0 :         MOZ_ASSERT(value->type() < MIRType::Value);
     329           0 :         MBox* box = MBox::New(alloc, value);
     330           0 :         value = box;
     331             :     }
     332             : 
     333           0 :     return value;
     334             : }
     335             : 
     336             : void
     337        1244 : MDefinition::analyzeEdgeCasesForward()
     338             : {
     339        1244 : }
     340             : 
     341             : void
     342        1471 : MDefinition::analyzeEdgeCasesBackward()
     343             : {
     344        1471 : }
     345             : 
     346             : void
     347        4969 : MInstruction::setResumePoint(MResumePoint* resumePoint)
     348             : {
     349        4969 :     MOZ_ASSERT(!resumePoint_);
     350        4969 :     resumePoint_ = resumePoint;
     351        4969 :     resumePoint_->setInstruction(this);
     352        4969 : }
     353             : 
     354             : void
     355           0 : MInstruction::stealResumePoint(MInstruction* ins)
     356             : {
     357           0 :     MOZ_ASSERT(ins->resumePoint_->instruction() == ins);
     358           0 :     resumePoint_ = ins->resumePoint_;
     359           0 :     ins->resumePoint_ = nullptr;
     360           0 :     resumePoint_->replaceInstruction(this);
     361           0 : }
     362             : 
     363             : void
     364          49 : MInstruction::moveResumePointAsEntry()
     365             : {
     366          49 :     MOZ_ASSERT(isNop());
     367          49 :     block()->clearEntryResumePoint();
     368          49 :     block()->setEntryResumePoint(resumePoint_);
     369          49 :     resumePoint_->resetInstruction();
     370          49 :     resumePoint_ = nullptr;
     371          49 : }
     372             : 
     373             : void
     374           0 : MInstruction::clearResumePoint()
     375             : {
     376           0 :     resumePoint_->resetInstruction();
     377           0 :     block()->discardPreAllocatedResumePoint(resumePoint_);
     378           0 :     resumePoint_ = nullptr;
     379           0 : }
     380             : 
     381             : bool
     382        1763 : MDefinition::maybeEmulatesUndefined(CompilerConstraintList* constraints)
     383             : {
     384        1763 :     if (!mightBeType(MIRType::Object))
     385        1750 :         return false;
     386             : 
     387          13 :     TemporaryTypeSet* types = resultTypeSet();
     388          13 :     if (!types)
     389           6 :         return true;
     390             : 
     391           7 :     return types->maybeEmulatesUndefined(constraints);
     392             : }
     393             : 
     394             : static bool
     395           3 : MaybeCallable(CompilerConstraintList* constraints, MDefinition* op)
     396             : {
     397           3 :     if (!op->mightBeType(MIRType::Object))
     398           3 :         return false;
     399             : 
     400           0 :     TemporaryTypeSet* types = op->resultTypeSet();
     401           0 :     if (!types)
     402           0 :         return true;
     403             : 
     404           0 :     return types->maybeCallable(constraints);
     405             : }
     406             : 
     407             : /* static */ const char*
     408           0 : AliasSet::Name(size_t flag)
     409             : {
     410           0 :     switch(flag) {
     411           0 :       case 0: return "ObjectFields";
     412           0 :       case 1: return "Element";
     413           0 :       case 2: return "UnboxedElement";
     414           0 :       case 3: return "DynamicSlot";
     415           0 :       case 4: return "FixedSlot";
     416           0 :       case 5: return "DOMProperty";
     417           0 :       case 6: return "FrameArgument";
     418           0 :       case 7: return "WasmGlobalVar";
     419           0 :       case 8: return "WasmHeap";
     420           0 :       case 9: return "TypedArrayLength";
     421             :       default:
     422           0 :         MOZ_CRASH("Unknown flag");
     423             :     }
     424             : }
     425             : 
     426             : void
     427         912 : MTest::cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints)
     428             : {
     429         912 :     MOZ_ASSERT(operandMightEmulateUndefined());
     430             : 
     431         912 :     if (!getOperand(0)->maybeEmulatesUndefined(constraints))
     432         910 :         markNoOperandEmulatesUndefined();
     433         912 : }
     434             : 
     435             : MDefinition*
     436         232 : MTest::foldsDoubleNegation(TempAllocator& alloc)
     437             : {
     438         232 :     MDefinition* op = getOperand(0);
     439             : 
     440         232 :     if (op->isNot()) {
     441             :         // If the operand of the Not is itself a Not, they cancel out.
     442           8 :         MDefinition* opop = op->getOperand(0);
     443           8 :         if (opop->isNot())
     444           0 :             return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse());
     445           8 :         return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue());
     446             :     }
     447         224 :     return nullptr;
     448             : }
     449             : 
     450             : MDefinition*
     451         224 : MTest::foldsConstant(TempAllocator& alloc)
     452             : {
     453         224 :     MDefinition* op = getOperand(0);
     454         224 :     if (MConstant* opConst = op->maybeConstantValue()) {
     455             :         bool b;
     456          32 :         if (opConst->valueToBoolean(&b))
     457          32 :             return MGoto::New(alloc, b ? ifTrue() : ifFalse());
     458             :     }
     459         192 :     return nullptr;
     460             : }
     461             : 
     462             : MDefinition*
     463         192 : MTest::foldsTypes(TempAllocator& alloc)
     464             : {
     465         192 :     MDefinition* op = getOperand(0);
     466             : 
     467         192 :     switch (op->type()) {
     468             :       case MIRType::Undefined:
     469             :       case MIRType::Null:
     470           0 :         return MGoto::New(alloc, ifFalse());
     471             :       case MIRType::Symbol:
     472           0 :         return MGoto::New(alloc, ifTrue());
     473             :       case MIRType::Object:
     474           0 :         if (!operandMightEmulateUndefined())
     475           0 :             return MGoto::New(alloc, ifTrue());
     476           0 :         break;
     477             :       default:
     478         192 :         break;
     479             :     }
     480         192 :     return nullptr;
     481             : }
     482             : 
     483             : MDefinition*
     484         192 : MTest::foldsNeedlessControlFlow(TempAllocator& alloc)
     485             : {
     486         228 :     for (MInstructionIterator iter(ifTrue()->begin()), end(ifTrue()->end()); iter != end; ) {
     487         209 :         MInstruction* ins = *iter++;
     488         209 :         if (ins->isNop() || ins->isGoto())
     489          22 :             continue;
     490         187 :         if (ins->hasUses())
     491         320 :             return nullptr;
     492          40 :         if (!DeadIfUnused(ins))
     493          26 :             return nullptr;
     494             :     }
     495             : 
     496          38 :     for (MInstructionIterator iter(ifFalse()->begin()), end(ifFalse()->end()); iter != end; ) {
     497          19 :         MInstruction* ins = *iter++;
     498          19 :         if (ins->isNop() || ins->isGoto())
     499           0 :             continue;
     500          19 :         if (ins->hasUses())
     501          34 :             return nullptr;
     502           4 :         if (!DeadIfUnused(ins))
     503           4 :             return nullptr;
     504             :     }
     505             : 
     506           0 :     if (ifTrue()->numSuccessors() != 1 || ifFalse()->numSuccessors() != 1)
     507           0 :         return nullptr;
     508           0 :     if (ifTrue()->getSuccessor(0) != ifFalse()->getSuccessor(0))
     509           0 :         return nullptr;
     510             : 
     511           0 :     if (ifTrue()->successorWithPhis())
     512           0 :         return nullptr;
     513             : 
     514           0 :     return MGoto::New(alloc, ifTrue());
     515             : }
     516             : 
     517             : MDefinition*
     518         232 : MTest::foldsTo(TempAllocator& alloc)
     519             : {
     520             : 
     521         232 :     if (MDefinition* def = foldsDoubleNegation(alloc))
     522           8 :         return def;
     523             : 
     524         224 :     if (MDefinition* def = foldsConstant(alloc))
     525          32 :         return def;
     526             : 
     527         192 :     if (MDefinition* def = foldsTypes(alloc))
     528           0 :         return def;
     529             : 
     530         192 :     if (MDefinition* def = foldsNeedlessControlFlow(alloc))
     531           0 :         return def;
     532             : 
     533         192 :     return this;
     534             : }
     535             : 
     536             : void
     537           2 : MTest::filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
     538             :                               bool* filtersNull)
     539             : {
     540           2 :     MDefinition* ins = getOperand(0);
     541           2 :     if (ins->isCompare()) {
     542           0 :         ins->toCompare()->filtersUndefinedOrNull(trueBranch, subject, filtersUndefined, filtersNull);
     543           0 :         return;
     544             :     }
     545             : 
     546           2 :     if (!trueBranch && ins->isNot()) {
     547           0 :         *subject = ins->getOperand(0);
     548           0 :         *filtersUndefined = *filtersNull = true;
     549           0 :         return;
     550             :     }
     551             : 
     552           2 :     if (trueBranch) {
     553           0 :         *subject = ins;
     554           0 :         *filtersUndefined = *filtersNull = true;
     555           0 :         return;
     556             :     }
     557             : 
     558           2 :     *filtersUndefined = *filtersNull = false;
     559           2 :     *subject = nullptr;
     560             : }
     561             : 
     562             : void
     563           0 : MDefinition::printOpcode(GenericPrinter& out) const
     564             : {
     565           0 :     PrintOpcodeName(out, op());
     566           0 :     for (size_t j = 0, e = numOperands(); j < e; j++) {
     567           0 :         out.printf(" ");
     568           0 :         if (getUseFor(j)->hasProducer())
     569           0 :             getOperand(j)->printName(out);
     570             :         else
     571           0 :             out.printf("(null)");
     572             :     }
     573           0 : }
     574             : 
     575             : void
     576           0 : MDefinition::dump(GenericPrinter& out) const
     577             : {
     578           0 :     printName(out);
     579           0 :     out.printf(" = ");
     580           0 :     printOpcode(out);
     581           0 :     out.printf("\n");
     582             : 
     583           0 :     if (isInstruction()) {
     584           0 :         if (MResumePoint* resume = toInstruction()->resumePoint())
     585           0 :             resume->dump(out);
     586             :     }
     587           0 : }
     588             : 
     589             : void
     590           0 : MDefinition::dump() const
     591             : {
     592           0 :     Fprinter out(stderr);
     593           0 :     dump(out);
     594           0 :     out.finish();
     595           0 : }
     596             : 
     597             : void
     598           0 : MDefinition::dumpLocation(GenericPrinter& out) const
     599             : {
     600           0 :     MResumePoint* rp = nullptr;
     601           0 :     const char* linkWord = nullptr;
     602           0 :     if (isInstruction() && toInstruction()->resumePoint()) {
     603           0 :         rp = toInstruction()->resumePoint();
     604           0 :         linkWord = "at";
     605             :     } else {
     606           0 :         rp = block()->entryResumePoint();
     607           0 :         linkWord = "after";
     608             :     }
     609             : 
     610           0 :     while (rp) {
     611           0 :         JSScript* script = rp->block()->info().script();
     612           0 :         uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc());
     613           0 :         out.printf("  %s %s:%d\n", linkWord, script->filename(), lineno);
     614           0 :         rp = rp->caller();
     615           0 :         linkWord = "in";
     616             :     }
     617           0 : }
     618             : 
     619             : void
     620           0 : MDefinition::dumpLocation() const
     621             : {
     622           0 :     Fprinter out(stderr);
     623           0 :     dumpLocation(out);
     624           0 :     out.finish();
     625           0 : }
     626             : 
     627             : #if defined(DEBUG) || defined(JS_JITSPEW)
     628             : size_t
     629           0 : MDefinition::useCount() const
     630             : {
     631           0 :     size_t count = 0;
     632           0 :     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++)
     633           0 :         count++;
     634           0 :     return count;
     635             : }
     636             : 
     637             : size_t
     638       22401 : MDefinition::defUseCount() const
     639             : {
     640       22401 :     size_t count = 0;
     641      359865 :     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++)
     642      337464 :         if ((*i)->consumer()->isDefinition())
     643       44807 :             count++;
     644       22401 :     return count;
     645             : }
     646             : #endif
     647             : 
     648             : bool
     649          49 : MDefinition::hasOneUse() const
     650             : {
     651          49 :     MUseIterator i(uses_.begin());
     652          49 :     if (i == uses_.end())
     653           0 :         return false;
     654          49 :     i++;
     655          49 :     return i == uses_.end();
     656             : }
     657             : 
     658             : bool
     659          28 : MDefinition::hasOneDefUse() const
     660             : {
     661          28 :     bool hasOneDefUse = false;
     662         168 :     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
     663         162 :         if (!(*i)->consumer()->isDefinition())
     664         112 :             continue;
     665             : 
     666             :         // We already have a definition use. So 1+
     667          50 :         if (hasOneDefUse)
     668          22 :             return false;
     669             : 
     670             :         // We saw one definition. Loop to test if there is another.
     671          28 :         hasOneDefUse = true;
     672             :     }
     673             : 
     674           6 :     return hasOneDefUse;
     675             : }
     676             : 
     677             : bool
     678          40 : MDefinition::hasDefUses() const
     679             : {
     680          44 :     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
     681          30 :         if ((*i)->consumer()->isDefinition())
     682          26 :             return true;
     683             :     }
     684             : 
     685          14 :     return false;
     686             : }
     687             : 
     688             : bool
     689        1565 : MDefinition::hasLiveDefUses() const
     690             : {
     691        5573 :     for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
     692        4008 :         MNode* ins = (*i)->consumer();
     693        4008 :         if (ins->isDefinition()) {
     694         696 :             if (!ins->toDefinition()->isRecoveredOnBailout())
     695           0 :                 return true;
     696             :         } else {
     697        3312 :             MOZ_ASSERT(ins->isResumePoint());
     698        3312 :             if (!ins->toResumePoint()->isRecoverableOperand(*i))
     699           0 :                 return true;
     700             :         }
     701             :     }
     702             : 
     703        1565 :     return false;
     704             : }
     705             : 
     706             : void
     707          23 : MDefinition::replaceAllUsesWith(MDefinition* dom)
     708             : {
     709          54 :     for (size_t i = 0, e = numOperands(); i < e; ++i)
     710          31 :         getOperand(i)->setUseRemovedUnchecked();
     711             : 
     712          23 :     justReplaceAllUsesWith(dom);
     713          23 : }
     714             : 
     715             : void
     716        2173 : MDefinition::justReplaceAllUsesWith(MDefinition* dom)
     717             : {
     718        2173 :     MOZ_ASSERT(dom != nullptr);
     719        2173 :     MOZ_ASSERT(dom != this);
     720             : 
     721             :     // Carry over the fact the value has uses which are no longer inspectable
     722             :     // with the graph.
     723        2173 :     if (isUseRemoved())
     724          77 :         dom->setUseRemovedUnchecked();
     725             : 
     726       36057 :     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i)
     727       33884 :         i->setProducerUnchecked(dom);
     728        2173 :     dom->uses_.takeElements(uses_);
     729        2173 : }
     730             : 
     731             : void
     732           0 : MDefinition::justReplaceAllUsesWithExcept(MDefinition* dom)
     733             : {
     734           0 :     MOZ_ASSERT(dom != nullptr);
     735           0 :     MOZ_ASSERT(dom != this);
     736             : 
     737             :     // Carry over the fact the value has uses which are no longer inspectable
     738             :     // with the graph.
     739           0 :     if (isUseRemoved())
     740           0 :         dom->setUseRemovedUnchecked();
     741             : 
     742             :     // Move all uses to new dom. Save the use of the dominating instruction.
     743           0 :     MUse *exceptUse = nullptr;
     744           0 :     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) {
     745           0 :         if (i->consumer() != dom) {
     746           0 :             i->setProducerUnchecked(dom);
     747             :         } else {
     748           0 :             MOZ_ASSERT(!exceptUse);
     749           0 :             exceptUse = *i;
     750             :         }
     751             :     }
     752           0 :     dom->uses_.takeElements(uses_);
     753             : 
     754             :     // Restore the use to the original definition.
     755           0 :     dom->uses_.remove(exceptUse);
     756           0 :     exceptUse->setProducerUnchecked(this);
     757           0 :     uses_.pushFront(exceptUse);
     758           0 : }
     759             : 
     760             : bool
     761         677 : MDefinition::optimizeOutAllUses(TempAllocator& alloc)
     762             : {
     763        5141 :     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
     764        4464 :         MUse* use = *i++;
     765        4464 :         MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc);
     766        4464 :         if (!alloc.ensureBallast())
     767           0 :             return false;
     768             : 
     769             :         // Update the resume point operand to use the optimized-out constant.
     770        4464 :         use->setProducerUnchecked(constant);
     771        4464 :         constant->addUseUnchecked(use);
     772             :     }
     773             : 
     774             :     // Remove dangling pointers.
     775         677 :     this->uses_.clear();
     776         677 :     return true;
     777             : }
     778             : 
     779             : void
     780           0 : MDefinition::replaceAllLiveUsesWith(MDefinition* dom)
     781             : {
     782           0 :     for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ) {
     783           0 :         MUse* use = *i++;
     784           0 :         MNode* consumer = use->consumer();
     785           0 :         if (consumer->isResumePoint())
     786           0 :             continue;
     787           0 :         if (consumer->isDefinition() && consumer->toDefinition()->isRecoveredOnBailout())
     788           0 :             continue;
     789             : 
     790             :         // Update the operand to use the dominating definition.
     791           0 :         use->replaceProducer(dom);
     792             :     }
     793           0 : }
     794             : 
     795             : bool
     796         184 : MDefinition::emptyResultTypeSet() const
     797             : {
     798         184 :     return resultTypeSet() && resultTypeSet()->empty();
     799             : }
     800             : 
     801             : MConstant*
     802        5855 : MConstant::New(TempAllocator& alloc, const Value& v, CompilerConstraintList* constraints)
     803             : {
     804        5855 :     return new(alloc) MConstant(v, constraints);
     805             : }
     806             : 
     807             : MConstant*
     808           0 : MConstant::New(TempAllocator::Fallible alloc, const Value& v, CompilerConstraintList* constraints)
     809             : {
     810           0 :     return new(alloc) MConstant(v, constraints);
     811             : }
     812             : 
     813             : MConstant*
     814           0 : MConstant::NewFloat32(TempAllocator& alloc, double d)
     815             : {
     816           0 :     MOZ_ASSERT(IsNaN(d) || d == double(float(d)));
     817           0 :     return new(alloc) MConstant(float(d));
     818             : }
     819             : 
     820             : MConstant*
     821           0 : MConstant::NewInt64(TempAllocator& alloc, int64_t i)
     822             : {
     823           0 :     return new(alloc) MConstant(i);
     824             : }
     825             : 
     826             : MConstant*
     827           0 : MConstant::New(TempAllocator& alloc, const Value& v, MIRType type)
     828             : {
     829           0 :     if (type == MIRType::Float32)
     830           0 :         return NewFloat32(alloc, v.toNumber());
     831           0 :     MConstant* res = New(alloc, v);
     832           0 :     MOZ_ASSERT(res->type() == type);
     833           0 :     return res;
     834             : }
     835             : 
     836             : MConstant*
     837          49 : MConstant::NewConstraintlessObject(TempAllocator& alloc, JSObject* v)
     838             : {
     839          49 :     return new(alloc) MConstant(v);
     840             : }
     841             : 
     842             : static TemporaryTypeSet*
     843         641 : MakeSingletonTypeSetFromKey(CompilerConstraintList* constraints, TypeSet::ObjectKey* key)
     844             : {
     845             :     // Invalidate when this object's ObjectGroup gets unknown properties. This
     846             :     // happens for instance when we mutate an object's __proto__, in this case
     847             :     // we want to invalidate and mark this TypeSet as containing AnyObject
     848             :     // (because mutating __proto__ will change an object's ObjectGroup).
     849         641 :     MOZ_ASSERT(constraints);
     850         641 :     (void)key->hasStableClassAndProto(constraints);
     851             : 
     852         641 :     LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc();
     853         641 :     return alloc->new_<TemporaryTypeSet>(alloc, TypeSet::ObjectType(key));
     854             : }
     855             : 
     856             : TemporaryTypeSet*
     857         632 : jit::MakeSingletonTypeSet(CompilerConstraintList* constraints, JSObject* obj)
     858             : {
     859         632 :     return MakeSingletonTypeSetFromKey(constraints, TypeSet::ObjectKey::get(obj));
     860             : }
     861             : 
     862             : TemporaryTypeSet*
     863           9 : jit::MakeSingletonTypeSet(CompilerConstraintList* constraints, ObjectGroup* obj)
     864             : {
     865           9 :     return MakeSingletonTypeSetFromKey(constraints, TypeSet::ObjectKey::get(obj));
     866             : }
     867             : 
     868             : static TemporaryTypeSet*
     869          19 : MakeUnknownTypeSet()
     870             : {
     871          19 :     LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc();
     872          19 :     return alloc->new_<TemporaryTypeSet>(alloc, TypeSet::UnknownType());
     873             : }
     874             : 
     875             : #ifdef DEBUG
     876             : 
     877             : bool
     878           0 : jit::IonCompilationCanUseNurseryPointers()
     879             : {
     880             :     // If we are doing backend compilation, which could occur on a helper
     881             :     // thread but might actually be on the active thread, check the flag set on
     882             :     // the JSContext by AutoEnterIonCompilation.
     883           0 :     if (CurrentThreadIsIonCompiling())
     884           0 :         return !CurrentThreadIsIonCompilingSafeForMinorGC();
     885             : 
     886             :     // Otherwise, we must be on the active thread during MIR construction. The
     887             :     // store buffer must have been notified that minor GCs must cancel pending
     888             :     // or in progress Ion compilations.
     889           0 :     JSContext* cx = TlsContext.get();
     890           0 :     return cx->zone()->group()->storeBuffer().cancelIonCompilations();
     891             : }
     892             : 
     893             : #endif // DEBUG
     894             : 
     895        5855 : MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints)
     896             : {
     897        5855 :     setResultType(MIRTypeFromValue(vp));
     898             : 
     899        5855 :     MOZ_ASSERT(payload_.asBits == 0);
     900             : 
     901        5855 :     switch (type()) {
     902             :       case MIRType::Undefined:
     903             :       case MIRType::Null:
     904        1697 :         break;
     905             :       case MIRType::Boolean:
     906         209 :         payload_.b = vp.toBoolean();
     907         209 :         break;
     908             :       case MIRType::Int32:
     909        2204 :         payload_.i32 = vp.toInt32();
     910        2204 :         break;
     911             :       case MIRType::Double:
     912          30 :         payload_.d = vp.toDouble();
     913          30 :         break;
     914             :       case MIRType::String:
     915         159 :         MOZ_ASSERT(vp.toString()->isAtom());
     916         159 :         payload_.str = vp.toString();
     917         159 :         break;
     918             :       case MIRType::Symbol:
     919           5 :         payload_.sym = vp.toSymbol();
     920           5 :         break;
     921             :       case MIRType::Object:
     922         581 :         payload_.obj = &vp.toObject();
     923             :         // Create a singleton type set for the object. This isn't necessary for
     924             :         // other types as the result type encodes all needed information.
     925         581 :         MOZ_ASSERT_IF(IsInsideNursery(&vp.toObject()), IonCompilationCanUseNurseryPointers());
     926         581 :         setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
     927         581 :         break;
     928             :       case MIRType::MagicOptimizedArguments:
     929             :       case MIRType::MagicOptimizedOut:
     930             :       case MIRType::MagicHole:
     931             :       case MIRType::MagicIsConstructing:
     932         951 :         break;
     933             :       case MIRType::MagicUninitializedLexical:
     934             :         // JS_UNINITIALIZED_LEXICAL does not escape to script and is not
     935             :         // observed in type sets. However, it may flow around freely during
     936             :         // Ion compilation. Give it an unknown typeset to poison any type sets
     937             :         // it merges with.
     938             :         //
     939             :         // TODO We could track uninitialized lexicals more precisely by tracking
     940             :         // them in type sets.
     941          19 :         setResultTypeSet(MakeUnknownTypeSet());
     942          19 :         break;
     943             :       default:
     944           0 :         MOZ_CRASH("Unexpected type");
     945             :     }
     946             : 
     947        5855 :     setMovable();
     948        5855 : }
     949             : 
     950          49 : MConstant::MConstant(JSObject* obj)
     951             : {
     952          49 :     MOZ_ASSERT_IF(IsInsideNursery(obj), IonCompilationCanUseNurseryPointers());
     953          49 :     setResultType(MIRType::Object);
     954          49 :     payload_.obj = obj;
     955          49 :     setMovable();
     956          49 : }
     957             : 
     958           0 : MConstant::MConstant(float f)
     959             : {
     960           0 :     setResultType(MIRType::Float32);
     961           0 :     payload_.f = f;
     962           0 :     setMovable();
     963           0 : }
     964             : 
     965           0 : MConstant::MConstant(int64_t i)
     966             : {
     967           0 :     setResultType(MIRType::Int64);
     968           0 :     payload_.i64 = i;
     969           0 :     setMovable();
     970           0 : }
     971             : 
     972             : #ifdef DEBUG
     973             : void
     974        5352 : MConstant::assertInitializedPayload() const
     975             : {
     976             :     // valueHash() and equals() expect the unused payload bits to be
     977             :     // initialized to zero. Assert this in debug builds.
     978             : 
     979        5352 :     switch (type()) {
     980             :       case MIRType::Int32:
     981             :       case MIRType::Float32:
     982         575 :         MOZ_ASSERT((payload_.asBits >> 32) == 0);
     983         575 :         break;
     984             :       case MIRType::Boolean:
     985         916 :         MOZ_ASSERT((payload_.asBits >> 1) == 0);
     986         916 :         break;
     987             :       case MIRType::Double:
     988             :       case MIRType::Int64:
     989           5 :         break;
     990             :       case MIRType::String:
     991             :       case MIRType::Object:
     992             :       case MIRType::Symbol:
     993             :         MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0);
     994         761 :         break;
     995             :       default:
     996        3095 :         MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()));
     997        3095 :         MOZ_ASSERT(payload_.asBits == 0);
     998        3095 :         break;
     999             :     }
    1000        5352 : }
    1001             : #endif
    1002             : 
    1003             : static HashNumber
    1004        1958 : ConstantValueHash(MIRType type, uint64_t payload)
    1005             : {
    1006             :     // Build a 64-bit value holding both the payload and the type.
    1007             :     static const size_t TypeBits = 8;
    1008             :     static const size_t TypeShift = 64 - TypeBits;
    1009        1958 :     MOZ_ASSERT(uintptr_t(type) <= (1 << TypeBits) - 1);
    1010        1958 :     uint64_t bits = (uint64_t(type) << TypeShift) ^ payload;
    1011             : 
    1012             :     // Fold all 64 bits into the 32-bit result. It's tempting to just discard
    1013             :     // half of the bits, as this is just a hash, however there are many common
    1014             :     // patterns of values where only the low or the high bits vary, so
    1015             :     // discarding either side would lead to excessive hash collisions.
    1016        1958 :     return (HashNumber)bits ^ (HashNumber)(bits >> 32);
    1017             : }
    1018             : 
    1019             : HashNumber
    1020        1958 : MConstant::valueHash() const
    1021             : {
    1022             :     static_assert(sizeof(Payload) == sizeof(uint64_t),
    1023             :                   "Code below assumes payload fits in 64 bits");
    1024             : 
    1025        1958 :     assertInitializedPayload();
    1026        1958 :     return ConstantValueHash(type(), payload_.asBits);
    1027             : }
    1028             : 
    1029             : bool
    1030        3394 : MConstant::congruentTo(const MDefinition* ins) const
    1031             : {
    1032        3394 :     return ins->isConstant() && equals(ins->toConstant());
    1033             : }
    1034             : 
    1035             : void
    1036           0 : MConstant::printOpcode(GenericPrinter& out) const
    1037             : {
    1038           0 :     PrintOpcodeName(out, op());
    1039           0 :     out.printf(" ");
    1040           0 :     switch (type()) {
    1041             :       case MIRType::Undefined:
    1042           0 :         out.printf("undefined");
    1043           0 :         break;
    1044             :       case MIRType::Null:
    1045           0 :         out.printf("null");
    1046           0 :         break;
    1047             :       case MIRType::Boolean:
    1048           0 :         out.printf(toBoolean() ? "true" : "false");
    1049           0 :         break;
    1050             :       case MIRType::Int32:
    1051           0 :         out.printf("0x%x", toInt32());
    1052           0 :         break;
    1053             :       case MIRType::Int64:
    1054           0 :         out.printf("0x%" PRIx64, toInt64());
    1055           0 :         break;
    1056             :       case MIRType::Double:
    1057           0 :         out.printf("%.16g", toDouble());
    1058           0 :         break;
    1059             :       case MIRType::Float32:
    1060             :       {
    1061           0 :         float val = toFloat32();
    1062           0 :         out.printf("%.16g", val);
    1063           0 :         break;
    1064             :       }
    1065             :       case MIRType::Object:
    1066           0 :         if (toObject().is<JSFunction>()) {
    1067           0 :             JSFunction* fun = &toObject().as<JSFunction>();
    1068           0 :             if (fun->displayAtom()) {
    1069           0 :                 out.put("function ");
    1070           0 :                 EscapedStringPrinter(out, fun->displayAtom(), 0);
    1071             :             } else {
    1072           0 :                 out.put("unnamed function");
    1073             :             }
    1074           0 :             if (fun->hasScript()) {
    1075           0 :                 JSScript* script = fun->nonLazyScript();
    1076           0 :                 out.printf(" (%s:%" PRIuSIZE ")",
    1077           0 :                         script->filename() ? script->filename() : "", script->lineno());
    1078             :             }
    1079           0 :             out.printf(" at %p", (void*) fun);
    1080           0 :             break;
    1081             :         }
    1082           0 :         out.printf("object %p (%s)", (void*)&toObject(), toObject().getClass()->name);
    1083           0 :         break;
    1084             :       case MIRType::Symbol:
    1085           0 :         out.printf("symbol at %p", (void*)toSymbol());
    1086           0 :         break;
    1087             :       case MIRType::String:
    1088           0 :         out.printf("string %p", (void*)toString());
    1089           0 :         break;
    1090             :       case MIRType::MagicOptimizedArguments:
    1091           0 :         out.printf("magic lazyargs");
    1092           0 :         break;
    1093             :       case MIRType::MagicHole:
    1094           0 :         out.printf("magic hole");
    1095           0 :         break;
    1096             :       case MIRType::MagicIsConstructing:
    1097           0 :         out.printf("magic is-constructing");
    1098           0 :         break;
    1099             :       case MIRType::MagicOptimizedOut:
    1100           0 :         out.printf("magic optimized-out");
    1101           0 :         break;
    1102             :       case MIRType::MagicUninitializedLexical:
    1103           0 :         out.printf("magic uninitialized-lexical");
    1104           0 :         break;
    1105             :       default:
    1106           0 :         MOZ_CRASH("unexpected type");
    1107             :     }
    1108           0 : }
    1109             : 
    1110             : bool
    1111          88 : MConstant::canProduceFloat32() const
    1112             : {
    1113          88 :     if (!isTypeRepresentableAsDouble())
    1114          83 :         return false;
    1115             : 
    1116           5 :     if (type() == MIRType::Int32)
    1117           5 :         return IsFloat32Representable(static_cast<double>(toInt32()));
    1118           0 :     if (type() == MIRType::Double)
    1119           0 :         return IsFloat32Representable(toDouble());
    1120           0 :     MOZ_ASSERT(type() == MIRType::Float32);
    1121           0 :     return true;
    1122             : }
    1123             : 
    1124             : Value
    1125         571 : MConstant::toJSValue() const
    1126             : {
    1127             :     // Wasm has types like int64 that cannot be stored as js::Value. It also
    1128             :     // doesn't want the NaN canonicalization enforced by js::Value.
    1129         571 :     MOZ_ASSERT(!IsCompilingWasm());
    1130             : 
    1131         571 :     switch (type()) {
    1132             :       case MIRType::Undefined:
    1133          48 :         return UndefinedValue();
    1134             :       case MIRType::Null:
    1135           4 :         return NullValue();
    1136             :       case MIRType::Boolean:
    1137         189 :         return BooleanValue(toBoolean());
    1138             :       case MIRType::Int32:
    1139         106 :         return Int32Value(toInt32());
    1140             :       case MIRType::Double:
    1141           0 :         return DoubleValue(toDouble());
    1142             :       case MIRType::Float32:
    1143           0 :         return Float32Value(toFloat32());
    1144             :       case MIRType::String:
    1145          29 :         return StringValue(toString());
    1146             :       case MIRType::Symbol:
    1147           3 :         return SymbolValue(toSymbol());
    1148             :       case MIRType::Object:
    1149         188 :         return ObjectValue(toObject());
    1150             :       case MIRType::MagicOptimizedArguments:
    1151           0 :         return MagicValue(JS_OPTIMIZED_ARGUMENTS);
    1152             :       case MIRType::MagicOptimizedOut:
    1153           0 :         return MagicValue(JS_OPTIMIZED_OUT);
    1154             :       case MIRType::MagicHole:
    1155           0 :         return MagicValue(JS_ELEMENTS_HOLE);
    1156             :       case MIRType::MagicIsConstructing:
    1157           0 :         return MagicValue(JS_IS_CONSTRUCTING);
    1158             :       case MIRType::MagicUninitializedLexical:
    1159           4 :         return MagicValue(JS_UNINITIALIZED_LEXICAL);
    1160             :       default:
    1161           0 :         MOZ_CRASH("Unexpected type");
    1162             :     }
    1163             : }
    1164             : 
    1165             : bool
    1166          43 : MConstant::valueToBoolean(bool* res) const
    1167             : {
    1168          43 :     switch (type()) {
    1169             :       case MIRType::Boolean:
    1170          30 :         *res = toBoolean();
    1171          30 :         return true;
    1172             :       case MIRType::Int32:
    1173           0 :         *res = toInt32() != 0;
    1174           0 :         return true;
    1175             :       case MIRType::Int64:
    1176           0 :         *res = toInt64() != 0;
    1177           0 :         return true;
    1178             :       case MIRType::Double:
    1179           0 :         *res = !mozilla::IsNaN(toDouble()) && toDouble() != 0.0;
    1180           0 :         return true;
    1181             :       case MIRType::Float32:
    1182           0 :         *res = !mozilla::IsNaN(toFloat32()) && toFloat32() != 0.0f;
    1183           0 :         return true;
    1184             :       case MIRType::Null:
    1185             :       case MIRType::Undefined:
    1186          13 :         *res = false;
    1187          13 :         return true;
    1188             :       case MIRType::Symbol:
    1189           0 :         *res = true;
    1190           0 :         return true;
    1191             :       case MIRType::String:
    1192           0 :         *res = toString()->length() != 0;
    1193           0 :         return true;
    1194             :       case MIRType::Object:
    1195           0 :         *res = !EmulatesUndefined(&toObject());
    1196           0 :         return true;
    1197             :       default:
    1198           0 :         MOZ_ASSERT(IsMagicType(type()));
    1199           0 :         return false;
    1200             :     }
    1201             : }
    1202             : 
    1203             : HashNumber
    1204           0 : MWasmFloatConstant::valueHash() const
    1205             : {
    1206           0 :     return ConstantValueHash(type(), u.bits_);
    1207             : }
    1208             : 
    1209             : bool
    1210           0 : MWasmFloatConstant::congruentTo(const MDefinition* ins) const
    1211             : {
    1212           0 :     return ins->isWasmFloatConstant() &&
    1213           0 :            type() == ins->type() &&
    1214           0 :            u.bits_ == ins->toWasmFloatConstant()->u.bits_;
    1215             : }
    1216             : 
    1217             : MDefinition*
    1218           0 : MSimdValueX4::foldsTo(TempAllocator& alloc)
    1219             : {
    1220             : #ifdef DEBUG
    1221           0 :     MIRType laneType = SimdTypeToLaneArgumentType(type());
    1222             : #endif
    1223           0 :     bool allConstants = true;
    1224           0 :     bool allSame = true;
    1225             : 
    1226           0 :     for (size_t i = 0; i < 4; ++i) {
    1227           0 :         MDefinition* op = getOperand(i);
    1228           0 :         MOZ_ASSERT(op->type() == laneType);
    1229           0 :         if (!op->isConstant())
    1230           0 :             allConstants = false;
    1231           0 :         if (i > 0 && op != getOperand(i - 1))
    1232           0 :             allSame = false;
    1233             :     }
    1234             : 
    1235           0 :     if (!allConstants && !allSame)
    1236           0 :         return this;
    1237             : 
    1238           0 :     if (allConstants) {
    1239             :         SimdConstant cst;
    1240           0 :         switch (type()) {
    1241             :           case MIRType::Bool32x4: {
    1242             :             int32_t a[4];
    1243           0 :             for (size_t i = 0; i < 4; ++i)
    1244           0 :                 a[i] = getOperand(i)->toConstant()->valueToBooleanInfallible() ? -1 : 0;
    1245           0 :             cst = SimdConstant::CreateX4(a);
    1246           0 :             break;
    1247             :           }
    1248             :           case MIRType::Int32x4: {
    1249             :             int32_t a[4];
    1250           0 :             for (size_t i = 0; i < 4; ++i)
    1251           0 :                 a[i] = getOperand(i)->toConstant()->toInt32();
    1252           0 :             cst = SimdConstant::CreateX4(a);
    1253           0 :             break;
    1254             :           }
    1255             :           case MIRType::Float32x4: {
    1256             :             float a[4];
    1257           0 :             for (size_t i = 0; i < 4; ++i)
    1258           0 :                 a[i] = getOperand(i)->toConstant()->numberToDouble();
    1259           0 :             cst = SimdConstant::CreateX4(a);
    1260           0 :             break;
    1261             :           }
    1262           0 :           default: MOZ_CRASH("unexpected type in MSimdValueX4::foldsTo");
    1263             :         }
    1264             : 
    1265           0 :         return MSimdConstant::New(alloc, cst, type());
    1266             :     }
    1267             : 
    1268           0 :     MOZ_ASSERT(allSame);
    1269           0 :     return MSimdSplat::New(alloc, getOperand(0), type());
    1270             : }
    1271             : 
    1272             : MDefinition*
    1273           0 : MSimdSplat::foldsTo(TempAllocator& alloc)
    1274             : {
    1275             : #ifdef DEBUG
    1276           0 :     MIRType laneType = SimdTypeToLaneArgumentType(type());
    1277             : #endif
    1278           0 :     MDefinition* op = getOperand(0);
    1279           0 :     if (!op->isConstant())
    1280           0 :         return this;
    1281           0 :     MOZ_ASSERT(op->type() == laneType);
    1282             : 
    1283             :     SimdConstant cst;
    1284           0 :     switch (type()) {
    1285             :       case MIRType::Bool8x16: {
    1286           0 :         int8_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0;
    1287           0 :         cst = SimdConstant::SplatX16(v);
    1288           0 :         break;
    1289             :       }
    1290             :       case MIRType::Bool16x8: {
    1291           0 :         int16_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0;
    1292           0 :         cst = SimdConstant::SplatX8(v);
    1293           0 :         break;
    1294             :       }
    1295             :       case MIRType::Bool32x4: {
    1296           0 :         int32_t v = op->toConstant()->valueToBooleanInfallible() ? -1 : 0;
    1297           0 :         cst = SimdConstant::SplatX4(v);
    1298           0 :         break;
    1299             :       }
    1300             :       case MIRType::Int8x16: {
    1301           0 :         int32_t v = op->toConstant()->toInt32();
    1302           0 :         cst = SimdConstant::SplatX16(v);
    1303           0 :         break;
    1304             :       }
    1305             :       case MIRType::Int16x8: {
    1306           0 :         int32_t v = op->toConstant()->toInt32();
    1307           0 :         cst = SimdConstant::SplatX8(v);
    1308           0 :         break;
    1309             :       }
    1310             :       case MIRType::Int32x4: {
    1311           0 :         int32_t v = op->toConstant()->toInt32();
    1312           0 :         cst = SimdConstant::SplatX4(v);
    1313           0 :         break;
    1314             :       }
    1315             :       case MIRType::Float32x4: {
    1316           0 :         float v = op->toConstant()->numberToDouble();
    1317           0 :         cst = SimdConstant::SplatX4(v);
    1318           0 :         break;
    1319             :       }
    1320           0 :       default: MOZ_CRASH("unexpected type in MSimdSplat::foldsTo");
    1321             :     }
    1322             : 
    1323           0 :     return MSimdConstant::New(alloc, cst, type());
    1324             : }
    1325             : 
    1326             : MDefinition*
    1327           0 : MSimdUnbox::foldsTo(TempAllocator& alloc)
    1328             : {
    1329           0 :     MDefinition* in = input();
    1330             : 
    1331           0 :     if (in->isSimdBox()) {
    1332           0 :         MSimdBox* box = in->toSimdBox();
    1333             :         // If the operand is a MSimdBox, then we just reuse the operand of the
    1334             :         // MSimdBox as long as the type corresponds to what we are supposed to
    1335             :         // unbox.
    1336           0 :         in = box->input();
    1337           0 :         if (box->simdType() != simdType())
    1338           0 :             return this;
    1339           0 :         MOZ_ASSERT(in->type() == type());
    1340           0 :         return in;
    1341             :     }
    1342             : 
    1343           0 :     return this;
    1344             : }
    1345             : 
    1346             : MDefinition*
    1347           0 : MSimdSwizzle::foldsTo(TempAllocator& alloc)
    1348             : {
    1349           0 :     if (lanesMatch(0, 1, 2, 3))
    1350           0 :         return input();
    1351           0 :     return this;
    1352             : }
    1353             : 
    1354             : MDefinition*
    1355           0 : MSimdGeneralShuffle::foldsTo(TempAllocator& alloc)
    1356             : {
    1357           0 :     FixedList<uint8_t> lanes;
    1358           0 :     if (!lanes.init(alloc, numLanes()))
    1359           0 :         return this;
    1360             : 
    1361           0 :     for (size_t i = 0; i < numLanes(); i++) {
    1362           0 :         if (!lane(i)->isConstant() || lane(i)->type() != MIRType::Int32)
    1363           0 :             return this;
    1364           0 :         int32_t temp = lane(i)->toConstant()->toInt32();
    1365           0 :         if (temp < 0 || unsigned(temp) >= numLanes() * numVectors())
    1366           0 :             return this;
    1367           0 :         lanes[i] = uint8_t(temp);
    1368             :     }
    1369             : 
    1370           0 :     if (numVectors() == 1)
    1371           0 :         return MSimdSwizzle::New(alloc, vector(0), lanes.data());
    1372             : 
    1373           0 :     MOZ_ASSERT(numVectors() == 2);
    1374           0 :     return MSimdShuffle::New(alloc, vector(0), vector(1), lanes.data());
    1375             : }
    1376             : 
    1377             : MInstruction*
    1378           0 : MSimdConvert::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* obj,
    1379             :                            MIRType toType, SimdSign sign, wasm::BytecodeOffset bytecodeOffset)
    1380             : {
    1381           0 :     MIRType fromType = obj->type();
    1382             : 
    1383           0 :     if (SupportsUint32x4FloatConversions || sign != SimdSign::Unsigned) {
    1384           0 :         MInstruction* ins = New(alloc, obj, toType, sign, bytecodeOffset);
    1385           0 :         addTo->add(ins);
    1386           0 :         return ins;
    1387             :     }
    1388             : 
    1389             :     // This architecture can't do Uint32x4 <-> Float32x4 conversions (Hi SSE!)
    1390           0 :     MOZ_ASSERT(sign == SimdSign::Unsigned);
    1391           0 :     if (fromType == MIRType::Int32x4 && toType == MIRType::Float32x4) {
    1392             :         // Converting Uint32x4 -> Float32x4. This algorithm is from LLVM.
    1393             :         //
    1394             :         // Split the input number into high and low parts:
    1395             :         //
    1396             :         // uint32_t hi = x >> 16;
    1397             :         // uint32_t lo = x & 0xffff;
    1398             :         //
    1399             :         // Insert these parts as the low mantissa bits in a float32 number with
    1400             :         // the corresponding exponent:
    1401             :         //
    1402             :         // float fhi = (bits-as-float)(hi | 0x53000000); // 0x1.0p39f + hi*2^16
    1403             :         // float flo = (bits-as-float)(lo | 0x4b000000); // 0x1.0p23f + lo
    1404             :         //
    1405             :         // Subtract the bias from the hi part:
    1406             :         //
    1407             :         // fhi -= (0x1.0p39 + 0x1.0p23) // hi*2^16 - 0x1.0p23
    1408             :         //
    1409             :         // And finally combine:
    1410             :         //
    1411             :         // result = flo + fhi // lo + hi*2^16.
    1412             : 
    1413             :         // Compute hi = obj >> 16 (lane-wise unsigned shift).
    1414           0 :         MInstruction* c16 = MConstant::New(alloc, Int32Value(16));
    1415           0 :         addTo->add(c16);
    1416           0 :         MInstruction* hi = MSimdShift::AddLegalized(alloc, addTo, obj, c16, MSimdShift::ursh);
    1417             : 
    1418             :         // Compute lo = obj & 0xffff (lane-wise).
    1419             :         MInstruction* m16 =
    1420           0 :           MSimdConstant::New(alloc, SimdConstant::SplatX4(0xffff), MIRType::Int32x4);
    1421           0 :         addTo->add(m16);
    1422           0 :         MInstruction* lo = MSimdBinaryBitwise::New(alloc, obj, m16, MSimdBinaryBitwise::and_);
    1423           0 :         addTo->add(lo);
    1424             : 
    1425             :         // Mix in the exponents.
    1426             :         MInstruction* exphi =
    1427           0 :           MSimdConstant::New(alloc, SimdConstant::SplatX4(0x53000000), MIRType::Int32x4);
    1428           0 :         addTo->add(exphi);
    1429           0 :         MInstruction* mhi = MSimdBinaryBitwise::New(alloc, hi, exphi, MSimdBinaryBitwise::or_);
    1430           0 :         addTo->add(mhi);
    1431             :         MInstruction* explo =
    1432           0 :           MSimdConstant::New(alloc, SimdConstant::SplatX4(0x4b000000), MIRType::Int32x4);
    1433           0 :         addTo->add(explo);
    1434           0 :         MInstruction* mlo = MSimdBinaryBitwise::New(alloc, lo, explo, MSimdBinaryBitwise::or_);
    1435           0 :         addTo->add(mlo);
    1436             : 
    1437             :         // Bit-cast both to Float32x4.
    1438           0 :         MInstruction* fhi = MSimdReinterpretCast::New(alloc, mhi, MIRType::Float32x4);
    1439           0 :         addTo->add(fhi);
    1440           0 :         MInstruction* flo = MSimdReinterpretCast::New(alloc, mlo, MIRType::Float32x4);
    1441           0 :         addTo->add(flo);
    1442             : 
    1443             :         // Subtract out the bias: 0x1.0p39f + 0x1.0p23f.
    1444             :         // MSVC doesn't support the hexadecimal float syntax.
    1445           0 :         const float BiasValue = 549755813888.f + 8388608.f;
    1446             :         MInstruction* bias =
    1447           0 :           MSimdConstant::New(alloc, SimdConstant::SplatX4(BiasValue), MIRType::Float32x4);
    1448           0 :         addTo->add(bias);
    1449             :         MInstruction* fhi_debiased =
    1450           0 :           MSimdBinaryArith::AddLegalized(alloc, addTo, fhi, bias, MSimdBinaryArith::Op_sub);
    1451             : 
    1452             :         // Compute the final result.
    1453             :         return MSimdBinaryArith::AddLegalized(alloc, addTo, fhi_debiased, flo,
    1454           0 :                                               MSimdBinaryArith::Op_add);
    1455             :     }
    1456             : 
    1457           0 :     if (fromType == MIRType::Float32x4 && toType == MIRType::Int32x4) {
    1458             :         // The Float32x4 -> Uint32x4 conversion can throw if the input is out of
    1459             :         // range. This is handled by the LFloat32x4ToUint32x4 expansion.
    1460           0 :         MInstruction* ins = New(alloc, obj, toType, sign, bytecodeOffset);
    1461           0 :         addTo->add(ins);
    1462           0 :         return ins;
    1463             :     }
    1464             : 
    1465           0 :     MOZ_CRASH("Unhandled SIMD type conversion");
    1466             : }
    1467             : 
    1468             : MInstruction*
    1469           0 : MSimdBinaryComp::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
    1470             :                               MDefinition* right, Operation op, SimdSign sign)
    1471             : {
    1472           0 :     MOZ_ASSERT(left->type() == right->type());
    1473           0 :     MIRType opType = left->type();
    1474           0 :     MOZ_ASSERT(IsSimdType(opType));
    1475           0 :     bool IsEquality = op == equal || op == notEqual;
    1476             : 
    1477             :     // Check if this is an unsupported unsigned compare that needs to be biased.
    1478             :     // If so, put the bias vector in `bias`.
    1479           0 :     if (sign == SimdSign::Unsigned && !IsEquality) {
    1480           0 :         MInstruction* bias = nullptr;
    1481             : 
    1482             :         // This is an order comparison of Uint32x4 vectors which are not supported on this target.
    1483             :         // Simply offset |left| and |right| by INT_MIN, then do a signed comparison.
    1484           0 :         if (!SupportsUint32x4Compares && opType == MIRType::Int32x4)
    1485           0 :             bias = MSimdConstant::New(alloc, SimdConstant::SplatX4(int32_t(0x80000000)), opType);
    1486           0 :         else if (!SupportsUint16x8Compares && opType == MIRType::Int16x8)
    1487           0 :             bias = MSimdConstant::New(alloc, SimdConstant::SplatX8(int16_t(0x8000)), opType);
    1488           0 :         if (!SupportsUint8x16Compares && opType == MIRType::Int8x16)
    1489           0 :             bias = MSimdConstant::New(alloc, SimdConstant::SplatX16(int8_t(0x80)), opType);
    1490             : 
    1491           0 :         if (bias) {
    1492           0 :             addTo->add(bias);
    1493             : 
    1494             :             // Add the bias.
    1495             :             MInstruction* bleft =
    1496           0 :               MSimdBinaryArith::AddLegalized(alloc, addTo, left, bias, MSimdBinaryArith::Op_add);
    1497             :             MInstruction* bright =
    1498           0 :               MSimdBinaryArith::AddLegalized(alloc, addTo, right, bias, MSimdBinaryArith::Op_add);
    1499             : 
    1500             :             // Do the equivalent signed comparison.
    1501             :             MInstruction* result =
    1502           0 :               MSimdBinaryComp::New(alloc, bleft, bright, op, SimdSign::Signed);
    1503           0 :             addTo->add(result);
    1504             : 
    1505           0 :             return result;
    1506             :         }
    1507             :     }
    1508             : 
    1509           0 :     if (sign == SimdSign::Unsigned &&
    1510           0 :         ((!SupportsUint32x4Compares && opType == MIRType::Int32x4) ||
    1511           0 :          (!SupportsUint16x8Compares && opType == MIRType::Int16x8) ||
    1512           0 :          (!SupportsUint8x16Compares && opType == MIRType::Int8x16))) {
    1513             :         // The sign doesn't matter for equality tests. Flip it to make the
    1514             :         // backend assertions happy.
    1515           0 :         MOZ_ASSERT(IsEquality);
    1516           0 :         sign = SimdSign::Signed;
    1517             :     }
    1518             : 
    1519             :     // This is a legal operation already. Just create the instruction requested.
    1520           0 :     MInstruction* result = MSimdBinaryComp::New(alloc, left, right, op, sign);
    1521           0 :     addTo->add(result);
    1522           0 :     return result;
    1523             : }
    1524             : 
    1525             : MInstruction*
    1526           0 : MSimdBinaryArith::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
    1527             :                                MDefinition* right, Operation op)
    1528             : {
    1529           0 :     MOZ_ASSERT(left->type() == right->type());
    1530           0 :     MIRType opType = left->type();
    1531           0 :     MOZ_ASSERT(IsSimdType(opType));
    1532             : 
    1533             :     // SSE does not have 8x16 multiply instructions.
    1534           0 :     if (opType == MIRType::Int8x16 && op == Op_mul) {
    1535             :         // Express the multiply in terms of Int16x8 multiplies by handling the
    1536             :         // even and odd lanes separately.
    1537             : 
    1538           0 :         MInstruction* wideL = MSimdReinterpretCast::New(alloc, left, MIRType::Int16x8);
    1539           0 :         addTo->add(wideL);
    1540           0 :         MInstruction* wideR = MSimdReinterpretCast::New(alloc, right, MIRType::Int16x8);
    1541           0 :         addTo->add(wideR);
    1542             : 
    1543             :         // wideL = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx
    1544             :         // wideR = bbaa bbaa bbaa bbaa bbaa bbaa bbaa bbaa
    1545             : 
    1546             :         // Shift the odd lanes down to the low bits of the 16x8 vectors.
    1547           0 :         MInstruction* eight = MConstant::New(alloc, Int32Value(8));
    1548           0 :         addTo->add(eight);
    1549           0 :         MInstruction* evenL = wideL;
    1550           0 :         MInstruction* evenR = wideR;
    1551             :         MInstruction* oddL =
    1552           0 :           MSimdShift::AddLegalized(alloc, addTo, wideL, eight, MSimdShift::ursh);
    1553             :         MInstruction* oddR =
    1554           0 :           MSimdShift::AddLegalized(alloc, addTo, wideR, eight, MSimdShift::ursh);
    1555             : 
    1556             :         // evenL = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx
    1557             :         // evenR = bbaa bbaa bbaa bbaa bbaa bbaa bbaa bbaa
    1558             :         // oddL  = 00yy 00yy 00yy 00yy 00yy 00yy 00yy 00yy
    1559             :         // oddR  = 00bb 00bb 00bb 00bb 00bb 00bb 00bb 00bb
    1560             : 
    1561             :         // Now do two 16x8 multiplications. We can use the low bits of each.
    1562           0 :         MInstruction* even = MSimdBinaryArith::AddLegalized(alloc, addTo, evenL, evenR, Op_mul);
    1563           0 :         MInstruction* odd = MSimdBinaryArith::AddLegalized(alloc, addTo, oddL, oddR, Op_mul);
    1564             : 
    1565             :         // even = ~~PP ~~PP ~~PP ~~PP ~~PP ~~PP ~~PP ~~PP
    1566             :         // odd  = ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ ~~QQ
    1567             : 
    1568             :         MInstruction* mask =
    1569           0 :           MSimdConstant::New(alloc, SimdConstant::SplatX8(int16_t(0x00ff)), MIRType::Int16x8);
    1570           0 :         addTo->add(mask);
    1571           0 :         even = MSimdBinaryBitwise::New(alloc, even, mask, MSimdBinaryBitwise::and_);
    1572           0 :         addTo->add(even);
    1573           0 :         odd = MSimdShift::AddLegalized(alloc, addTo, odd, eight, MSimdShift::lsh);
    1574             : 
    1575             :         // even = 00PP 00PP 00PP 00PP 00PP 00PP 00PP 00PP
    1576             :         // odd  = QQ00 QQ00 QQ00 QQ00 QQ00 QQ00 QQ00 QQ00
    1577             : 
    1578             :         // Combine:
    1579           0 :         MInstruction* result = MSimdBinaryBitwise::New(alloc, even, odd, MSimdBinaryBitwise::or_);
    1580           0 :         addTo->add(result);
    1581           0 :         result = MSimdReinterpretCast::New(alloc, result, opType);
    1582           0 :         addTo->add(result);
    1583           0 :         return result;
    1584             :     }
    1585             : 
    1586             :     // This is a legal operation already. Just create the instruction requested.
    1587           0 :     MInstruction* result = MSimdBinaryArith::New(alloc, left, right, op);
    1588           0 :     addTo->add(result);
    1589           0 :     return result;
    1590             : }
    1591             : 
    1592             : MInstruction*
    1593           0 : MSimdShift::AddLegalized(TempAllocator& alloc, MBasicBlock* addTo, MDefinition* left,
    1594             :                          MDefinition* right, Operation op)
    1595             : {
    1596           0 :     MIRType opType = left->type();
    1597           0 :     MOZ_ASSERT(IsIntegerSimdType(opType));
    1598             : 
    1599             :     // SSE does not provide 8x16 shift instructions.
    1600           0 :     if (opType == MIRType::Int8x16) {
    1601             :         // Express the shift in terms of Int16x8 shifts by splitting into even
    1602             :         // and odd lanes, place 8-bit lanes into the high bits of Int16x8
    1603             :         // vectors `even` and `odd`. Shift, mask, combine.
    1604             :         //
    1605             :         //   wide = Int16x8.fromInt8x16Bits(left);
    1606             :         //   shiftBy = right & 7
    1607             :         //   mask = Int16x8.splat(0xff00);
    1608             :         //
    1609           0 :         MInstruction* wide = MSimdReinterpretCast::New(alloc, left, MIRType::Int16x8);
    1610           0 :         addTo->add(wide);
    1611             : 
    1612             :         // wide = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx
    1613             : 
    1614           0 :         MInstruction* shiftMask = MConstant::New(alloc, Int32Value(7));
    1615           0 :         addTo->add(shiftMask);
    1616           0 :         MBinaryBitwiseInstruction* shiftBy = MBitAnd::New(alloc, right, shiftMask);
    1617           0 :         shiftBy->setInt32Specialization();
    1618           0 :         addTo->add(shiftBy);
    1619             : 
    1620             :         // Move the even 8x16 lanes into the high bits of the 16x8 lanes.
    1621           0 :         MInstruction* eight = MConstant::New(alloc, Int32Value(8));
    1622           0 :         addTo->add(eight);
    1623           0 :         MInstruction* even = MSimdShift::AddLegalized(alloc, addTo, wide, eight, lsh);
    1624             : 
    1625             :         // Leave the odd lanes in place.
    1626           0 :         MInstruction* odd = wide;
    1627             : 
    1628             :         // even = xx00 xx00 xx00 xx00 xx00 xx00 xx00 xx00
    1629             :         // odd  = yyxx yyxx yyxx yyxx yyxx yyxx yyxx yyxx
    1630             : 
    1631             :         MInstruction* mask =
    1632           0 :           MSimdConstant::New(alloc, SimdConstant::SplatX8(int16_t(0xff00)), MIRType::Int16x8);
    1633           0 :         addTo->add(mask);
    1634             : 
    1635             :         // Left-shift: Clear the low bits in `odd` before shifting.
    1636           0 :         if (op == lsh) {
    1637           0 :             odd = MSimdBinaryBitwise::New(alloc, odd, mask, MSimdBinaryBitwise::and_);
    1638           0 :             addTo->add(odd);
    1639             :             // odd  = yy00 yy00 yy00 yy00 yy00 yy00 yy00 yy00
    1640             :         }
    1641             : 
    1642             :         // Do the real shift twice: once for the even lanes, once for the odd
    1643             :         // lanes. This is a recursive call, but with a different type.
    1644           0 :         even = MSimdShift::AddLegalized(alloc, addTo, even, shiftBy, op);
    1645           0 :         odd = MSimdShift::AddLegalized(alloc, addTo, odd, shiftBy, op);
    1646             : 
    1647             :         // even = XX~~ XX~~ XX~~ XX~~ XX~~ XX~~ XX~~ XX~~
    1648             :         // odd  = YY~~ YY~~ YY~~ YY~~ YY~~ YY~~ YY~~ YY~~
    1649             : 
    1650             :         // Right-shift: Clear the low bits in `odd` after shifting.
    1651           0 :         if (op != lsh) {
    1652           0 :             odd = MSimdBinaryBitwise::New(alloc, odd, mask, MSimdBinaryBitwise::and_);
    1653           0 :             addTo->add(odd);
    1654             :             // odd  = YY00 YY00 YY00 YY00 YY00 YY00 YY00 YY00
    1655             :         }
    1656             : 
    1657             :         // Move the even lanes back to their original place.
    1658           0 :         even = MSimdShift::AddLegalized(alloc, addTo, even, eight, ursh);
    1659             : 
    1660             :         // Now, `odd` contains the odd lanes properly shifted, and `even`
    1661             :         // contains the even lanes properly shifted:
    1662             :         //
    1663             :         // even = 00XX 00XX 00XX 00XX 00XX 00XX 00XX 00XX
    1664             :         // odd  = YY00 YY00 YY00 YY00 YY00 YY00 YY00 YY00
    1665             :         //
    1666             :         // Combine:
    1667           0 :         MInstruction* result = MSimdBinaryBitwise::New(alloc, even, odd, MSimdBinaryBitwise::or_);
    1668           0 :         addTo->add(result);
    1669           0 :         result = MSimdReinterpretCast::New(alloc, result, opType);
    1670           0 :         addTo->add(result);
    1671           0 :         return result;
    1672             :     }
    1673             : 
    1674             :     // This is a legal operation already. Just create the instruction requested.
    1675           0 :     MInstruction* result = MSimdShift::New(alloc, left, right, op);
    1676           0 :     addTo->add(result);
    1677           0 :     return result;
    1678             : }
    1679             : 
    1680             : template <typename T>
    1681             : static void
    1682           0 : PrintOpcodeOperation(T* mir, GenericPrinter& out)
    1683             : {
    1684           0 :     mir->MDefinition::printOpcode(out);
    1685           0 :     out.printf(" (%s)", T::OperationName(mir->operation()));
    1686           0 : }
    1687             : 
    1688             : void
    1689           0 : MSimdBinaryArith::printOpcode(GenericPrinter& out) const
    1690             : {
    1691           0 :     PrintOpcodeOperation(this, out);
    1692           0 : }
    1693             : void
    1694           0 : MSimdBinarySaturating::printOpcode(GenericPrinter& out) const
    1695             : {
    1696           0 :     PrintOpcodeOperation(this, out);
    1697           0 : }
    1698             : void
    1699           0 : MSimdBinaryBitwise::printOpcode(GenericPrinter& out) const
    1700             : {
    1701           0 :     PrintOpcodeOperation(this, out);
    1702           0 : }
    1703             : void
    1704           0 : MSimdUnaryArith::printOpcode(GenericPrinter& out) const
    1705             : {
    1706           0 :     PrintOpcodeOperation(this, out);
    1707           0 : }
    1708             : void
    1709           0 : MSimdBinaryComp::printOpcode(GenericPrinter& out) const
    1710             : {
    1711           0 :     PrintOpcodeOperation(this, out);
    1712           0 : }
    1713             : void
    1714           0 : MSimdShift::printOpcode(GenericPrinter& out) const
    1715             : {
    1716           0 :     PrintOpcodeOperation(this, out);
    1717           0 : }
    1718             : 
    1719             : void
    1720           0 : MSimdInsertElement::printOpcode(GenericPrinter& out) const
    1721             : {
    1722           0 :     MDefinition::printOpcode(out);
    1723           0 :     out.printf(" (lane %u)", lane());
    1724           0 : }
    1725             : 
    1726             : void
    1727           0 : MSimdBox::printOpcode(GenericPrinter& out) const
    1728             : {
    1729           0 :     MDefinition::printOpcode(out);
    1730           0 :     out.printf(" (%s%s)", SimdTypeToString(simdType()),
    1731           0 :                initialHeap() == gc::TenuredHeap ? ", tenured" : "");
    1732           0 : }
    1733             : 
    1734             : void
    1735           0 : MSimdUnbox::printOpcode(GenericPrinter& out) const
    1736             : {
    1737           0 :     MDefinition::printOpcode(out);
    1738           0 :     out.printf(" (%s)", SimdTypeToString(simdType()));
    1739           0 : }
    1740             : 
    1741             : void
    1742           0 : MControlInstruction::printOpcode(GenericPrinter& out) const
    1743             : {
    1744           0 :     MDefinition::printOpcode(out);
    1745           0 :     for (size_t j = 0; j < numSuccessors(); j++) {
    1746           0 :         if (getSuccessor(j))
    1747           0 :             out.printf(" block%u", getSuccessor(j)->id());
    1748             :         else
    1749           0 :             out.printf(" (null-to-be-patched)");
    1750             :     }
    1751           0 : }
    1752             : 
    1753             : void
    1754           0 : MCompare::printOpcode(GenericPrinter& out) const
    1755             : {
    1756           0 :     MDefinition::printOpcode(out);
    1757           0 :     out.printf(" %s", CodeName[jsop()]);
    1758           0 : }
    1759             : 
    1760             : void
    1761           0 : MConstantElements::printOpcode(GenericPrinter& out) const
    1762             : {
    1763           0 :     PrintOpcodeName(out, op());
    1764           0 :     out.printf(" 0x%" PRIxPTR, value().asValue());
    1765           0 : }
    1766             : 
    1767             : void
    1768           0 : MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const
    1769             : {
    1770           0 :     MDefinition::printOpcode(out);
    1771           0 :     out.printf(" %s", ScalarTypeDescr::typeName(storageType()));
    1772           0 : }
    1773             : 
    1774             : void
    1775           0 : MAssertRange::printOpcode(GenericPrinter& out) const
    1776             : {
    1777           0 :     MDefinition::printOpcode(out);
    1778           0 :     out.put(" ");
    1779           0 :     assertedRange()->dump(out);
    1780           0 : }
    1781             : 
    1782           0 : void MNearbyInt::printOpcode(GenericPrinter& out) const
    1783             : {
    1784           0 :     MDefinition::printOpcode(out);
    1785           0 :     const char* roundingModeStr = nullptr;
    1786           0 :     switch (roundingMode_) {
    1787           0 :       case RoundingMode::Up:                roundingModeStr = "(up)"; break;
    1788           0 :       case RoundingMode::Down:              roundingModeStr = "(down)"; break;
    1789           0 :       case RoundingMode::NearestTiesToEven: roundingModeStr = "(nearest ties even)"; break;
    1790           0 :       case RoundingMode::TowardsZero:       roundingModeStr = "(towards zero)"; break;
    1791             :     }
    1792           0 :     out.printf(" %s", roundingModeStr);
    1793           0 : }
    1794             : 
    1795             : const char*
    1796           0 : MMathFunction::FunctionName(Function function)
    1797             : {
    1798           0 :     switch (function) {
    1799           0 :       case Log:    return "Log";
    1800           0 :       case Sin:    return "Sin";
    1801           0 :       case Cos:    return "Cos";
    1802           0 :       case Exp:    return "Exp";
    1803           0 :       case Tan:    return "Tan";
    1804           0 :       case ACos:   return "ACos";
    1805           0 :       case ASin:   return "ASin";
    1806           0 :       case ATan:   return "ATan";
    1807           0 :       case Log10:  return "Log10";
    1808           0 :       case Log2:   return "Log2";
    1809           0 :       case Log1P:  return "Log1P";
    1810           0 :       case ExpM1:  return "ExpM1";
    1811           0 :       case CosH:   return "CosH";
    1812           0 :       case SinH:   return "SinH";
    1813           0 :       case TanH:   return "TanH";
    1814           0 :       case ACosH:  return "ACosH";
    1815           0 :       case ASinH:  return "ASinH";
    1816           0 :       case ATanH:  return "ATanH";
    1817           0 :       case Sign:   return "Sign";
    1818           0 :       case Trunc:  return "Trunc";
    1819           0 :       case Cbrt:   return "Cbrt";
    1820           0 :       case Floor:  return "Floor";
    1821           0 :       case Ceil:   return "Ceil";
    1822           0 :       case Round:  return "Round";
    1823             :       default:
    1824           0 :         MOZ_CRASH("Unknown math function");
    1825             :     }
    1826             : }
    1827             : 
    1828             : void
    1829           0 : MMathFunction::printOpcode(GenericPrinter& out) const
    1830             : {
    1831           0 :     MDefinition::printOpcode(out);
    1832           0 :     out.printf(" %s", FunctionName(function()));
    1833           0 : }
    1834             : 
    1835             : MDefinition*
    1836           0 : MMathFunction::foldsTo(TempAllocator& alloc)
    1837             : {
    1838           0 :     MDefinition* input = getOperand(0);
    1839           0 :     if (!input->isConstant() || !input->toConstant()->isTypeRepresentableAsDouble())
    1840           0 :         return this;
    1841             : 
    1842           0 :     double in = input->toConstant()->numberToDouble();
    1843             :     double out;
    1844           0 :     switch (function_) {
    1845             :       case Log:
    1846           0 :         out = js::math_log_uncached(in);
    1847           0 :         break;
    1848             :       case Sin:
    1849           0 :         out = js::math_sin_uncached(in);
    1850           0 :         break;
    1851             :       case Cos:
    1852           0 :         out = js::math_cos_uncached(in);
    1853           0 :         break;
    1854             :       case Exp:
    1855           0 :         out = js::math_exp_uncached(in);
    1856           0 :         break;
    1857             :       case Tan:
    1858           0 :         out = js::math_tan_uncached(in);
    1859           0 :         break;
    1860             :       case ACos:
    1861           0 :         out = js::math_acos_uncached(in);
    1862           0 :         break;
    1863             :       case ASin:
    1864           0 :         out = js::math_asin_uncached(in);
    1865           0 :         break;
    1866             :       case ATan:
    1867           0 :         out = js::math_atan_uncached(in);
    1868           0 :         break;
    1869             :       case Log10:
    1870           0 :         out = js::math_log10_uncached(in);
    1871           0 :         break;
    1872             :       case Log2:
    1873           0 :         out = js::math_log2_uncached(in);
    1874           0 :         break;
    1875             :       case Log1P:
    1876           0 :         out = js::math_log1p_uncached(in);
    1877           0 :         break;
    1878             :       case ExpM1:
    1879           0 :         out = js::math_expm1_uncached(in);
    1880           0 :         break;
    1881             :       case CosH:
    1882           0 :         out = js::math_cosh_uncached(in);
    1883           0 :         break;
    1884             :       case SinH:
    1885           0 :         out = js::math_sinh_uncached(in);
    1886           0 :         break;
    1887             :       case TanH:
    1888           0 :         out = js::math_tanh_uncached(in);
    1889           0 :         break;
    1890             :       case ACosH:
    1891           0 :         out = js::math_acosh_uncached(in);
    1892           0 :         break;
    1893             :       case ASinH:
    1894           0 :         out = js::math_asinh_uncached(in);
    1895           0 :         break;
    1896             :       case ATanH:
    1897           0 :         out = js::math_atanh_uncached(in);
    1898           0 :         break;
    1899             :       case Sign:
    1900           0 :         out = js::math_sign_uncached(in);
    1901           0 :         break;
    1902             :       case Trunc:
    1903           0 :         out = js::math_trunc_uncached(in);
    1904           0 :         break;
    1905             :       case Cbrt:
    1906           0 :         out = js::math_cbrt_uncached(in);
    1907           0 :         break;
    1908             :       case Floor:
    1909           0 :         out = js::math_floor_impl(in);
    1910           0 :         break;
    1911             :       case Ceil:
    1912           0 :         out = js::math_ceil_impl(in);
    1913           0 :         break;
    1914             :       case Round:
    1915           0 :         out = js::math_round_impl(in);
    1916           0 :         break;
    1917             :       default:
    1918           0 :         return this;
    1919             :     }
    1920             : 
    1921           0 :     if (input->type() == MIRType::Float32)
    1922           0 :         return MConstant::NewFloat32(alloc, out);
    1923           0 :     return MConstant::New(alloc, DoubleValue(out));
    1924             : }
    1925             : 
    1926             : MDefinition*
    1927           0 : MAtomicIsLockFree::foldsTo(TempAllocator& alloc)
    1928             : {
    1929           0 :     MDefinition* input = getOperand(0);
    1930           0 :     if (!input->isConstant() || input->type() != MIRType::Int32)
    1931           0 :         return this;
    1932             : 
    1933           0 :     int32_t i = input->toConstant()->toInt32();
    1934           0 :     return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfree(i)));
    1935             : }
    1936             : 
    1937             : // Define |THIS_SLOT| as part of this translation unit, as it is used to
    1938             : // specialized the parameterized |New| function calls introduced by
    1939             : // TRIVIAL_NEW_WRAPPERS.
    1940             : const int32_t MParameter::THIS_SLOT;
    1941             : 
    1942             : void
    1943           0 : MParameter::printOpcode(GenericPrinter& out) const
    1944             : {
    1945           0 :     PrintOpcodeName(out, op());
    1946           0 :     if (index() == THIS_SLOT)
    1947           0 :         out.printf(" THIS_SLOT");
    1948             :     else
    1949           0 :         out.printf(" %d", index());
    1950           0 : }
    1951             : 
    1952             : HashNumber
    1953           6 : MParameter::valueHash() const
    1954             : {
    1955           6 :     HashNumber hash = MDefinition::valueHash();
    1956           6 :     hash = addU32ToHash(hash, index_);
    1957           6 :     return hash;
    1958             : }
    1959             : 
    1960             : bool
    1961           0 : MParameter::congruentTo(const MDefinition* ins) const
    1962             : {
    1963           0 :     if (!ins->isParameter())
    1964           0 :         return false;
    1965             : 
    1966           0 :     return ins->toParameter()->index() == index_;
    1967             : }
    1968             : 
    1969         263 : WrappedFunction::WrappedFunction(JSFunction* fun)
    1970             :   : fun_(fun),
    1971         263 :     nargs_(fun->nargs()),
    1972         263 :     isNative_(fun->isNative()),
    1973         263 :     isConstructor_(fun->isConstructor()),
    1974         263 :     isClassConstructor_(fun->isClassConstructor()),
    1975        1315 :     isSelfHostedBuiltin_(fun->isSelfHostedBuiltin())
    1976         263 : {}
    1977             : 
    1978             : MCall*
    1979        1145 : MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
    1980             :            bool construct, bool ignoresReturnValue, bool isDOMCall)
    1981             : {
    1982        1145 :     WrappedFunction* wrappedTarget = target ? new(alloc) WrappedFunction(target) : nullptr;
    1983        1145 :     MOZ_ASSERT(maxArgc >= numActualArgs);
    1984             :     MCall* ins;
    1985        1145 :     if (isDOMCall) {
    1986           0 :         MOZ_ASSERT(!construct);
    1987           0 :         ins = new(alloc) MCallDOMNative(wrappedTarget, numActualArgs);
    1988             :     } else {
    1989        1145 :         ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct, ignoresReturnValue);
    1990             :     }
    1991        1145 :     if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
    1992           0 :         return nullptr;
    1993        1145 :     return ins;
    1994             : }
    1995             : 
    1996             : AliasSet
    1997           0 : MCallDOMNative::getAliasSet() const
    1998             : {
    1999           0 :     const JSJitInfo* jitInfo = getJitInfo();
    2000             : 
    2001             :     // If we don't know anything about the types of our arguments, we have to
    2002             :     // assume that type-coercions can have side-effects, so we need to alias
    2003             :     // everything.
    2004           0 :     if (jitInfo->aliasSet() == JSJitInfo::AliasEverything || !jitInfo->isTypedMethodJitInfo())
    2005           0 :         return AliasSet::Store(AliasSet::Any);
    2006             : 
    2007           0 :     uint32_t argIndex = 0;
    2008             :     const JSTypedMethodJitInfo* methodInfo =
    2009           0 :         reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
    2010           0 :     for (const JSJitInfo::ArgType* argType = methodInfo->argTypes;
    2011           0 :          *argType != JSJitInfo::ArgTypeListEnd;
    2012             :          ++argType, ++argIndex)
    2013             :     {
    2014           0 :         if (argIndex >= numActualArgs()) {
    2015             :             // Passing through undefined can't have side-effects
    2016           0 :             continue;
    2017             :         }
    2018             :         // getArg(0) is "this", so skip it
    2019           0 :         MDefinition* arg = getArg(argIndex+1);
    2020           0 :         MIRType actualType = arg->type();
    2021             :         // The only way to reliably avoid side-effects given the information we
    2022             :         // have here is if we're passing in a known primitive value to an
    2023             :         // argument that expects a primitive value.
    2024             :         //
    2025             :         // XXXbz maybe we need to communicate better information.  For example,
    2026             :         // a sequence argument will sort of unavoidably have side effects, while
    2027             :         // a typed array argument won't have any, but both are claimed to be
    2028             :         // JSJitInfo::Object.  But if we do that, we need to watch out for our
    2029             :         // movability/DCE-ability bits: if we have an arg type that can reliably
    2030             :         // throw an exception on conversion, that might not affect our alias set
    2031             :         // per se, but it should prevent us being moved or DCE-ed, unless we
    2032             :         // know the incoming things match that arg type and won't throw.
    2033             :         //
    2034           0 :         if ((actualType == MIRType::Value || actualType == MIRType::Object) ||
    2035           0 :             (*argType & JSJitInfo::Object))
    2036             :          {
    2037           0 :              return AliasSet::Store(AliasSet::Any);
    2038             :          }
    2039             :     }
    2040             : 
    2041             :     // We checked all the args, and they check out.  So we only alias DOM
    2042             :     // mutations or alias nothing, depending on the alias set in the jitinfo.
    2043           0 :     if (jitInfo->aliasSet() == JSJitInfo::AliasNone)
    2044           0 :         return AliasSet::None();
    2045             : 
    2046           0 :     MOZ_ASSERT(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets);
    2047           0 :     return AliasSet::Load(AliasSet::DOMProperty);
    2048             : }
    2049             : 
    2050             : void
    2051           0 : MCallDOMNative::computeMovable()
    2052             : {
    2053             :     // We are movable if the jitinfo says we can be and if we're also not
    2054             :     // effectful.  The jitinfo can't check for the latter, since it depends on
    2055             :     // the types of our arguments.
    2056           0 :     const JSJitInfo* jitInfo = getJitInfo();
    2057             : 
    2058           0 :     MOZ_ASSERT_IF(jitInfo->isMovable,
    2059             :                   jitInfo->aliasSet() != JSJitInfo::AliasEverything);
    2060             : 
    2061           0 :     if (jitInfo->isMovable && !isEffectful())
    2062           0 :         setMovable();
    2063           0 : }
    2064             : 
    2065             : bool
    2066           0 : MCallDOMNative::congruentTo(const MDefinition* ins) const
    2067             : {
    2068           0 :     if (!isMovable())
    2069           0 :         return false;
    2070             : 
    2071           0 :     if (!ins->isCall())
    2072           0 :         return false;
    2073             : 
    2074           0 :     const MCall* call = ins->toCall();
    2075             : 
    2076           0 :     if (!call->isCallDOMNative())
    2077           0 :         return false;
    2078             : 
    2079           0 :     if (getSingleTarget() != call->getSingleTarget())
    2080           0 :         return false;
    2081             : 
    2082           0 :     if (isConstructing() != call->isConstructing())
    2083           0 :         return false;
    2084             : 
    2085           0 :     if (numActualArgs() != call->numActualArgs())
    2086           0 :         return false;
    2087             : 
    2088           0 :     if (needsArgCheck() != call->needsArgCheck())
    2089           0 :         return false;
    2090             : 
    2091           0 :     if (!congruentIfOperandsEqual(call))
    2092           0 :         return false;
    2093             : 
    2094             :     // The other call had better be movable at this point!
    2095           0 :     MOZ_ASSERT(call->isMovable());
    2096             : 
    2097           0 :     return true;
    2098             : }
    2099             : 
    2100             : const JSJitInfo*
    2101           0 : MCallDOMNative::getJitInfo() const
    2102             : {
    2103           0 :     MOZ_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
    2104             : 
    2105           0 :     const JSJitInfo* jitInfo = getSingleTarget()->jitInfo();
    2106           0 :     MOZ_ASSERT(jitInfo);
    2107             : 
    2108           0 :     return jitInfo;
    2109             : }
    2110             : 
    2111             : MDefinition*
    2112          20 : MStringLength::foldsTo(TempAllocator& alloc)
    2113             : {
    2114          20 :     if (type() == MIRType::Int32 && string()->isConstant()) {
    2115           0 :         JSAtom* atom = &string()->toConstant()->toString()->asAtom();
    2116           0 :         return MConstant::New(alloc, Int32Value(atom->length()));
    2117             :     }
    2118             : 
    2119          20 :     return this;
    2120             : }
    2121             : 
    2122             : MDefinition*
    2123          24 : MConcat::foldsTo(TempAllocator& alloc)
    2124             : {
    2125          24 :     if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty())
    2126           0 :         return rhs();
    2127             : 
    2128          24 :     if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty())
    2129           0 :         return lhs();
    2130             : 
    2131          24 :     return this;
    2132             : }
    2133             : 
    2134             : static bool
    2135           0 : EnsureFloatInputOrConvert(MUnaryInstruction* owner, TempAllocator& alloc)
    2136             : {
    2137           0 :     MDefinition* input = owner->input();
    2138           0 :     if (!input->canProduceFloat32()) {
    2139           0 :         if (input->type() == MIRType::Float32)
    2140           0 :             ConvertDefinitionToDouble<0>(alloc, input, owner);
    2141           0 :         return false;
    2142             :     }
    2143           0 :     return true;
    2144             : }
    2145             : 
    2146             : void
    2147           0 : MFloor::trySpecializeFloat32(TempAllocator& alloc)
    2148             : {
    2149           0 :     MOZ_ASSERT(type() == MIRType::Int32);
    2150           0 :     if (EnsureFloatInputOrConvert(this, alloc))
    2151           0 :         specialization_ = MIRType::Float32;
    2152           0 : }
    2153             : 
    2154             : void
    2155           0 : MCeil::trySpecializeFloat32(TempAllocator& alloc)
    2156             : {
    2157           0 :     MOZ_ASSERT(type() == MIRType::Int32);
    2158           0 :     if (EnsureFloatInputOrConvert(this, alloc))
    2159           0 :         specialization_ = MIRType::Float32;
    2160           0 : }
    2161             : 
    2162             : void
    2163           0 : MRound::trySpecializeFloat32(TempAllocator& alloc)
    2164             : {
    2165           0 :     MOZ_ASSERT(type() == MIRType::Int32);
    2166           0 :     if (EnsureFloatInputOrConvert(this, alloc))
    2167           0 :         specialization_ = MIRType::Float32;
    2168           0 : }
    2169             : 
    2170             : void
    2171           0 : MNearbyInt::trySpecializeFloat32(TempAllocator& alloc)
    2172             : {
    2173           0 :     if (EnsureFloatInputOrConvert(this, alloc)) {
    2174           0 :         specialization_ = MIRType::Float32;
    2175           0 :         setResultType(MIRType::Float32);
    2176             :     }
    2177           0 : }
    2178             : 
    2179             : MTableSwitch*
    2180          44 : MTableSwitch::New(TempAllocator& alloc, MDefinition* ins, int32_t low, int32_t high)
    2181             : {
    2182          44 :     return new(alloc) MTableSwitch(alloc, ins, low, high);
    2183             : }
    2184             : 
    2185             : MGoto*
    2186        2531 : MGoto::New(TempAllocator& alloc, MBasicBlock* target)
    2187             : {
    2188        2531 :     MOZ_ASSERT(target);
    2189        2531 :     return new(alloc) MGoto(target);
    2190             : }
    2191             : 
    2192             : MGoto*
    2193           0 : MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target)
    2194             : {
    2195           0 :     MOZ_ASSERT(target);
    2196           0 :     return new(alloc) MGoto(target);
    2197             : }
    2198             : 
    2199             : MGoto*
    2200           0 : MGoto::New(TempAllocator& alloc)
    2201             : {
    2202           0 :     return new(alloc) MGoto(nullptr);
    2203             : }
    2204             : 
    2205             : void
    2206           0 : MUnbox::printOpcode(GenericPrinter& out) const
    2207             : {
    2208           0 :     PrintOpcodeName(out, op());
    2209           0 :     out.printf(" ");
    2210           0 :     getOperand(0)->printName(out);
    2211           0 :     out.printf(" ");
    2212             : 
    2213           0 :     switch (type()) {
    2214           0 :       case MIRType::Int32: out.printf("to Int32"); break;
    2215           0 :       case MIRType::Double: out.printf("to Double"); break;
    2216           0 :       case MIRType::Boolean: out.printf("to Boolean"); break;
    2217           0 :       case MIRType::String: out.printf("to String"); break;
    2218           0 :       case MIRType::Symbol: out.printf("to Symbol"); break;
    2219           0 :       case MIRType::Object: out.printf("to Object"); break;
    2220           0 :       default: break;
    2221             :     }
    2222             : 
    2223           0 :     switch (mode()) {
    2224           0 :       case Fallible: out.printf(" (fallible)"); break;
    2225           0 :       case Infallible: out.printf(" (infallible)"); break;
    2226           0 :       case TypeBarrier: out.printf(" (typebarrier)"); break;
    2227           0 :       default: break;
    2228             :     }
    2229           0 : }
    2230             : 
    2231             : MDefinition*
    2232         207 : MUnbox::foldsTo(TempAllocator &alloc)
    2233             : {
    2234         207 :     if (!input()->isLoadFixedSlot())
    2235         168 :         return this;
    2236          39 :     MLoadFixedSlot* load = input()->toLoadFixedSlot();
    2237          39 :     if (load->type() != MIRType::Value)
    2238           0 :         return this;
    2239          39 :     if (type() != MIRType::Boolean && !IsNumberType(type()))
    2240          38 :         return this;
    2241             :     // Only optimize if the load comes immediately before the unbox, so it's
    2242             :     // safe to copy the load's dependency field.
    2243           1 :     MInstructionIterator iter(load->block()->begin(load));
    2244           1 :     ++iter;
    2245           1 :     if (*iter != this)
    2246           0 :         return this;
    2247             : 
    2248           2 :     MLoadFixedSlotAndUnbox* ins = MLoadFixedSlotAndUnbox::New(alloc, load->object(), load->slot(),
    2249           3 :                                                               mode(), type(), bailoutKind());
    2250             :     // As GVN runs after the Alias Analysis, we have to set the dependency by hand
    2251           1 :     ins->setDependency(load->dependency());
    2252           1 :     return ins;
    2253             : }
    2254             : 
    2255             : void
    2256           0 : MTypeBarrier::printOpcode(GenericPrinter& out) const
    2257             : {
    2258           0 :     PrintOpcodeName(out, op());
    2259           0 :     out.printf(" ");
    2260           0 :     getOperand(0)->printName(out);
    2261           0 : }
    2262             : 
    2263             : bool
    2264         246 : MTypeBarrier::congruentTo(const MDefinition* def) const
    2265             : {
    2266         246 :     if (!def->isTypeBarrier())
    2267           0 :         return false;
    2268         246 :     const MTypeBarrier* other = def->toTypeBarrier();
    2269         246 :     if (barrierKind() != other->barrierKind() || isGuard() != other->isGuard())
    2270           8 :         return false;
    2271         238 :     if (!resultTypeSet()->equals(other->resultTypeSet()))
    2272           0 :         return false;
    2273         238 :     return congruentIfOperandsEqual(other);
    2274             : }
    2275             : 
    2276             : MDefinition*
    2277         234 : MTypeBarrier::foldsTo(TempAllocator& alloc)
    2278             : {
    2279         234 :     MIRType type = resultTypeSet()->getKnownMIRType();
    2280         234 :     if (type == MIRType::Value || type == MIRType::Object)
    2281         117 :         return this;
    2282             : 
    2283         117 :     if (!input()->isConstant())
    2284         113 :         return this;
    2285             : 
    2286           4 :     if (input()->type() != type)
    2287           0 :         return this;
    2288             : 
    2289           4 :     return input();
    2290             : }
    2291             : 
    2292             : #ifdef DEBUG
    2293             : void
    2294          46 : MPhi::assertLoopPhi() const
    2295             : {
    2296             :     // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these
    2297             :     // predecessors being at indices 0 and 1.
    2298          46 :     MBasicBlock* pred = block()->getPredecessor(0);
    2299          46 :     MBasicBlock* back = block()->getPredecessor(1);
    2300          46 :     MOZ_ASSERT(pred == block()->loopPredecessor());
    2301          46 :     MOZ_ASSERT(pred->successorWithPhis() == block());
    2302          46 :     MOZ_ASSERT(pred->positionInPhiSuccessor() == 0);
    2303          46 :     MOZ_ASSERT(back == block()->backedge());
    2304          46 :     MOZ_ASSERT(back->successorWithPhis() == block());
    2305          46 :     MOZ_ASSERT(back->positionInPhiSuccessor() == 1);
    2306          46 : }
    2307             : #endif
    2308             : 
    2309             : void
    2310         214 : MPhi::removeOperand(size_t index)
    2311             : {
    2312         214 :     MOZ_ASSERT(index < numOperands());
    2313         214 :     MOZ_ASSERT(getUseFor(index)->index() == index);
    2314         214 :     MOZ_ASSERT(getUseFor(index)->consumer() == this);
    2315             : 
    2316             :     // If we have phi(..., a, b, c, d, ..., z) and we plan
    2317             :     // on removing a, then first shift downward so that we have
    2318             :     // phi(..., b, c, d, ..., z, z):
    2319         214 :     MUse* p = inputs_.begin() + index;
    2320         214 :     MUse* e = inputs_.end();
    2321         214 :     p->producer()->removeUse(p);
    2322        1160 :     for (; p < e - 1; ++p) {
    2323         473 :         MDefinition* producer = (p + 1)->producer();
    2324         473 :         p->setProducerUnchecked(producer);
    2325         473 :         producer->replaceUse(p + 1, p);
    2326             :     }
    2327             : 
    2328             :     // truncate the inputs_ list:
    2329         214 :     inputs_.popBack();
    2330         214 : }
    2331             : 
    2332             : void
    2333        1991 : MPhi::removeAllOperands()
    2334             : {
    2335        5922 :     for (MUse& p : inputs_)
    2336        3931 :         p.producer()->removeUse(&p);
    2337        1991 :     inputs_.clear();
    2338        1991 : }
    2339             : 
    2340             : MDefinition*
    2341         338 : MPhi::foldsTernary(TempAllocator& alloc)
    2342             : {
    2343             :     /* Look if this MPhi is a ternary construct.
    2344             :      * This is a very loose term as it actually only checks for
    2345             :      *
    2346             :      *      MTest X
    2347             :      *       /  \
    2348             :      *    ...    ...
    2349             :      *       \  /
    2350             :      *     MPhi X Y
    2351             :      *
    2352             :      * Which we will simply call:
    2353             :      * x ? x : y or x ? y : x
    2354             :      */
    2355             : 
    2356         338 :     if (numOperands() != 2)
    2357          32 :         return nullptr;
    2358             : 
    2359         306 :     MOZ_ASSERT(block()->numPredecessors() == 2);
    2360             : 
    2361         306 :     MBasicBlock* pred = block()->immediateDominator();
    2362         306 :     if (!pred || !pred->lastIns()->isTest())
    2363         150 :         return nullptr;
    2364             : 
    2365         156 :     MTest* test = pred->lastIns()->toTest();
    2366             : 
    2367             :     // True branch may only dominate one edge of MPhi.
    2368         312 :     if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
    2369         156 :         test->ifTrue()->dominates(block()->getPredecessor(1)))
    2370             :     {
    2371           0 :         return nullptr;
    2372             :     }
    2373             : 
    2374             :     // False branch may only dominate one edge of MPhi.
    2375         312 :     if (test->ifFalse()->dominates(block()->getPredecessor(0)) ==
    2376         156 :         test->ifFalse()->dominates(block()->getPredecessor(1)))
    2377             :     {
    2378           0 :         return nullptr;
    2379             :     }
    2380             : 
    2381             :     // True and false branch must dominate different edges of MPhi.
    2382         312 :     if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
    2383         156 :         test->ifFalse()->dominates(block()->getPredecessor(0)))
    2384             :     {
    2385           0 :         return nullptr;
    2386             :     }
    2387             : 
    2388             :     // We found a ternary construct.
    2389         156 :     bool firstIsTrueBranch = test->ifTrue()->dominates(block()->getPredecessor(0));
    2390         156 :     MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1);
    2391         156 :     MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0);
    2392             : 
    2393             :     // Accept either
    2394             :     // testArg ? testArg : constant or
    2395             :     // testArg ? constant : testArg
    2396         156 :     if (!trueDef->isConstant() && !falseDef->isConstant())
    2397         112 :         return nullptr;
    2398             : 
    2399          44 :     MConstant* c = trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
    2400          44 :     MDefinition* testArg = (trueDef == c) ? falseDef : trueDef;
    2401          44 :     if (testArg != test->input())
    2402          36 :         return nullptr;
    2403             : 
    2404             :     // This check should be a tautology, except that the constant might be the
    2405             :     // result of the removal of a branch.  In such case the domination scope of
    2406             :     // the block which is holding the constant might be incomplete. This
    2407             :     // condition is used to prevent doing this optimization based on incomplete
    2408             :     // information.
    2409             :     //
    2410             :     // As GVN removed a branch, it will update the dominations rules before
    2411             :     // trying to fold this MPhi again. Thus, this condition does not inhibit
    2412             :     // this optimization.
    2413           8 :     MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
    2414           8 :     MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
    2415          16 :     if (!trueDef->block()->dominates(truePred) ||
    2416           8 :         !falseDef->block()->dominates(falsePred))
    2417             :     {
    2418           0 :         return nullptr;
    2419             :     }
    2420             : 
    2421             :     // If testArg is an int32 type we can:
    2422             :     // - fold testArg ? testArg : 0 to testArg
    2423             :     // - fold testArg ? 0 : testArg to 0
    2424           8 :     if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) {
    2425           0 :         testArg->setGuardRangeBailoutsUnchecked();
    2426             : 
    2427             :         // When folding to the constant we need to hoist it.
    2428           0 :         if (trueDef == c && !c->block()->dominates(block()))
    2429           0 :             c->block()->moveBefore(pred->lastIns(), c);
    2430           0 :         return trueDef;
    2431             :     }
    2432             : 
    2433             :     // If testArg is an double type we can:
    2434             :     // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg)
    2435           8 :     if (testArg->type() == MIRType::Double && mozilla::IsPositiveZero(c->numberToDouble()) &&
    2436             :         c != trueDef)
    2437             :     {
    2438           0 :         MNaNToZero* replace = MNaNToZero::New(alloc, testArg);
    2439           0 :         test->block()->insertBefore(test, replace);
    2440           0 :         return replace;
    2441             :     }
    2442             : 
    2443             :     // If testArg is a string type we can:
    2444             :     // - fold testArg ? testArg : "" to testArg
    2445             :     // - fold testArg ? "" : testArg to ""
    2446           8 :     if (testArg->type() == MIRType::String &&
    2447           0 :         c->toString() == GetJitContext()->runtime->emptyString())
    2448             :     {
    2449             :         // When folding to the constant we need to hoist it.
    2450           0 :         if (trueDef == c && !c->block()->dominates(block()))
    2451           0 :             c->block()->moveBefore(pred->lastIns(), c);
    2452           0 :         return trueDef;
    2453             :     }
    2454             : 
    2455           8 :     return nullptr;
    2456             : }
    2457             : 
    2458             : MDefinition*
    2459        3979 : MPhi::operandIfRedundant()
    2460             : {
    2461        3979 :     if (inputs_.length() == 0)
    2462           0 :         return nullptr;
    2463             : 
    2464             :     // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
    2465             :     // returns the operand that it will always be equal to (a, in
    2466             :     // those two cases).
    2467        3979 :     MDefinition* first = getOperand(0);
    2468        5648 :     for (size_t i = 1, e = numOperands(); i < e; i++) {
    2469        4081 :         MDefinition* op = getOperand(i);
    2470        4081 :         if (op != first && op != this)
    2471        2412 :             return nullptr;
    2472             :     }
    2473        1567 :     return first;
    2474             : }
    2475             : 
    2476             : MDefinition*
    2477         338 : MPhi::foldsFilterTypeSet()
    2478             : {
    2479             :     // Fold phi with as operands a combination of 'subject' and
    2480             :     // MFilterTypeSet(subject) to 'subject'.
    2481             : 
    2482         338 :     if (inputs_.length() == 0)
    2483           0 :         return nullptr;
    2484             : 
    2485         338 :     MDefinition* subject = getOperand(0);
    2486         338 :     if (subject->isFilterTypeSet())
    2487           4 :         subject = subject->toFilterTypeSet()->input();
    2488             : 
    2489             :     // Not same type, don't fold.
    2490         338 :     if (subject->type() != type())
    2491           0 :         return nullptr;
    2492             : 
    2493             :     // Phi is better typed (has typeset). Don't fold.
    2494         338 :     if (resultTypeSet() && !subject->resultTypeSet())
    2495          18 :         return nullptr;
    2496             : 
    2497             :     // Phi is better typed (according to typeset). Don't fold.
    2498         320 :     if (subject->resultTypeSet() && resultTypeSet()) {
    2499         263 :         if (!subject->resultTypeSet()->isSubset(resultTypeSet()))
    2500           4 :             return nullptr;
    2501             :     }
    2502             : 
    2503         364 :     for (size_t i = 1, e = numOperands(); i < e; i++) {
    2504         364 :         MDefinition* op = getOperand(i);
    2505         364 :         if (op == subject)
    2506          48 :             continue;
    2507         316 :         if (op->isFilterTypeSet() && op->toFilterTypeSet()->input() == subject)
    2508           0 :             continue;
    2509             : 
    2510         316 :         return nullptr;
    2511             :     }
    2512             : 
    2513           0 :     return subject;
    2514             : }
    2515             : 
    2516             : MDefinition*
    2517         365 : MPhi::foldsTo(TempAllocator& alloc)
    2518             : {
    2519         365 :     if (MDefinition* def = operandIfRedundant())
    2520          27 :         return def;
    2521             : 
    2522         338 :     if (MDefinition* def = foldsTernary(alloc))
    2523           0 :         return def;
    2524             : 
    2525         338 :     if (MDefinition* def = foldsFilterTypeSet())
    2526           0 :         return def;
    2527             : 
    2528         338 :     return this;
    2529             : }
    2530             : 
    2531             : bool
    2532         400 : MPhi::congruentTo(const MDefinition* ins) const
    2533             : {
    2534         400 :     if (!ins->isPhi())
    2535           0 :         return false;
    2536             : 
    2537             :     // Phis in different blocks may have different control conditions.
    2538             :     // For example, these phis:
    2539             :     //
    2540             :     //   if (p)
    2541             :     //     goto a
    2542             :     //   a:
    2543             :     //     t = phi(x, y)
    2544             :     //
    2545             :     //   if (q)
    2546             :     //     goto b
    2547             :     //   b:
    2548             :     //     s = phi(x, y)
    2549             :     //
    2550             :     // have identical operands, but they are not equvalent because t is
    2551             :     // effectively p?x:y and s is effectively q?x:y.
    2552             :     //
    2553             :     // For now, consider phis in different blocks incongruent.
    2554         400 :     if (ins->block() != block())
    2555           0 :         return false;
    2556             : 
    2557         400 :     return congruentIfOperandsEqual(ins);
    2558             : }
    2559             : 
    2560             : static inline TemporaryTypeSet*
    2561         432 : MakeMIRTypeSet(TempAllocator& alloc, MIRType type)
    2562             : {
    2563         432 :     MOZ_ASSERT(type != MIRType::Value);
    2564             :     TypeSet::Type ntype = type == MIRType::Object
    2565             :                           ? TypeSet::AnyObjectType()
    2566         432 :                           : TypeSet::PrimitiveType(ValueTypeFromMIRType(type));
    2567         432 :     return alloc.lifoAlloc()->new_<TemporaryTypeSet>(alloc.lifoAlloc(), ntype);
    2568             : }
    2569             : 
    2570             : bool
    2571        3108 : jit::MergeTypes(TempAllocator& alloc, MIRType* ptype, TemporaryTypeSet** ptypeSet,
    2572             :                 MIRType newType, TemporaryTypeSet* newTypeSet)
    2573             : {
    2574        3108 :     if (newTypeSet && newTypeSet->empty())
    2575         973 :         return true;
    2576        4270 :     LifoAlloc::AutoFallibleScope fallibleAllocator(alloc.lifoAlloc());
    2577        2135 :     if (newType != *ptype) {
    2578         343 :         if (IsTypeRepresentableAsDouble(newType) && IsTypeRepresentableAsDouble(*ptype)) {
    2579          24 :             *ptype = MIRType::Double;
    2580         319 :         } else if (*ptype != MIRType::Value) {
    2581         127 :             if (!*ptypeSet) {
    2582          63 :                 *ptypeSet = MakeMIRTypeSet(alloc, *ptype);
    2583          63 :                 if (!*ptypeSet)
    2584           0 :                     return false;
    2585             :             }
    2586         127 :             *ptype = MIRType::Value;
    2587         192 :         } else if (*ptypeSet && (*ptypeSet)->empty()) {
    2588         114 :             *ptype = newType;
    2589             :         }
    2590             :     }
    2591        2135 :     if (*ptypeSet) {
    2592        1046 :         if (!newTypeSet && newType != MIRType::Value) {
    2593         369 :             newTypeSet = MakeMIRTypeSet(alloc, newType);
    2594         369 :             if (!newTypeSet)
    2595           0 :                 return false;
    2596             :         }
    2597        1046 :         if (newTypeSet) {
    2598        1038 :             if (!newTypeSet->isSubset(*ptypeSet)) {
    2599         237 :                 *ptypeSet = TypeSet::unionSets(*ptypeSet, newTypeSet, alloc.lifoAlloc());
    2600         237 :                 if (!*ptypeSet)
    2601           0 :                     return false;
    2602             :             }
    2603             :         } else {
    2604           8 :             *ptypeSet = nullptr;
    2605             :         }
    2606             :     }
    2607        2135 :     return true;
    2608             : }
    2609             : 
    2610             : // Tests whether 'types' includes all possible values represented by
    2611             : // input/inputTypes.
    2612             : bool
    2613         120 : jit::TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes)
    2614             : {
    2615         120 :     if (!types)
    2616           7 :         return inputTypes && inputTypes->empty();
    2617             : 
    2618         113 :     switch (input) {
    2619             :       case MIRType::Undefined:
    2620             :       case MIRType::Null:
    2621             :       case MIRType::Boolean:
    2622             :       case MIRType::Int32:
    2623             :       case MIRType::Double:
    2624             :       case MIRType::Float32:
    2625             :       case MIRType::String:
    2626             :       case MIRType::Symbol:
    2627             :       case MIRType::MagicOptimizedArguments:
    2628          55 :         return types->hasType(TypeSet::PrimitiveType(ValueTypeFromMIRType(input)));
    2629             : 
    2630             :       case MIRType::Object:
    2631           7 :         return types->unknownObject() || (inputTypes && inputTypes->isSubset(types));
    2632             : 
    2633             :       case MIRType::Value:
    2634          51 :         return types->unknown() || (inputTypes && inputTypes->isSubset(types));
    2635             : 
    2636             :       default:
    2637           0 :         MOZ_CRASH("Bad input type");
    2638             :     }
    2639             : }
    2640             : 
    2641             : // Tests if two type combos (type/typeset) are equal.
    2642             : bool
    2643           0 : jit::EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
    2644             :                 MIRType type2, TemporaryTypeSet* typeset2)
    2645             : {
    2646             :     // Types should equal.
    2647           0 :     if (type1 != type2)
    2648           0 :         return false;
    2649             : 
    2650             :     // Both have equal type and no typeset.
    2651           0 :     if (!typeset1 && !typeset2)
    2652           0 :         return true;
    2653             : 
    2654             :     // If only one instructions has a typeset.
    2655             :     // Test if the typset contains the same information as the MIRType.
    2656           0 :     if (typeset1 && !typeset2)
    2657           0 :         return TypeSetIncludes(typeset1, type2, nullptr);
    2658           0 :     if (!typeset1 && typeset2)
    2659           0 :         return TypeSetIncludes(typeset2, type1, nullptr);
    2660             : 
    2661             :     // Typesets should equal.
    2662           0 :     return typeset1->equals(typeset2);
    2663             : }
    2664             : 
    2665             : // Tests whether input/inputTypes can always be stored to an unboxed
    2666             : // object/array property with the given unboxed type.
    2667             : bool
    2668           0 : jit::CanStoreUnboxedType(TempAllocator& alloc,
    2669             :                          JSValueType unboxedType, MIRType input, TypeSet* inputTypes)
    2670             : {
    2671           0 :     TemporaryTypeSet types;
    2672             : 
    2673           0 :     switch (unboxedType) {
    2674             :       case JSVAL_TYPE_BOOLEAN:
    2675             :       case JSVAL_TYPE_INT32:
    2676             :       case JSVAL_TYPE_DOUBLE:
    2677             :       case JSVAL_TYPE_STRING:
    2678           0 :         types.addType(TypeSet::PrimitiveType(unboxedType), alloc.lifoAlloc());
    2679           0 :         break;
    2680             : 
    2681             :       case JSVAL_TYPE_OBJECT:
    2682           0 :         types.addType(TypeSet::AnyObjectType(), alloc.lifoAlloc());
    2683           0 :         types.addType(TypeSet::NullType(), alloc.lifoAlloc());
    2684           0 :         break;
    2685             : 
    2686             :       default:
    2687           0 :         MOZ_CRASH("Bad unboxed type");
    2688             :     }
    2689             : 
    2690           0 :     return TypeSetIncludes(&types, input, inputTypes);
    2691             : }
    2692             : 
    2693             : static bool
    2694           0 : CanStoreUnboxedType(TempAllocator& alloc, JSValueType unboxedType, MDefinition* value)
    2695             : {
    2696           0 :     return CanStoreUnboxedType(alloc, unboxedType, value->type(), value->resultTypeSet());
    2697             : }
    2698             : 
    2699             : bool
    2700        2635 : MPhi::specializeType(TempAllocator& alloc)
    2701             : {
    2702             : #ifdef DEBUG
    2703        2635 :     MOZ_ASSERT(!specialized_);
    2704        2635 :     specialized_ = true;
    2705             : #endif
    2706             : 
    2707        2635 :     MOZ_ASSERT(!inputs_.empty());
    2708             : 
    2709             :     size_t start;
    2710        2635 :     if (hasBackedgeType_) {
    2711             :         // The type of this phi has already been populated with potential types
    2712             :         // that could come in via loop backedges.
    2713          86 :         start = 0;
    2714             :     } else {
    2715        2549 :         setResultType(getOperand(0)->type());
    2716        2549 :         setResultTypeSet(getOperand(0)->resultTypeSet());
    2717        2549 :         start = 1;
    2718             :     }
    2719             : 
    2720        2635 :     MIRType resultType = this->type();
    2721        2635 :     TemporaryTypeSet* resultTypeSet = this->resultTypeSet();
    2722             : 
    2723        4115 :     for (size_t i = start; i < inputs_.length(); i++) {
    2724        1480 :         MDefinition* def = getOperand(i);
    2725        1480 :         if (!MergeTypes(alloc, &resultType, &resultTypeSet, def->type(), def->resultTypeSet()))
    2726           0 :             return false;
    2727             :     }
    2728             : 
    2729        2635 :     setResultType(resultType);
    2730        2635 :     setResultTypeSet(resultTypeSet);
    2731        2635 :     return true;
    2732             : }
    2733             : 
    2734             : bool
    2735         195 : MPhi::addBackedgeType(TempAllocator& alloc, MIRType type, TemporaryTypeSet* typeSet)
    2736             : {
    2737         195 :     MOZ_ASSERT(!specialized_);
    2738             : 
    2739         195 :     if (hasBackedgeType_) {
    2740         109 :         MIRType resultType = this->type();
    2741         109 :         TemporaryTypeSet* resultTypeSet = this->resultTypeSet();
    2742             : 
    2743         109 :         if (!MergeTypes(alloc, &resultType, &resultTypeSet, type, typeSet))
    2744           0 :             return false;
    2745             : 
    2746         109 :         setResultType(resultType);
    2747         109 :         setResultTypeSet(resultTypeSet);
    2748             :     } else {
    2749          86 :         setResultType(type);
    2750          86 :         setResultTypeSet(typeSet);
    2751          86 :         hasBackedgeType_ = true;
    2752             :     }
    2753         195 :     return true;
    2754             : }
    2755             : 
    2756             : bool
    2757           1 : MPhi::typeIncludes(MDefinition* def)
    2758             : {
    2759           1 :     if (def->type() == MIRType::Int32 && this->type() == MIRType::Double)
    2760           0 :         return true;
    2761             : 
    2762           1 :     if (TemporaryTypeSet* types = def->resultTypeSet()) {
    2763           1 :         if (this->resultTypeSet())
    2764           0 :             return types->isSubset(this->resultTypeSet());
    2765           1 :         if (this->type() == MIRType::Value || types->empty())
    2766           1 :             return true;
    2767           0 :         return this->type() == types->getKnownMIRType();
    2768             :     }
    2769             : 
    2770           0 :     if (def->type() == MIRType::Value) {
    2771             :         // This phi must be able to be any value.
    2772           0 :         return this->type() == MIRType::Value
    2773           0 :             && (!this->resultTypeSet() || this->resultTypeSet()->unknown());
    2774             :     }
    2775             : 
    2776           0 :     return this->mightBeType(def->type());
    2777             : }
    2778             : 
    2779             : bool
    2780        1519 : MPhi::checkForTypeChange(TempAllocator& alloc, MDefinition* ins, bool* ptypeChange)
    2781             : {
    2782        1519 :     MIRType resultType = this->type();
    2783        1519 :     TemporaryTypeSet* resultTypeSet = this->resultTypeSet();
    2784             : 
    2785        1519 :     if (!MergeTypes(alloc, &resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
    2786           0 :         return false;
    2787             : 
    2788        1519 :     if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
    2789           3 :         *ptypeChange = true;
    2790           3 :         setResultType(resultType);
    2791           3 :         setResultTypeSet(resultTypeSet);
    2792             :     }
    2793        1519 :     return true;
    2794             : }
    2795             : 
    2796             : void
    2797        3492 : MCall::addArg(size_t argnum, MDefinition* arg)
    2798             : {
    2799             :     // The operand vector is initialized in reverse order by the IonBuilder.
    2800             :     // It cannot be checked for consistency until all arguments are added.
    2801             :     // FixedList doesn't initialize its elements, so do an unchecked init.
    2802        3492 :     initOperand(argnum + NumNonArgumentOperands, arg);
    2803        3492 : }
    2804             : 
    2805             : static inline bool
    2806          24 : IsConstant(MDefinition* def, double v)
    2807             : {
    2808          24 :     if (!def->isConstant())
    2809          12 :         return false;
    2810             : 
    2811          12 :     return NumbersAreIdentical(def->toConstant()->numberToDouble(), v);
    2812             : }
    2813             : 
    2814             : MDefinition*
    2815           0 : MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc)
    2816             : {
    2817           0 :     if (specialization_ != MIRType::Int32)
    2818           0 :         return this;
    2819             : 
    2820           0 :     if (MDefinition* folded = EvaluateConstantOperands(alloc, this))
    2821           0 :         return folded;
    2822             : 
    2823           0 :     return this;
    2824             : }
    2825             : 
    2826             : MDefinition*
    2827           0 : MBinaryBitwiseInstruction::foldUnnecessaryBitop()
    2828             : {
    2829           0 :     if (specialization_ != MIRType::Int32)
    2830           0 :         return this;
    2831             : 
    2832             :     // Fold unsigned shift right operator when the second operand is zero and
    2833             :     // the only use is an unsigned modulo. Thus, the expression
    2834             :     // |(x >>> 0) % y| becomes |x % y|.
    2835           0 :     if (isUrsh() && hasOneDefUse() && IsUint32Type(this)) {
    2836           0 :         MUseDefIterator use(this);
    2837           0 :         if (use.def()->isMod() && use.def()->toMod()->isUnsigned())
    2838           0 :             return getOperand(0);
    2839           0 :         MOZ_ASSERT(!(++use));
    2840             :     }
    2841             : 
    2842             :     // Eliminate bitwise operations that are no-ops when used on integer
    2843             :     // inputs, such as (x | 0).
    2844             : 
    2845           0 :     MDefinition* lhs = getOperand(0);
    2846           0 :     MDefinition* rhs = getOperand(1);
    2847             : 
    2848           0 :     if (IsConstant(lhs, 0))
    2849           0 :         return foldIfZero(0);
    2850             : 
    2851           0 :     if (IsConstant(rhs, 0))
    2852           0 :         return foldIfZero(1);
    2853             : 
    2854           0 :     if (IsConstant(lhs, -1))
    2855           0 :         return foldIfNegOne(0);
    2856             : 
    2857           0 :     if (IsConstant(rhs, -1))
    2858           0 :         return foldIfNegOne(1);
    2859             : 
    2860           0 :     if (lhs == rhs)
    2861           0 :         return foldIfEqual();
    2862             : 
    2863           0 :     if (maskMatchesRightRange) {
    2864           0 :         MOZ_ASSERT(lhs->isConstant());
    2865           0 :         MOZ_ASSERT(lhs->type() == MIRType::Int32);
    2866           0 :         return foldIfAllBitsSet(0);
    2867             :     }
    2868             : 
    2869           0 :     if (maskMatchesLeftRange) {
    2870           0 :         MOZ_ASSERT(rhs->isConstant());
    2871           0 :         MOZ_ASSERT(rhs->type() == MIRType::Int32);
    2872           0 :         return foldIfAllBitsSet(1);
    2873             :     }
    2874             : 
    2875           0 :     return this;
    2876             : }
    2877             : 
    2878             : void
    2879           2 : MBinaryBitwiseInstruction::infer(BaselineInspector*, jsbytecode*)
    2880             : {
    2881           8 :     if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(0)->mightBeType(MIRType::Symbol) ||
    2882           6 :         getOperand(1)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Symbol))
    2883             :     {
    2884           0 :         specialization_ = MIRType::None;
    2885             :     } else {
    2886           2 :         specializeAs(MIRType::Int32);
    2887             :     }
    2888           2 : }
    2889             : 
    2890             : void
    2891           2 : MBinaryBitwiseInstruction::specializeAs(MIRType type)
    2892             : {
    2893           2 :     MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
    2894           2 :     MOZ_ASSERT(this->type() == type);
    2895             : 
    2896           2 :     specialization_ = type;
    2897             : 
    2898           2 :     if (isBitOr() || isBitAnd() || isBitXor())
    2899           2 :         setCommutative();
    2900           2 : }
    2901             : 
    2902             : void
    2903           0 : MShiftInstruction::infer(BaselineInspector*, jsbytecode*)
    2904             : {
    2905           0 :     if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Object) ||
    2906           0 :         getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol))
    2907           0 :         specialization_ = MIRType::None;
    2908             :     else
    2909           0 :         specialization_ = MIRType::Int32;
    2910           0 : }
    2911             : 
    2912             : void
    2913           0 : MUrsh::infer(BaselineInspector* inspector, jsbytecode* pc)
    2914             : {
    2915           0 :     if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Object) ||
    2916           0 :         getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol))
    2917             :     {
    2918           0 :         specialization_ = MIRType::None;
    2919           0 :         setResultType(MIRType::Value);
    2920           0 :         return;
    2921             :     }
    2922             : 
    2923           0 :     if (inspector->hasSeenDoubleResult(pc)) {
    2924           0 :         specialization_ = MIRType::Double;
    2925           0 :         setResultType(MIRType::Double);
    2926           0 :         return;
    2927             :     }
    2928             : 
    2929           0 :     specialization_ = MIRType::Int32;
    2930           0 :     setResultType(MIRType::Int32);
    2931             : }
    2932             : 
    2933             : static inline bool
    2934           0 : CanProduceNegativeZero(MDefinition* def)
    2935             : {
    2936             :     // Test if this instruction can produce negative zero even when bailing out
    2937             :     // and changing types.
    2938           0 :     switch (def->op()) {
    2939             :         case MDefinition::Op_Constant:
    2940           0 :             if (def->type() == MIRType::Double && def->toConstant()->toDouble() == -0.0)
    2941           0 :                 return true;
    2942             :             MOZ_FALLTHROUGH;
    2943             :         case MDefinition::Op_BitAnd:
    2944             :         case MDefinition::Op_BitOr:
    2945             :         case MDefinition::Op_BitXor:
    2946             :         case MDefinition::Op_BitNot:
    2947             :         case MDefinition::Op_Lsh:
    2948             :         case MDefinition::Op_Rsh:
    2949           0 :             return false;
    2950             :         default:
    2951           0 :             return true;
    2952             :     }
    2953             : }
    2954             : 
    2955             : static inline bool
    2956           1 : NeedNegativeZeroCheck(MDefinition* def)
    2957             : {
    2958           1 :     if (def->isGuardRangeBailouts())
    2959           0 :         return true;
    2960             : 
    2961             :     // Test if all uses have the same semantics for -0 and 0
    2962           2 :     for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
    2963           1 :         if (use->consumer()->isResumePoint())
    2964           0 :             continue;
    2965             : 
    2966           1 :         MDefinition* use_def = use->consumer()->toDefinition();
    2967           1 :         switch (use_def->op()) {
    2968             :           case MDefinition::Op_Add: {
    2969             :             // If add is truncating -0 and 0 are observed as the same.
    2970           0 :             if (use_def->toAdd()->isTruncated())
    2971           0 :                 break;
    2972             : 
    2973             :             // x + y gives -0, when both x and y are -0
    2974             : 
    2975             :             // Figure out the order in which the addition's operands will
    2976             :             // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
    2977             :             // definitions for us so that this just requires comparing ids.
    2978           0 :             MDefinition* first = use_def->toAdd()->lhs();
    2979           0 :             MDefinition* second = use_def->toAdd()->rhs();
    2980           0 :             if (first->id() > second->id()) {
    2981           0 :                 MDefinition* temp = first;
    2982           0 :                 first = second;
    2983           0 :                 second = temp;
    2984             :             }
    2985             :             // Negative zero checks can be removed on the first executed
    2986             :             // operand only if it is guaranteed the second executed operand
    2987             :             // will produce a value other than -0. While the second is
    2988             :             // typed as an int32, a bailout taken between execution of the
    2989             :             // operands may change that type and cause a -0 to flow to the
    2990             :             // second.
    2991             :             //
    2992             :             // There is no way to test whether there are any bailouts
    2993             :             // between execution of the operands, so remove negative
    2994             :             // zero checks from the first only if the second's type is
    2995             :             // independent from type changes that may occur after bailing.
    2996           0 :             if (def == first && CanProduceNegativeZero(second))
    2997           0 :                 return true;
    2998             : 
    2999             :             // The negative zero check can always be removed on the second
    3000             :             // executed operand; by the time this executes the first will have
    3001             :             // been evaluated as int32 and the addition's result cannot be -0.
    3002           0 :             break;
    3003             :           }
    3004             :           case MDefinition::Op_Sub: {
    3005             :             // If sub is truncating -0 and 0 are observed as the same
    3006           0 :             if (use_def->toSub()->isTruncated())
    3007           0 :                 break;
    3008             : 
    3009             :             // x + y gives -0, when x is -0 and y is 0
    3010             : 
    3011             :             // We can remove the negative zero check on the rhs, only if we
    3012             :             // are sure the lhs isn't negative zero.
    3013             : 
    3014             :             // The lhs is typed as integer (i.e. not -0.0), but it can bailout
    3015             :             // and change type. This should be fine if the lhs is executed
    3016             :             // first. However if the rhs is executed first, the lhs can bail,
    3017             :             // change type and become -0.0 while the rhs has already been
    3018             :             // optimized to not make a difference between zero and negative zero.
    3019           0 :             MDefinition* lhs = use_def->toSub()->lhs();
    3020           0 :             MDefinition* rhs = use_def->toSub()->rhs();
    3021           0 :             if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs))
    3022           0 :                 return true;
    3023             : 
    3024             :             MOZ_FALLTHROUGH;
    3025             :           }
    3026             :           case MDefinition::Op_StoreElement:
    3027             :           case MDefinition::Op_StoreElementHole:
    3028             :           case MDefinition::Op_FallibleStoreElement:
    3029             :           case MDefinition::Op_LoadElement:
    3030             :           case MDefinition::Op_LoadElementHole:
    3031             :           case MDefinition::Op_LoadUnboxedScalar:
    3032             :           case MDefinition::Op_LoadTypedArrayElementHole:
    3033             :           case MDefinition::Op_CharCodeAt:
    3034             :           case MDefinition::Op_Mod:
    3035             :             // Only allowed to remove check when definition is the second operand
    3036           0 :             if (use_def->getOperand(0) == def)
    3037           0 :                 return true;
    3038           0 :             for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
    3039           0 :                 if (use_def->getOperand(i) == def)
    3040           0 :                     return true;
    3041             :             }
    3042           0 :             break;
    3043             :           case MDefinition::Op_BoundsCheck:
    3044             :             // Only allowed to remove check when definition is the first operand
    3045           0 :             if (use_def->toBoundsCheck()->getOperand(1) == def)
    3046           0 :                 return true;
    3047           0 :             break;
    3048             :           case MDefinition::Op_ToString:
    3049             :           case MDefinition::Op_FromCharCode:
    3050             :           case MDefinition::Op_TableSwitch:
    3051             :           case MDefinition::Op_Compare:
    3052             :           case MDefinition::Op_BitAnd:
    3053             :           case MDefinition::Op_BitOr:
    3054             :           case MDefinition::Op_BitXor:
    3055             :           case MDefinition::Op_Abs:
    3056             :           case MDefinition::Op_TruncateToInt32:
    3057             :             // Always allowed to remove check. No matter which operand.
    3058           1 :             break;
    3059             :           default:
    3060           0 :             return true;
    3061             :         }
    3062             :     }
    3063           1 :     return false;
    3064             : }
    3065             : 
    3066             : void
    3067           0 : MBinaryArithInstruction::printOpcode(GenericPrinter& out) const
    3068             : {
    3069           0 :     MDefinition::printOpcode(out);
    3070             : 
    3071           0 :     switch (type()) {
    3072             :       case MIRType::Int32:
    3073           0 :         if (isDiv())
    3074           0 :             out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32");
    3075           0 :         else if (isMod())
    3076           0 :             out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32");
    3077             :         else
    3078           0 :             out.printf(" [int32]");
    3079           0 :         break;
    3080             :       case MIRType::Int64:
    3081           0 :         if (isDiv())
    3082           0 :             out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64");
    3083           0 :         else if (isMod())
    3084           0 :             out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64");
    3085             :         else
    3086           0 :             out.printf(" [int64]");
    3087           0 :         break;
    3088             :       case MIRType::Float32:
    3089           0 :         out.printf(" [float]");
    3090           0 :         break;
    3091             :       case MIRType::Double:
    3092           0 :         out.printf(" [double]");
    3093           0 :         break;
    3094             :       default:
    3095           0 :         break;
    3096             :     }
    3097           0 : }
    3098             : 
    3099             : MBinaryArithInstruction*
    3100         211 : MBinaryArithInstruction::New(TempAllocator& alloc, Opcode op,
    3101             :                              MDefinition* left, MDefinition* right)
    3102             : {
    3103         211 :     switch (op) {
    3104             :       case Op_Add:
    3105         208 :         return MAdd::New(alloc, left, right);
    3106             :       case Op_Sub:
    3107           0 :         return MSub::New(alloc, left, right);
    3108             :       case Op_Mul:
    3109           3 :         return MMul::New(alloc, left, right);
    3110             :       case Op_Div:
    3111           0 :         return MDiv::New(alloc, left, right);
    3112             :       case Op_Mod:
    3113           0 :         return MMod::New(alloc, left, right);
    3114             :       default:
    3115           0 :         MOZ_CRASH("unexpected binary opcode");
    3116             :     }
    3117             : }
    3118             : 
    3119             : void
    3120         211 : MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector,
    3121             :                                                  jsbytecode* pc)
    3122             : {
    3123         211 :     setSpecialization(MIRType::Double);
    3124             : 
    3125             :     // Try to specialize as int32.
    3126         211 :     if (getOperand(0)->type() == MIRType::Int32 && getOperand(1)->type() == MIRType::Int32) {
    3127         160 :         bool seenDouble = inspector->hasSeenDoubleResult(pc);
    3128             : 
    3129             :         // Use int32 specialization if the operation doesn't overflow on its
    3130             :         // constant operands and if the operation has never overflowed.
    3131         160 :         if (!seenDouble && !constantDoubleResult(alloc))
    3132         160 :             setInt32Specialization();
    3133             :     }
    3134         211 : }
    3135             : 
    3136             : bool
    3137         160 : MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc)
    3138             : {
    3139         160 :     bool typeChange = false;
    3140         160 :     EvaluateConstantOperands(alloc, this, &typeChange);
    3141         160 :     return typeChange;
    3142             : }
    3143             : 
    3144             : MDefinition*
    3145           0 : MRsh::foldsTo(TempAllocator& alloc)
    3146             : {
    3147           0 :     MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
    3148             : 
    3149           0 :     if (f != this)
    3150           0 :         return f;
    3151             : 
    3152           0 :     MDefinition* lhs = getOperand(0);
    3153           0 :     MDefinition* rhs = getOperand(1);
    3154             : 
    3155           0 :     if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32)
    3156           0 :         return this;
    3157             : 
    3158           0 :     if (!lhs->getOperand(1)->isConstant() || lhs->getOperand(1)->type() != MIRType::Int32)
    3159           0 :         return this;
    3160             : 
    3161           0 :     uint32_t shift = rhs->toConstant()->toInt32();
    3162           0 :     uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32();
    3163           0 :     if (shift != shift_lhs)
    3164           0 :         return this;
    3165             : 
    3166           0 :     switch (shift) {
    3167             :       case 16:
    3168           0 :         return MSignExtend::New(alloc, lhs->getOperand(0), MSignExtend::Half);
    3169             :       case 24:
    3170           0 :         return MSignExtend::New(alloc, lhs->getOperand(0), MSignExtend::Byte);
    3171             :     }
    3172             : 
    3173           0 :     return this;
    3174             : }
    3175             : 
    3176             : MDefinition*
    3177          13 : MBinaryArithInstruction::foldsTo(TempAllocator& alloc)
    3178             : {
    3179          13 :     if (specialization_ == MIRType::None)
    3180           0 :         return this;
    3181             : 
    3182          13 :     if (specialization_ == MIRType::Int64)
    3183           0 :         return this;
    3184             : 
    3185          13 :     MDefinition* lhs = getOperand(0);
    3186          13 :     MDefinition* rhs = getOperand(1);
    3187          13 :     if (MConstant* folded = EvaluateConstantOperands(alloc, this)) {
    3188           1 :         if (isTruncated()) {
    3189           0 :             if (!folded->block())
    3190           0 :                 block()->insertBefore(this, folded);
    3191           0 :             if (folded->type() != MIRType::Int32)
    3192           1 :                 return MTruncateToInt32::New(alloc, folded);
    3193             :         }
    3194           1 :         return folded;
    3195             :     }
    3196             : 
    3197          12 :     if (mustPreserveNaN_)
    3198           0 :         return this;
    3199             : 
    3200             :     // 0 + -0 = 0. So we can't remove addition
    3201          12 :     if (isAdd() && specialization_ != MIRType::Int32)
    3202           0 :         return this;
    3203             : 
    3204          12 :     if (IsConstant(rhs, getIdentity())) {
    3205           0 :         if (isTruncated())
    3206           0 :             return MTruncateToInt32::New(alloc, lhs);
    3207           0 :         return lhs;
    3208             :     }
    3209             : 
    3210             :     // subtraction isn't commutative. So we can't remove subtraction when lhs equals 0
    3211          12 :     if (isSub())
    3212           0 :         return this;
    3213             : 
    3214          12 :     if (IsConstant(lhs, getIdentity())) {
    3215           0 :         if (isTruncated())
    3216           0 :             return MTruncateToInt32::New(alloc, rhs);
    3217           0 :         return rhs; // x op id => x
    3218             :     }
    3219             : 
    3220          12 :     return this;
    3221             : }
    3222             : 
    3223             : void
    3224           0 : MFilterTypeSet::trySpecializeFloat32(TempAllocator& alloc)
    3225             : {
    3226           0 :     MDefinition* in = input();
    3227           0 :     if (in->type() != MIRType::Float32)
    3228           0 :         return;
    3229             : 
    3230           0 :     setResultType(MIRType::Float32);
    3231             : }
    3232             : 
    3233             : bool
    3234           6 : MFilterTypeSet::canProduceFloat32() const
    3235             : {
    3236             :     // A FilterTypeSet should be a producer if the input is a producer too.
    3237             :     // Also, be overly conservative by marking as not float32 producer when the
    3238             :     // input is a phi, as phis can be cyclic (phiA -> FilterTypeSet -> phiB ->
    3239             :     // phiA) and FilterTypeSet doesn't belong in the Float32 phi analysis.
    3240           6 :     return !input()->isPhi() && input()->canProduceFloat32();
    3241             : }
    3242             : 
    3243             : bool
    3244           0 : MFilterTypeSet::canConsumeFloat32(MUse* operand) const
    3245             : {
    3246           0 :     MOZ_ASSERT(getUseFor(0) == operand);
    3247             :     // A FilterTypeSet should be a consumer if all uses are consumer. See also
    3248             :     // comment below MFilterTypeSet::canProduceFloat32.
    3249           0 :     bool allConsumerUses = true;
    3250           0 :     for (MUseDefIterator use(this); allConsumerUses && use; use++)
    3251           0 :         allConsumerUses &= !use.def()->isPhi() && use.def()->canConsumeFloat32(use.use());
    3252           0 :     return allConsumerUses;
    3253             : }
    3254             : 
    3255             : void
    3256           0 : MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc)
    3257             : {
    3258             :     // Do not use Float32 if we can use int32.
    3259           0 :     if (specialization_ == MIRType::Int32)
    3260           0 :         return;
    3261           0 :     if (specialization_ == MIRType::None)
    3262           0 :         return;
    3263             : 
    3264           0 :     MDefinition* left = lhs();
    3265           0 :     MDefinition* right = rhs();
    3266             : 
    3267           0 :     if (!left->canProduceFloat32() || !right->canProduceFloat32() ||
    3268           0 :         !CheckUsesAreFloat32Consumers(this))
    3269             :     {
    3270           0 :         if (left->type() == MIRType::Float32)
    3271           0 :             ConvertDefinitionToDouble<0>(alloc, left, this);
    3272           0 :         if (right->type() == MIRType::Float32)
    3273           0 :             ConvertDefinitionToDouble<1>(alloc, right, this);
    3274           0 :         return;
    3275             :     }
    3276             : 
    3277           0 :     specialization_ = MIRType::Float32;
    3278           0 :     setResultType(MIRType::Float32);
    3279             : }
    3280             : 
    3281             : void
    3282           0 : MMinMax::trySpecializeFloat32(TempAllocator& alloc)
    3283             : {
    3284           0 :     if (specialization_ == MIRType::Int32)
    3285           0 :         return;
    3286             : 
    3287           0 :     MDefinition* left = lhs();
    3288           0 :     MDefinition* right = rhs();
    3289             : 
    3290           0 :     if (!(left->canProduceFloat32() || (left->isMinMax() && left->type() == MIRType::Float32)) ||
    3291           0 :         !(right->canProduceFloat32() || (right->isMinMax() && right->type() == MIRType::Float32)))
    3292             :     {
    3293           0 :         if (left->type() == MIRType::Float32)
    3294           0 :             ConvertDefinitionToDouble<0>(alloc, left, this);
    3295           0 :         if (right->type() == MIRType::Float32)
    3296           0 :             ConvertDefinitionToDouble<1>(alloc, right, this);
    3297           0 :         return;
    3298             :     }
    3299             : 
    3300           0 :     specialization_ = MIRType::Float32;
    3301           0 :     setResultType(MIRType::Float32);
    3302             : }
    3303             : 
    3304             : MDefinition*
    3305           8 : MMinMax::foldsTo(TempAllocator& alloc)
    3306             : {
    3307           8 :     if (!lhs()->isConstant() && !rhs()->isConstant())
    3308           0 :         return this;
    3309             : 
    3310             :     // Directly apply math utility to compare the rhs() and lhs() when
    3311             :     // they are both constants.
    3312           8 :     if (lhs()->isConstant() && rhs()->isConstant()) {
    3313           0 :         if (!lhs()->toConstant()->isTypeRepresentableAsDouble() ||
    3314           0 :             !rhs()->toConstant()->isTypeRepresentableAsDouble())
    3315             :         {
    3316           0 :             return this;
    3317             :         }
    3318             : 
    3319           0 :         double lnum = lhs()->toConstant()->numberToDouble();
    3320           0 :         double rnum = rhs()->toConstant()->numberToDouble();
    3321             : 
    3322             :         double result;
    3323           0 :         if (isMax())
    3324           0 :             result = js::math_max_impl(lnum, rnum);
    3325             :         else
    3326           0 :             result = js::math_min_impl(lnum, rnum);
    3327             : 
    3328             :         // The folded MConstant should maintain the same MIRType with
    3329             :         // the original MMinMax.
    3330           0 :         if (type() == MIRType::Int32) {
    3331             :             int32_t cast;
    3332           0 :             if (mozilla::NumberEqualsInt32(result, &cast))
    3333           0 :                 return MConstant::New(alloc, Int32Value(cast));
    3334           0 :         } else if (type() == MIRType::Float32) {
    3335           0 :             return MConstant::NewFloat32(alloc, result);
    3336             :         } else {
    3337           0 :             MOZ_ASSERT(type() == MIRType::Double);
    3338           0 :             return MConstant::New(alloc, DoubleValue(result));
    3339             :         }
    3340             :     }
    3341             : 
    3342           8 :     MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
    3343           8 :     MConstant* constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
    3344             : 
    3345           8 :     if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType::Int32) {
    3346             :         // min(int32, cte >= INT32_MAX) = int32
    3347           0 :         if (!isMax() &&
    3348           0 :             constant->isTypeRepresentableAsDouble() &&
    3349           0 :             constant->numberToDouble() >= INT32_MAX)
    3350             :         {
    3351             :             MLimitedTruncate* limit =
    3352           0 :                 MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
    3353           0 :             block()->insertBefore(this, limit);
    3354           0 :             MToDouble* toDouble = MToDouble::New(alloc, limit);
    3355           0 :             return toDouble;
    3356             :         }
    3357             : 
    3358             :         // max(int32, cte <= INT32_MIN) = int32
    3359           0 :         if (isMax() &&
    3360           0 :             constant->isTypeRepresentableAsDouble() &&
    3361           0 :             constant->numberToDouble() <= INT32_MIN)
    3362             :         {
    3363             :             MLimitedTruncate* limit =
    3364           0 :                 MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
    3365           0 :             block()->insertBefore(this, limit);
    3366           0 :             MToDouble* toDouble = MToDouble::New(alloc, limit);
    3367           0 :             return toDouble;
    3368             :         }
    3369             :     }
    3370             : 
    3371           8 :     if (operand->isArrayLength() && constant->type() == MIRType::Int32) {
    3372           0 :         MOZ_ASSERT(operand->type() == MIRType::Int32);
    3373             : 
    3374             :         // max(array.length, 0) = array.length
    3375             :         // ArrayLength is always >= 0, so just return it.
    3376           0 :         if (isMax() && constant->toInt32() <= 0)
    3377           0 :             return operand;
    3378             :     }
    3379             : 
    3380           8 :     return this;
    3381             : }
    3382             : 
    3383             : MDefinition*
    3384           0 : MPow::foldsConstant(TempAllocator &alloc)
    3385             : {
    3386             :     // Both `x` and `p` in `x^p` must be constants in order to precompute.
    3387           0 :     if(!(input()->isConstant() && power()->isConstant()))
    3388           0 :         return nullptr;
    3389           0 :     if(!power()->toConstant()->isTypeRepresentableAsDouble())
    3390           0 :         return nullptr;
    3391           0 :     if(!input()->toConstant()->isTypeRepresentableAsDouble())
    3392           0 :         return nullptr;
    3393             : 
    3394           0 :     double x = input()->toConstant()->numberToDouble();
    3395           0 :     double p = power()->toConstant()->numberToDouble();
    3396           0 :     return MConstant::New(alloc, DoubleValue(js::ecmaPow(x, p)));
    3397             : }
    3398             : 
    3399             : MDefinition*
    3400           0 : MPow::foldsConstantPower(TempAllocator &alloc)
    3401             : {
    3402             :     // If `p` in `x^p` isn't constant, we can't apply these folds.
    3403           0 :     if(!power()->isConstant())
    3404           0 :         return nullptr;
    3405           0 :     if(!power()->toConstant()->isTypeRepresentableAsDouble())
    3406           0 :         return nullptr;
    3407             : 
    3408           0 :     double pow = power()->toConstant()->numberToDouble();
    3409           0 :     MIRType outputType = type();
    3410             : 
    3411             :     // Math.pow(x, 0.5) is a sqrt with edge-case detection.
    3412           0 :     if (pow == 0.5)
    3413           0 :         return MPowHalf::New(alloc, input());
    3414             : 
    3415             :     // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
    3416           0 :     if (pow == -0.5) {
    3417           0 :         MPowHalf* half = MPowHalf::New(alloc, input());
    3418           0 :         block()->insertBefore(this, half);
    3419           0 :         MConstant* one = MConstant::New(alloc, DoubleValue(1.0));
    3420           0 :         block()->insertBefore(this, one);
    3421           0 :         return MDiv::New(alloc, one, half, MIRType::Double);
    3422             :     }
    3423             : 
    3424             :     // Math.pow(x, 1) == x.
    3425           0 :     if (pow == 1.0)
    3426           0 :         return input();
    3427             : 
    3428             :     // Math.pow(x, 2) == x*x.
    3429           0 :     if (pow == 2.0)
    3430           0 :         return MMul::New(alloc, input(), input(), outputType);
    3431             : 
    3432             :     // Math.pow(x, 3) == x*x*x.
    3433           0 :     if (pow == 3.0) {
    3434           0 :         MMul* mul1 = MMul::New(alloc, input(), input(), outputType);
    3435           0 :         block()->insertBefore(this, mul1);
    3436           0 :         return MMul::New(alloc, input(), mul1, outputType);
    3437             :     }
    3438             : 
    3439             :     // Math.pow(x, 4) == y*y, where y = x*x.
    3440           0 :     if (pow == 4.0) {
    3441           0 :         MMul* y = MMul::New(alloc, input(), input(), outputType);
    3442           0 :         block()->insertBefore(this, y);
    3443           0 :         return MMul::New(alloc, y, y, outputType);
    3444             :     }
    3445             : 
    3446             :     // No optimization
    3447           0 :     return nullptr;
    3448             : }
    3449             : 
    3450             : MDefinition*
    3451           0 : MPow::foldsTo(TempAllocator& alloc)
    3452             : {
    3453           0 :     if(MDefinition *def = foldsConstant(alloc))
    3454           0 :         return def;
    3455           0 :     if(MDefinition *def = foldsConstantPower(alloc))
    3456           0 :         return def;
    3457           0 :     return this;
    3458             : }
    3459             : 
    3460             : bool
    3461           0 : MAbs::fallible() const
    3462             : {
    3463           0 :     return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
    3464             : }
    3465             : 
    3466             : void
    3467           0 : MAbs::trySpecializeFloat32(TempAllocator& alloc)
    3468             : {
    3469             :     // Do not use Float32 if we can use int32.
    3470           0 :     if (input()->type() == MIRType::Int32)
    3471           0 :         return;
    3472             : 
    3473           0 :     if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
    3474           0 :         if (input()->type() == MIRType::Float32)
    3475           0 :             ConvertDefinitionToDouble<0>(alloc, input(), this);
    3476           0 :         return;
    3477             :     }
    3478             : 
    3479           0 :     setResultType(MIRType::Float32);
    3480           0 :     specialization_ = MIRType::Float32;
    3481             : }
    3482             : 
    3483             : MDefinition*
    3484           0 : MDiv::foldsTo(TempAllocator& alloc)
    3485             : {
    3486           0 :     if (specialization_ == MIRType::None)
    3487           0 :         return this;
    3488             : 
    3489           0 :     if (specialization_ == MIRType::Int64)
    3490           0 :         return this;
    3491             : 
    3492           0 :     if (MDefinition* folded = EvaluateConstantOperands(alloc, this))
    3493           0 :         return folded;
    3494             : 
    3495           0 :     if (MDefinition* folded = EvaluateExactReciprocal(alloc, this))
    3496           0 :         return folded;
    3497             : 
    3498           0 :     return this;
    3499             : }
    3500             : 
    3501             : void
    3502           0 : MDiv::analyzeEdgeCasesForward()
    3503             : {
    3504             :     // This is only meaningful when doing integer division.
    3505           0 :     if (specialization_ != MIRType::Int32)
    3506           0 :         return;
    3507             : 
    3508           0 :     MOZ_ASSERT(lhs()->type() == MIRType::Int32);
    3509           0 :     MOZ_ASSERT(rhs()->type() == MIRType::Int32);
    3510             : 
    3511             :     // Try removing divide by zero check
    3512           0 :     if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0))
    3513           0 :         canBeDivideByZero_ = false;
    3514             : 
    3515             :     // If lhs is a constant int != INT32_MIN, then
    3516             :     // negative overflow check can be skipped.
    3517           0 :     if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN))
    3518           0 :         canBeNegativeOverflow_ = false;
    3519             : 
    3520             :     // If rhs is a constant int != -1, likewise.
    3521           0 :     if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1))
    3522           0 :         canBeNegativeOverflow_ = false;
    3523             : 
    3524             :     // If lhs is != 0, then negative zero check can be skipped.
    3525           0 :     if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0))
    3526           0 :         setCanBeNegativeZero(false);
    3527             : 
    3528             :     // If rhs is >= 0, likewise.
    3529           0 :     if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
    3530           0 :         if (rhs()->toConstant()->toInt32() >= 0)
    3531           0 :             setCanBeNegativeZero(false);
    3532             :     }
    3533             : }
    3534             : 
    3535             : void
    3536           0 : MDiv::analyzeEdgeCasesBackward()
    3537             : {
    3538           0 :     if (canBeNegativeZero() && !NeedNegativeZeroCheck(this))
    3539           0 :         setCanBeNegativeZero(false);
    3540           0 : }
    3541             : 
    3542             : bool
    3543           0 : MDiv::fallible() const
    3544             : {
    3545           0 :     return !isTruncated();
    3546             : }
    3547             : 
    3548             : MDefinition*
    3549           0 : MMod::foldsTo(TempAllocator& alloc)
    3550             : {
    3551           0 :     if (specialization_ == MIRType::None)
    3552           0 :         return this;
    3553             : 
    3554           0 :     if (specialization_ == MIRType::Int64)
    3555           0 :         return this;
    3556             : 
    3557           0 :     if (MDefinition* folded = EvaluateConstantOperands(alloc, this))
    3558           0 :         return folded;
    3559             : 
    3560           0 :     return this;
    3561             : }
    3562             : 
    3563             : void
    3564           0 : MMod::analyzeEdgeCasesForward()
    3565             : {
    3566             :     // These optimizations make sense only for integer division
    3567           0 :     if (specialization_ != MIRType::Int32)
    3568           0 :         return;
    3569             : 
    3570           0 :     if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0))
    3571           0 :         canBeDivideByZero_ = false;
    3572             : 
    3573           0 :     if (rhs()->isConstant()) {
    3574           0 :         int32_t n = rhs()->toConstant()->toInt32();
    3575           0 :         if (n > 0 && !IsPowerOfTwo(uint32_t(n)))
    3576           0 :             canBePowerOfTwoDivisor_ = false;
    3577             :     }
    3578             : }
    3579             : 
    3580             : bool
    3581           0 : MMod::fallible() const
    3582             : {
    3583           0 :     return !isTruncated() &&
    3584           0 :            (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
    3585             : }
    3586             : 
    3587             : void
    3588           0 : MMathFunction::trySpecializeFloat32(TempAllocator& alloc)
    3589             : {
    3590           0 :     if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
    3591           0 :         if (input()->type() == MIRType::Float32)
    3592           0 :             ConvertDefinitionToDouble<0>(alloc, input(), this);
    3593           0 :         return;
    3594             :     }
    3595             : 
    3596           0 :     setResultType(MIRType::Float32);
    3597           0 :     specialization_ = MIRType::Float32;
    3598             : }
    3599             : 
    3600           0 : MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector & vector)
    3601             : {
    3602           0 :     uint32_t length = vector.length();
    3603           0 :     MHypot * hypot = new(alloc) MHypot;
    3604           0 :     if (!hypot->init(alloc, length))
    3605           0 :         return nullptr;
    3606             : 
    3607           0 :     for (uint32_t i = 0; i < length; ++i)
    3608           0 :         hypot->initOperand(i, vector[i]);
    3609           0 :     return hypot;
    3610             : }
    3611             : 
    3612             : bool
    3613          16 : MAdd::fallible() const
    3614             : {
    3615             :     // the add is fallible if range analysis does not say that it is finite, AND
    3616             :     // either the truncation analysis shows that there are non-truncated uses.
    3617          16 :     if (truncateKind() >= IndirectTruncate)
    3618           2 :         return false;
    3619          14 :     if (range() && range()->hasInt32Bounds())
    3620          12 :         return false;
    3621           2 :     return true;
    3622             : }
    3623             : 
    3624             : bool
    3625           0 : MSub::fallible() const
    3626             : {
    3627             :     // see comment in MAdd::fallible()
    3628           0 :     if (truncateKind() >= IndirectTruncate)
    3629           0 :         return false;
    3630           0 :     if (range() && range()->hasInt32Bounds())
    3631           0 :         return false;
    3632           0 :     return true;
    3633             : }
    3634             : 
    3635             : MDefinition*
    3636           0 : MMul::foldsTo(TempAllocator& alloc)
    3637             : {
    3638           0 :     MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
    3639           0 :     if (out != this)
    3640           0 :         return out;
    3641             : 
    3642           0 :     if (specialization() != MIRType::Int32)
    3643           0 :         return this;
    3644             : 
    3645           0 :     if (lhs() == rhs())
    3646           0 :         setCanBeNegativeZero(false);
    3647             : 
    3648           0 :     return this;
    3649             : }
    3650             : 
    3651             : void
    3652           0 : MMul::analyzeEdgeCasesForward()
    3653             : {
    3654             :     // Try to remove the check for negative zero
    3655             :     // This only makes sense when using the integer multiplication
    3656           0 :     if (specialization() != MIRType::Int32)
    3657           0 :         return;
    3658             : 
    3659             :     // If lhs is > 0, no need for negative zero check.
    3660           0 :     if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) {
    3661           0 :         if (lhs()->toConstant()->toInt32() > 0)
    3662           0 :             setCanBeNegativeZero(false);
    3663             :     }
    3664             : 
    3665             :     // If rhs is > 0, likewise.
    3666           0 :     if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
    3667           0 :         if (rhs()->toConstant()->toInt32() > 0)
    3668           0 :             setCanBeNegativeZero(false);
    3669             :     }
    3670             : }
    3671             : 
    3672             : void
    3673           0 : MMul::analyzeEdgeCasesBackward()
    3674             : {
    3675           0 :     if (canBeNegativeZero() && !NeedNegativeZeroCheck(this))
    3676           0 :         setCanBeNegativeZero(false);
    3677           0 : }
    3678             : 
    3679             : bool
    3680           0 : MMul::updateForReplacement(MDefinition* ins_)
    3681             : {
    3682           0 :     MMul* ins = ins_->toMul();
    3683           0 :     bool negativeZero = canBeNegativeZero() || ins->canBeNegativeZero();
    3684           0 :     setCanBeNegativeZero(negativeZero);
    3685             :     // Remove the imul annotation when merging imul and normal multiplication.
    3686           0 :     if (mode_ == Integer && ins->mode() != Integer)
    3687           0 :         mode_ = Normal;
    3688           0 :     return true;
    3689             : }
    3690             : 
    3691             : bool
    3692           0 : MMul::canOverflow() const
    3693             : {
    3694           0 :     if (isTruncated())
    3695           0 :         return false;
    3696           0 :     return !range() || !range()->hasInt32Bounds();
    3697             : }
    3698             : 
    3699             : bool
    3700           0 : MUrsh::fallible() const
    3701             : {
    3702           0 :     if (bailoutsDisabled())
    3703           0 :         return false;
    3704           0 :     return !range() || !range()->hasInt32Bounds();
    3705             : }
    3706             : 
    3707             : static inline bool
    3708          24 : SimpleArithOperand(MDefinition* op)
    3709             : {
    3710          24 :     return !op->mightBeType(MIRType::Object)
    3711          24 :         && !op->mightBeType(MIRType::String)
    3712          24 :         && !op->mightBeType(MIRType::Symbol)
    3713          24 :         && !op->mightBeType(MIRType::MagicOptimizedArguments)
    3714          24 :         && !op->mightBeType(MIRType::MagicHole)
    3715          48 :         && !op->mightBeType(MIRType::MagicIsConstructing);
    3716             : }
    3717             : 
    3718             : static bool
    3719          24 : SafelyCoercesToDouble(MDefinition* op)
    3720             : {
    3721             :     // Strings and symbols are unhandled -- visitToDouble() doesn't support them yet.
    3722             :     // Null is unhandled -- ToDouble(null) == 0, but (0 == null) is false.
    3723          24 :     return SimpleArithOperand(op) && !op->mightBeType(MIRType::Null);
    3724             : }
    3725             : 
    3726             : MIRType
    3727          61 : MCompare::inputType()
    3728             : {
    3729          61 :     switch(compareType_) {
    3730             :       case Compare_Undefined:
    3731           0 :         return MIRType::Undefined;
    3732             :       case Compare_Null:
    3733           8 :         return MIRType::Null;
    3734             :       case Compare_Boolean:
    3735           0 :         return MIRType::Boolean;
    3736             :       case Compare_UInt32:
    3737             :       case Compare_Int32:
    3738             :       case Compare_Int32MaybeCoerceBoth:
    3739             :       case Compare_Int32MaybeCoerceLHS:
    3740             :       case Compare_Int32MaybeCoerceRHS:
    3741          53 :         return MIRType::Int32;
    3742             :       case Compare_Double:
    3743             :       case Compare_DoubleMaybeCoerceLHS:
    3744             :       case Compare_DoubleMaybeCoerceRHS:
    3745           0 :         return MIRType::Double;
    3746             :       case Compare_Float32:
    3747           0 :         return MIRType::Float32;
    3748             :       case Compare_String:
    3749             :       case Compare_StrictString:
    3750           0 :         return MIRType::String;
    3751             :       case Compare_Symbol:
    3752           0 :         return MIRType::Symbol;
    3753             :       case Compare_Object:
    3754           0 :         return MIRType::Object;
    3755             :       case Compare_Unknown:
    3756             :       case Compare_Bitwise:
    3757           0 :         return MIRType::Value;
    3758             :       default:
    3759           0 :         MOZ_CRASH("No known conversion");
    3760             :     }
    3761             : }
    3762             : 
    3763             : static inline bool
    3764         486 : MustBeUInt32(MDefinition* def, MDefinition** pwrapped)
    3765             : {
    3766         486 :     if (def->isUrsh()) {
    3767           0 :         *pwrapped = def->toUrsh()->lhs();
    3768           0 :         MDefinition* rhs = def->toUrsh()->rhs();
    3769           0 :         return def->toUrsh()->bailoutsDisabled() &&
    3770           0 :                rhs->maybeConstantValue() &&
    3771           0 :                rhs->maybeConstantValue()->isInt32(0);
    3772             :     }
    3773             : 
    3774         486 :     if (MConstant* defConst = def->maybeConstantValue()) {
    3775           2 :         *pwrapped = defConst;
    3776           2 :         return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0;
    3777             :     }
    3778             : 
    3779         484 :     *pwrapped = nullptr;  // silence GCC warning
    3780         484 :     return false;
    3781             : }
    3782             : 
    3783             : /* static */ bool
    3784         486 : MBinaryInstruction::unsignedOperands(MDefinition* left, MDefinition* right)
    3785             : {
    3786             :     MDefinition* replace;
    3787         486 :     if (!MustBeUInt32(left, &replace))
    3788         486 :         return false;
    3789           0 :     if (replace->type() != MIRType::Int32)
    3790           0 :         return false;
    3791           0 :     if (!MustBeUInt32(right, &replace))
    3792           0 :         return false;
    3793           0 :     if (replace->type() != MIRType::Int32)
    3794           0 :         return false;
    3795           0 :     return true;
    3796             : }
    3797             : 
    3798             : bool
    3799           0 : MBinaryInstruction::unsignedOperands()
    3800             : {
    3801           0 :     return unsignedOperands(getOperand(0), getOperand(1));
    3802             : }
    3803             : 
    3804             : void
    3805           0 : MBinaryInstruction::replaceWithUnsignedOperands()
    3806             : {
    3807           0 :     MOZ_ASSERT(unsignedOperands());
    3808             : 
    3809           0 :     for (size_t i = 0; i < numOperands(); i++) {
    3810             :         MDefinition* replace;
    3811           0 :         MustBeUInt32(getOperand(i), &replace);
    3812           0 :         if (replace == getOperand(i))
    3813           0 :             continue;
    3814             : 
    3815           0 :         getOperand(i)->setImplicitlyUsedUnchecked();
    3816           0 :         replaceOperand(i, replace);
    3817             :     }
    3818           0 : }
    3819             : 
    3820             : MCompare::CompareType
    3821         486 : MCompare::determineCompareType(JSOp op, MDefinition* left, MDefinition* right)
    3822             : {
    3823         486 :     MIRType lhs = left->type();
    3824         486 :     MIRType rhs = right->type();
    3825             : 
    3826         486 :     bool looseEq = op == JSOP_EQ || op == JSOP_NE;
    3827         486 :     bool strictEq = op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
    3828         486 :     bool relationalEq = !(looseEq || strictEq);
    3829             : 
    3830             :     // Comparisons on unsigned integers may be treated as UInt32.
    3831         486 :     if (unsignedOperands(left, right))
    3832           0 :         return Compare_UInt32;
    3833             : 
    3834             :     // Integer to integer or boolean to boolean comparisons may be treated as Int32.
    3835         486 :     if ((lhs == MIRType::Int32 && rhs == MIRType::Int32) ||
    3836           0 :         (lhs == MIRType::Boolean && rhs == MIRType::Boolean))
    3837             :     {
    3838          84 :         return Compare_Int32MaybeCoerceBoth;
    3839             :     }
    3840             : 
    3841             :     // Loose/relational cross-integer/boolean comparisons may be treated as Int32.
    3842         402 :     if (!strictEq &&
    3843         162 :         (lhs == MIRType::Int32 || lhs == MIRType::Boolean) &&
    3844         107 :         (rhs == MIRType::Int32 || rhs == MIRType::Boolean))
    3845             :     {
    3846           0 :         return Compare_Int32MaybeCoerceBoth;
    3847             :     }
    3848             : 
    3849             :     // Numeric comparisons against a double coerce to double.
    3850         402 :     if (IsTypeRepresentableAsDouble(lhs) && IsTypeRepresentableAsDouble(rhs))
    3851          42 :         return Compare_Double;
    3852             : 
    3853             :     // Any comparison is allowed except strict eq.
    3854         360 :     if (!strictEq && IsFloatingPointType(rhs) && SafelyCoercesToDouble(left))
    3855           0 :         return Compare_DoubleMaybeCoerceLHS;
    3856         360 :     if (!strictEq && IsFloatingPointType(lhs) && SafelyCoercesToDouble(right))
    3857          24 :         return Compare_DoubleMaybeCoerceRHS;
    3858             : 
    3859             :     // Handle object comparison.
    3860         336 :     if (!relationalEq && lhs == MIRType::Object && rhs == MIRType::Object)
    3861           0 :         return Compare_Object;
    3862             : 
    3863             :     // Handle string comparisons. (Relational string compares are still unsupported).
    3864         336 :     if (!relationalEq && lhs == MIRType::String && rhs == MIRType::String)
    3865           3 :         return Compare_String;
    3866             : 
    3867             :     // Handle symbol comparisons. (Relaational compare will throw)
    3868         333 :     if (!relationalEq && lhs == MIRType::Symbol && rhs == MIRType::Symbol)
    3869           0 :         return Compare_Symbol;
    3870             : 
    3871             :     // Handle strict string compare.
    3872         333 :     if (strictEq && lhs == MIRType::String)
    3873           0 :         return Compare_StrictString;
    3874         333 :     if (strictEq && rhs == MIRType::String)
    3875           0 :         return Compare_StrictString;
    3876             : 
    3877             :     // Handle compare with lhs or rhs being Undefined or Null.
    3878         333 :     if (!relationalEq && IsNullOrUndefined(lhs))
    3879           2 :         return (lhs == MIRType::Null) ? Compare_Null : Compare_Undefined;
    3880         331 :     if (!relationalEq && IsNullOrUndefined(rhs))
    3881          15 :         return (rhs == MIRType::Null) ? Compare_Null : Compare_Undefined;
    3882             : 
    3883             :     // Handle strict comparison with lhs/rhs being typed Boolean.
    3884         316 :     if (strictEq && (lhs == MIRType::Boolean || rhs == MIRType::Boolean)) {
    3885             :         // bool/bool case got an int32 specialization earlier.
    3886           0 :         MOZ_ASSERT(!(lhs == MIRType::Boolean && rhs == MIRType::Boolean));
    3887           0 :         return Compare_Boolean;
    3888             :     }
    3889             : 
    3890         316 :     return Compare_Unknown;
    3891             : }
    3892             : 
    3893             : void
    3894         269 : MCompare::cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints)
    3895             : {
    3896         269 :     MOZ_ASSERT(operandMightEmulateUndefined());
    3897             : 
    3898         269 :     if (getOperand(0)->maybeEmulatesUndefined(constraints))
    3899          11 :         return;
    3900         258 :     if (getOperand(1)->maybeEmulatesUndefined(constraints))
    3901           0 :         return;
    3902             : 
    3903         258 :     markNoOperandEmulatesUndefined();
    3904             : }
    3905             : 
    3906             : MBitNot*
    3907           0 : MBitNot::NewInt32(TempAllocator& alloc, MDefinition* input)
    3908             : {
    3909           0 :     MBitNot* ins = new(alloc) MBitNot(input);
    3910           0 :     ins->specialization_ = MIRType::Int32;
    3911           0 :     MOZ_ASSERT(ins->type() == MIRType::Int32);
    3912           0 :     return ins;
    3913             : }
    3914             : 
    3915             : MDefinition*
    3916           4 : MBitNot::foldsTo(TempAllocator& alloc)
    3917             : {
    3918           4 :     if (specialization_ != MIRType::Int32)
    3919           0 :         return this;
    3920             : 
    3921           4 :     MDefinition* input = getOperand(0);
    3922             : 
    3923           4 :     if (input->isConstant()) {
    3924           0 :         js::Value v = Int32Value(~(input->toConstant()->toInt32()));
    3925           0 :         return MConstant::New(alloc, v);
    3926             :     }
    3927             : 
    3928           4 :     if (input->isBitNot() && input->toBitNot()->specialization_ == MIRType::Int32) {
    3929           2 :         MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType::Int32);
    3930           2 :         return MTruncateToInt32::New(alloc, input->toBitNot()->input()); // ~~x => x | 0
    3931             :     }
    3932             : 
    3933           2 :     return this;
    3934             : }
    3935             : 
    3936             : MDefinition*
    3937           0 : MTypeOf::foldsTo(TempAllocator& alloc)
    3938             : {
    3939             :     // Note: we can't use input->type() here, type analysis has
    3940             :     // boxed the input.
    3941           0 :     MOZ_ASSERT(input()->type() == MIRType::Value);
    3942             : 
    3943             :     JSType type;
    3944             : 
    3945           0 :     switch (inputType()) {
    3946             :       case MIRType::Double:
    3947             :       case MIRType::Float32:
    3948             :       case MIRType::Int32:
    3949           0 :         type = JSTYPE_NUMBER;
    3950           0 :         break;
    3951             :       case MIRType::String:
    3952           0 :         type = JSTYPE_STRING;
    3953           0 :         break;
    3954             :       case MIRType::Symbol:
    3955           0 :         type = JSTYPE_SYMBOL;
    3956           0 :         break;
    3957             :       case MIRType::Null:
    3958           0 :         type = JSTYPE_OBJECT;
    3959           0 :         break;
    3960             :       case MIRType::Undefined:
    3961           0 :         type = JSTYPE_UNDEFINED;
    3962           0 :         break;
    3963             :       case MIRType::Boolean:
    3964           0 :         type = JSTYPE_BOOLEAN;
    3965           0 :         break;
    3966             :       case MIRType::Object:
    3967           0 :         if (!inputMaybeCallableOrEmulatesUndefined()) {
    3968             :             // Object is not callable and does not emulate undefined, so it's
    3969             :             // safe to fold to "object".
    3970           0 :             type = JSTYPE_OBJECT;
    3971           0 :             break;
    3972             :         }
    3973             :         MOZ_FALLTHROUGH;
    3974             :       default:
    3975           0 :         return this;
    3976             :     }
    3977             : 
    3978           0 :     return MConstant::New(alloc, StringValue(TypeName(type, GetJitContext()->runtime->names())));
    3979             : }
    3980             : 
    3981             : void
    3982           3 : MTypeOf::cacheInputMaybeCallableOrEmulatesUndefined(CompilerConstraintList* constraints)
    3983             : {
    3984           3 :     MOZ_ASSERT(inputMaybeCallableOrEmulatesUndefined());
    3985             : 
    3986           3 :     if (!input()->maybeEmulatesUndefined(constraints) && !MaybeCallable(constraints, input()))
    3987           3 :         markInputNotCallableOrEmulatesUndefined();
    3988           3 : }
    3989             : 
    3990             : MBitAnd*
    3991           0 : MBitAnd::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
    3992             : {
    3993           0 :     return new(alloc) MBitAnd(left, right, MIRType::Int32);
    3994             : }
    3995             : 
    3996             : MBitAnd*
    3997           0 : MBitAnd::New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
    3998             : {
    3999           0 :     MBitAnd* ins = new(alloc) MBitAnd(left, right, type);
    4000           0 :     ins->specializeAs(type);
    4001           0 :     return ins;
    4002             : }
    4003             : 
    4004             : MBitOr*
    4005           2 : MBitOr::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
    4006             : {
    4007           2 :     return new(alloc) MBitOr(left, right, MIRType::Int32);
    4008             : }
    4009             : 
    4010             : MBitOr*
    4011           0 : MBitOr::New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
    4012             : {
    4013           0 :     MBitOr* ins = new(alloc) MBitOr(left, right, type);
    4014           0 :     ins->specializeAs(type);
    4015           0 :     return ins;
    4016             : }
    4017             : 
    4018             : MBitXor*
    4019           0 : MBitXor::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
    4020             : {
    4021           0 :     return new(alloc) MBitXor(left, right, MIRType::Int32);
    4022             : }
    4023             : 
    4024             : MBitXor*
    4025           0 : MBitXor::New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
    4026             : {
    4027           0 :     MBitXor* ins = new(alloc) MBitXor(left, right, type);
    4028           0 :     ins->specializeAs(type);
    4029           0 :     return ins;
    4030             : }
    4031             : 
    4032             : MLsh*
    4033           0 : MLsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
    4034             : {
    4035           0 :     return new(alloc) MLsh(left, right, MIRType::Int32);
    4036             : }
    4037             : 
    4038             : MLsh*
    4039           0 : MLsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
    4040             : {
    4041           0 :     MLsh* ins = new(alloc) MLsh(left, right, type);
    4042           0 :     ins->specializeAs(type);
    4043           0 :     return ins;
    4044             : }
    4045             : 
    4046             : MRsh*
    4047           0 : MRsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
    4048             : {
    4049           0 :     return new(alloc) MRsh(left, right, MIRType::Int32);
    4050             : }
    4051             : 
    4052             : MRsh*
    4053           0 : MRsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
    4054             : {
    4055           0 :     MRsh* ins = new(alloc) MRsh(left, right, type);
    4056           0 :     ins->specializeAs(type);
    4057           0 :     return ins;
    4058             : }
    4059             : 
    4060             : MUrsh*
    4061           0 : MUrsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right)
    4062             : {
    4063           0 :     return new(alloc) MUrsh(left, right, MIRType::Int32);
    4064             : }
    4065             : 
    4066             : MUrsh*
    4067           0 : MUrsh::New(TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type)
    4068             : {
    4069           0 :     MUrsh* ins = new(alloc) MUrsh(left, right, type);
    4070           0 :     ins->specializeAs(type);
    4071             : 
    4072             :     // Since Ion has no UInt32 type, we use Int32 and we have a special
    4073             :     // exception to the type rules: we can return values in
    4074             :     // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
    4075             :     // without bailing out. This is necessary because Ion has no UInt32
    4076             :     // type and we can't have bailouts in wasm code.
    4077           0 :     ins->bailoutsDisabled_ = true;
    4078             : 
    4079           0 :     return ins;
    4080             : }
    4081             : 
    4082             : MResumePoint*
    4083        4503 : MResumePoint::New(TempAllocator& alloc, MBasicBlock* block, jsbytecode* pc,
    4084             :                   Mode mode)
    4085             : {
    4086        4503 :     MResumePoint* resume = new(alloc) MResumePoint(block, pc, mode);
    4087        4503 :     if (!resume->init(alloc)) {
    4088           0 :         block->discardPreAllocatedResumePoint(resume);
    4089           0 :         return nullptr;
    4090             :     }
    4091        4503 :     resume->inherit(block);
    4092        4503 :     return resume;
    4093             : }
    4094             : 
    4095             : MResumePoint*
    4096           0 : MResumePoint::New(TempAllocator& alloc, MBasicBlock* block, MResumePoint* model,
    4097             :                   const MDefinitionVector& operands)
    4098             : {
    4099           0 :     MResumePoint* resume = new(alloc) MResumePoint(block, model->pc(), model->mode());
    4100             : 
    4101             :     // Allocate the same number of operands as the original resume point, and
    4102             :     // copy operands from the operands vector and not the not from the current
    4103             :     // block stack.
    4104           0 :     if (!resume->operands_.init(alloc, model->numAllocatedOperands())) {
    4105           0 :         block->discardPreAllocatedResumePoint(resume);
    4106           0 :         return nullptr;
    4107             :     }
    4108             : 
    4109             :     // Copy the operands.
    4110           0 :     for (size_t i = 0; i < operands.length(); i++)
    4111           0 :         resume->initOperand(i, operands[i]);
    4112             : 
    4113           0 :     return resume;
    4114             : }
    4115             : 
    4116             : MResumePoint*
    4117         533 : MResumePoint::Copy(TempAllocator& alloc, MResumePoint* src)
    4118             : {
    4119         533 :     MResumePoint* resume = new(alloc) MResumePoint(src->block(), src->pc(),
    4120         533 :                                                    src->mode());
    4121             :     // Copy the operands from the original resume point, and not from the
    4122             :     // current block stack.
    4123         533 :     if (!resume->operands_.init(alloc, src->numAllocatedOperands())) {
    4124           0 :         src->block()->discardPreAllocatedResumePoint(resume);
    4125           0 :         return nullptr;
    4126             :     }
    4127             : 
    4128             :     // Copy the operands.
    4129        7422 :     for (size_t i = 0; i < resume->numOperands(); i++)
    4130        6889 :         resume->initOperand(i, src->getOperand(i));
    4131         533 :     return resume;
    4132             : }
    4133             : 
    4134        8996 : MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, Mode mode)
    4135             :   : MNode(block),
    4136             :     pc_(pc),
    4137             :     instruction_(nullptr),
    4138        8996 :     mode_(mode)
    4139             : {
    4140        8996 :     block->addResumePoint(this);
    4141        8996 : }
    4142             : 
    4143             : bool
    4144        8463 : MResumePoint::init(TempAllocator& alloc)
    4145             : {
    4146        8463 :     return operands_.init(alloc, block()->stackDepth());
    4147             : }
    4148             : 
    4149             : MResumePoint*
    4150         751 : MResumePoint::caller() const
    4151             : {
    4152         751 :     return block_->callerResumePoint();
    4153             : }
    4154             : 
    4155             : void
    4156        4503 : MResumePoint::inherit(MBasicBlock* block)
    4157             : {
    4158             :     // FixedList doesn't initialize its elements, so do unchecked inits.
    4159       62732 :     for (size_t i = 0; i < stackDepth(); i++)
    4160       58229 :         initOperand(i, block->getSlot(i));
    4161        4503 : }
    4162             : 
    4163             : void
    4164         658 : MResumePoint::addStore(TempAllocator& alloc, MDefinition* store, const MResumePoint* cache)
    4165             : {
    4166         658 :     MOZ_ASSERT(block()->outerResumePoint() != this);
    4167         658 :     MOZ_ASSERT_IF(cache, !cache->stores_.empty());
    4168             : 
    4169         658 :     if (cache && cache->stores_.begin()->operand == store) {
    4170             :         // If the last resume point had the same side-effect stack, then we can
    4171             :         // reuse the current side effect without cloning it. This is a simple
    4172             :         // way to share common context by making a spaghetti stack.
    4173         583 :         if (++cache->stores_.begin() == stores_.begin()) {
    4174         571 :             stores_.copy(cache->stores_);
    4175         571 :             return;
    4176             :         }
    4177             :     }
    4178             : 
    4179             :     // Ensure that the store would not be deleted by DCE.
    4180          87 :     MOZ_ASSERT(store->isEffectful());
    4181             : 
    4182          87 :     MStoreToRecover* top = new(alloc) MStoreToRecover(store);
    4183          87 :     stores_.push(top);
    4184             : }
    4185             : 
    4186             : void
    4187           0 : MResumePoint::dump(GenericPrinter& out) const
    4188             : {
    4189           0 :     out.printf("resumepoint mode=");
    4190             : 
    4191           0 :     switch (mode()) {
    4192             :       case MResumePoint::ResumeAt:
    4193           0 :         if (instruction_)
    4194           0 :             out.printf("At(%d)", instruction_->id());
    4195             :         else
    4196           0 :             out.printf("At");
    4197           0 :         break;
    4198             :       case MResumePoint::ResumeAfter:
    4199           0 :         out.printf("After");
    4200           0 :         break;
    4201             :       case MResumePoint::Outer:
    4202           0 :         out.printf("Outer");
    4203           0 :         break;
    4204             :     }
    4205             : 
    4206           0 :     if (MResumePoint* c = caller())
    4207           0 :         out.printf(" (caller in block%u)", c->block()->id());
    4208             : 
    4209           0 :     for (size_t i = 0; i < numOperands(); i++) {
    4210           0 :         out.printf(" ");
    4211           0 :         if (operands_[i].hasProducer())
    4212           0 :             getOperand(i)->printName(out);
    4213             :         else
    4214           0 :             out.printf("(null)");
    4215             :     }
    4216           0 :     out.printf("\n");
    4217           0 : }
    4218             : 
    4219             : void
    4220           0 : MResumePoint::dump() const
    4221             : {
    4222           0 :     Fprinter out(stderr);
    4223           0 :     dump(out);
    4224           0 :     out.finish();
    4225           0 : }
    4226             : 
    4227             : bool
    4228        9514 : MResumePoint::isObservableOperand(MUse* u) const
    4229             : {
    4230        9514 :     return isObservableOperand(indexOf(u));
    4231             : }
    4232             : 
    4233             : bool
    4234        9762 : MResumePoint::isObservableOperand(size_t index) const
    4235             : {
    4236        9762 :     return block()->info().isObservableSlot(index);
    4237             : }
    4238             : 
    4239             : bool
    4240        3957 : MResumePoint::isRecoverableOperand(MUse* u) const
    4241             : {
    4242        3957 :     return block()->info().isRecoverableOperand(indexOf(u));
    4243             : }
    4244             : 
    4245             : MDefinition*
    4246          14 : MToInt32::foldsTo(TempAllocator& alloc)
    4247             : {
    4248          14 :     MDefinition* input = getOperand(0);
    4249             : 
    4250             :     // Fold this operation if the input operand is constant.
    4251          14 :     if (input->isConstant()) {
    4252           1 :         DebugOnly<MacroAssembler::IntConversionInputKind> convert = conversion();
    4253           1 :         switch (input->type()) {
    4254             :           case MIRType::Null:
    4255           0 :             MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any);
    4256           0 :             return MConstant::New(alloc, Int32Value(0));
    4257             :           case MIRType::Boolean:
    4258           0 :             MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any ||
    4259             :                        convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
    4260           0 :             return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean()));
    4261             :           case MIRType::Int32:
    4262           1 :             return MConstant::New(alloc, Int32Value(input->toConstant()->toInt32()));
    4263             :           case MIRType::Float32:
    4264             :           case MIRType::Double:
    4265             :             int32_t ival;
    4266             :             // Only the value within the range of Int32 can be substituted as constant.
    4267           0 :             if (mozilla::NumberIsInt32(input->toConstant()->numberToDouble(), &ival))
    4268           0 :                 return MConstant::New(alloc, Int32Value(ival));
    4269           0 :             break;
    4270             :           default:
    4271           0 :             break;
    4272             :         }
    4273             :     }
    4274             : 
    4275             :     // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
    4276             :     // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
    4277             :     // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
    4278             :     // is folded to a MTruncateToInt32 node, which will result in this MIR:
    4279             :     // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
    4280             :     // the MUrsh node's type is int32 (since uint32 is not implemented), and
    4281             :     // that would fold the MTruncateToInt32 node. This will make the modulo
    4282             :     // unsigned, while is should have been signed.
    4283          13 :     if (input->type() == MIRType::Int32 && !IsUint32Type(input))
    4284          11 :         return input;
    4285             : 
    4286           2 :     return this;
    4287             : }
    4288             : 
    4289             : void
    4290           1 : MToInt32::analyzeEdgeCasesBackward()
    4291             : {
    4292           1 :     if (!NeedNegativeZeroCheck(this))
    4293           1 :         setCanBeNegativeZero(false);
    4294           1 : }
    4295             : 
    4296             : MDefinition*
    4297           6 : MTruncateToInt32::foldsTo(TempAllocator& alloc)
    4298             : {
    4299           6 :     MDefinition* input = getOperand(0);
    4300           6 :     if (input->isBox())
    4301           0 :         input = input->getOperand(0);
    4302             : 
    4303             :     // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
    4304             :     // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
    4305             :     // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
    4306             :     // is folded to a MTruncateToInt32 node, which will result in this MIR:
    4307             :     // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
    4308             :     // the MUrsh node's type is int32 (since uint32 is not implemented), and
    4309             :     // that would fold the MTruncateToInt32 node. This will make the modulo
    4310             :     // unsigned, while is should have been signed.
    4311           6 :     if (input->type() == MIRType::Int32 && !IsUint32Type(input))
    4312           2 :         return input;
    4313             : 
    4314           4 :     if (input->type() == MIRType::Double && input->isConstant()) {
    4315           0 :         int32_t ret = ToInt32(input->toConstant()->toDouble());
    4316           0 :         return MConstant::New(alloc, Int32Value(ret));
    4317             :     }
    4318             : 
    4319           4 :     return this;
    4320             : }
    4321             : 
    4322             : MDefinition*
    4323           0 : MWasmTruncateToInt32::foldsTo(TempAllocator& alloc)
    4324             : {
    4325           0 :     MDefinition* input = getOperand(0);
    4326           0 :     if (input->type() == MIRType::Int32)
    4327           0 :         return input;
    4328             : 
    4329           0 :     if (input->type() == MIRType::Double && input->isConstant()) {
    4330           0 :         double d = input->toConstant()->toDouble();
    4331           0 :         if (IsNaN(d))
    4332           0 :             return this;
    4333             : 
    4334           0 :         if (!isUnsigned_ && d <= double(INT32_MAX) && d >= double(INT32_MIN))
    4335           0 :             return MConstant::New(alloc, Int32Value(ToInt32(d)));
    4336             : 
    4337           0 :         if (isUnsigned_ && d <= double(UINT32_MAX) && d >= 0)
    4338           0 :             return MConstant::New(alloc, Int32Value(ToInt32(d)));
    4339             :     }
    4340             : 
    4341           0 :     if (input->type() == MIRType::Float32 && input->isConstant()) {
    4342           0 :         double f = double(input->toConstant()->toFloat32());
    4343           0 :         if (IsNaN(f))
    4344           0 :             return this;
    4345             : 
    4346           0 :         if (!isUnsigned_ && f <= double(INT32_MAX) && f >= double(INT32_MIN))
    4347           0 :             return MConstant::New(alloc, Int32Value(ToInt32(f)));
    4348             : 
    4349           0 :         if (isUnsigned_ && f <= double(UINT32_MAX) && f >= 0)
    4350           0 :             return MConstant::New(alloc, Int32Value(ToInt32(f)));
    4351             :     }
    4352             : 
    4353           0 :     return this;
    4354             : }
    4355             : 
    4356             : MDefinition*
    4357           0 : MWrapInt64ToInt32::foldsTo(TempAllocator& alloc)
    4358             : {
    4359           0 :     MDefinition* input = this->input();
    4360           0 :     if (input->isConstant()) {
    4361           0 :         uint64_t c = input->toConstant()->toInt64();
    4362           0 :         int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32);
    4363           0 :         return MConstant::New(alloc, Int32Value(output));
    4364             :     }
    4365             : 
    4366           0 :     return this;
    4367             : }
    4368             : 
    4369             : MDefinition*
    4370           0 : MExtendInt32ToInt64::foldsTo(TempAllocator& alloc)
    4371             : {
    4372           0 :     MDefinition* input = this->input();
    4373           0 :     if (input->isConstant()) {
    4374           0 :         int32_t c = input->toConstant()->toInt32();
    4375           0 :         int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c);
    4376           0 :         return MConstant::NewInt64(alloc, res);
    4377             :     }
    4378             : 
    4379           0 :     return this;
    4380             : }
    4381             : 
    4382             : MDefinition*
    4383           0 : MToDouble::foldsTo(TempAllocator& alloc)
    4384             : {
    4385           0 :     MDefinition* input = getOperand(0);
    4386           0 :     if (input->isBox())
    4387           0 :         input = input->getOperand(0);
    4388             : 
    4389           0 :     if (input->type() == MIRType::Double)
    4390           0 :         return input;
    4391             : 
    4392           0 :     if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble())
    4393           0 :         return MConstant::New(alloc, DoubleValue(input->toConstant()->numberToDouble()));
    4394             : 
    4395           0 :     return this;
    4396             : }
    4397             : 
    4398             : MDefinition*
    4399           0 : MToFloat32::foldsTo(TempAllocator& alloc)
    4400             : {
    4401           0 :     MDefinition* input = getOperand(0);
    4402           0 :     if (input->isBox())
    4403           0 :         input = input->getOperand(0);
    4404             : 
    4405           0 :     if (input->type() == MIRType::Float32)
    4406           0 :         return input;
    4407             : 
    4408             :     // If x is a Float32, Float32(Double(x)) == x
    4409           0 :     if (!mustPreserveNaN_ &&
    4410           0 :         input->isToDouble() &&
    4411           0 :         input->toToDouble()->input()->type() == MIRType::Float32)
    4412             :     {
    4413           0 :         return input->toToDouble()->input();
    4414             :     }
    4415             : 
    4416           0 :     if (input->isConstant() && input->toConstant()->isTypeRepresentableAsDouble())
    4417           0 :         return MConstant::NewFloat32(alloc, float(input->toConstant()->numberToDouble()));
    4418             : 
    4419           0 :     return this;
    4420             : }
    4421             : 
    4422             : MDefinition*
    4423           8 : MToString::foldsTo(TempAllocator& alloc)
    4424             : {
    4425           8 :     MDefinition* in = input();
    4426           8 :     if (in->isBox())
    4427           0 :         in = in->getOperand(0);
    4428             : 
    4429           8 :     if (in->type() == MIRType::String)
    4430           0 :         return in;
    4431           8 :     return this;
    4432             : }
    4433             : 
    4434             : MDefinition*
    4435           0 : MClampToUint8::foldsTo(TempAllocator& alloc)
    4436             : {
    4437           0 :     if (MConstant* inputConst = input()->maybeConstantValue()) {
    4438           0 :         if (inputConst->isTypeRepresentableAsDouble()) {
    4439           0 :             int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble());
    4440           0 :             return MConstant::New(alloc, Int32Value(clamped));
    4441             :         }
    4442             :     }
    4443           0 :     return this;
    4444             : }
    4445             : 
    4446             : bool
    4447         158 : MCompare::tryFoldEqualOperands(bool* result)
    4448             : {
    4449         158 :     if (lhs() != rhs())
    4450         154 :         return false;
    4451             : 
    4452             :     // Intuitively somebody would think that if lhs == rhs,
    4453             :     // then we can just return true. (Or false for !==)
    4454             :     // However NaN !== NaN is true! So we spend some time trying
    4455             :     // to eliminate this case.
    4456             : 
    4457           4 :     if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE)
    4458           1 :         return false;
    4459             : 
    4460           3 :     if (compareType_ == Compare_Unknown)
    4461           0 :         return false;
    4462             : 
    4463           3 :     MOZ_ASSERT(compareType_ == Compare_Undefined || compareType_ == Compare_Null ||
    4464             :                compareType_ == Compare_Boolean || compareType_ == Compare_Int32 ||
    4465             :                compareType_ == Compare_Int32MaybeCoerceBoth ||
    4466             :                compareType_ == Compare_Int32MaybeCoerceLHS ||
    4467             :                compareType_ == Compare_Int32MaybeCoerceRHS || compareType_ == Compare_UInt32 ||
    4468             :                compareType_ == Compare_Double || compareType_ == Compare_DoubleMaybeCoerceLHS ||
    4469             :                compareType_ == Compare_DoubleMaybeCoerceRHS || compareType_ == Compare_Float32 ||
    4470             :                compareType_ == Compare_String || compareType_ == Compare_StrictString ||
    4471             :                compareType_ == Compare_Object || compareType_ == Compare_Bitwise ||
    4472             :                compareType_ == Compare_Symbol);
    4473             : 
    4474           3 :     if (isDoubleComparison() || isFloat32Comparison()) {
    4475           0 :         if (!operandsAreNeverNaN())
    4476           0 :             return false;
    4477             :     }
    4478             : 
    4479           3 :     lhs()->setGuardRangeBailoutsUnchecked();
    4480             : 
    4481           3 :     *result = (jsop() == JSOP_STRICTEQ);
    4482           3 :     return true;
    4483             : }
    4484             : 
    4485             : bool
    4486         155 : MCompare::tryFoldTypeOf(bool* result)
    4487             : {
    4488         155 :     if (!lhs()->isTypeOf() && !rhs()->isTypeOf())
    4489         155 :         return false;
    4490           0 :     if (!lhs()->isConstant() && !rhs()->isConstant())
    4491           0 :         return false;
    4492             : 
    4493           0 :     MTypeOf* typeOf = lhs()->isTypeOf() ? lhs()->toTypeOf() : rhs()->toTypeOf();
    4494           0 :     MConstant* constant = lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
    4495             : 
    4496           0 :     if (constant->type() != MIRType::String)
    4497           0 :         return false;
    4498             : 
    4499           0 :     if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE &&
    4500           0 :         jsop() != JSOP_EQ && jsop() != JSOP_NE)
    4501             :     {
    4502           0 :         return false;
    4503             :     }
    4504             : 
    4505           0 :     const JSAtomState& names = GetJitContext()->runtime->names();
    4506           0 :     if (constant->toString() == TypeName(JSTYPE_UNDEFINED, names)) {
    4507           0 :         if (!typeOf->input()->mightBeType(MIRType::Undefined) &&
    4508           0 :             !typeOf->inputMaybeCallableOrEmulatesUndefined())
    4509             :         {
    4510           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4511           0 :             return true;
    4512             :         }
    4513           0 :     } else if (constant->toString() == TypeName(JSTYPE_BOOLEAN, names)) {
    4514           0 :         if (!typeOf->input()->mightBeType(MIRType::Boolean)) {
    4515           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4516           0 :             return true;
    4517             :         }
    4518           0 :     } else if (constant->toString() == TypeName(JSTYPE_NUMBER, names)) {
    4519           0 :         if (!typeOf->input()->mightBeType(MIRType::Int32) &&
    4520           0 :             !typeOf->input()->mightBeType(MIRType::Float32) &&
    4521           0 :             !typeOf->input()->mightBeType(MIRType::Double))
    4522             :         {
    4523           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4524           0 :             return true;
    4525             :         }
    4526           0 :     } else if (constant->toString() == TypeName(JSTYPE_STRING, names)) {
    4527           0 :         if (!typeOf->input()->mightBeType(MIRType::String)) {
    4528           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4529           0 :             return true;
    4530             :         }
    4531           0 :     } else if (constant->toString() == TypeName(JSTYPE_SYMBOL, names)) {
    4532           0 :         if (!typeOf->input()->mightBeType(MIRType::Symbol)) {
    4533           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4534           0 :             return true;
    4535             :         }
    4536           0 :     } else if (constant->toString() == TypeName(JSTYPE_OBJECT, names)) {
    4537           0 :         if (!typeOf->input()->mightBeType(MIRType::Object) &&
    4538           0 :             !typeOf->input()->mightBeType(MIRType::Null))
    4539             :         {
    4540           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4541           0 :             return true;
    4542             :         }
    4543           0 :     } else if (constant->toString() == TypeName(JSTYPE_FUNCTION, names)) {
    4544           0 :         if (!typeOf->inputMaybeCallableOrEmulatesUndefined()) {
    4545           0 :             *result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
    4546           0 :             return true;
    4547             :         }
    4548             :     }
    4549             : 
    4550           0 :     return false;
    4551             : }
    4552             : 
    4553             : bool
    4554         158 : MCompare::tryFold(bool* result)
    4555             : {
    4556         158 :     JSOp op = jsop();
    4557             : 
    4558         158 :     if (tryFoldEqualOperands(result))
    4559           3 :         return true;
    4560             : 
    4561         155 :     if (tryFoldTypeOf(result))
    4562           0 :         return true;
    4563             : 
    4564         155 :     if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
    4565             :         // The LHS is the value we want to test against null or undefined.
    4566           5 :         if (op == JSOP_STRICTEQ || op == JSOP_STRICTNE) {
    4567           4 :             if (lhs()->type() == inputType()) {
    4568           0 :                 *result = (op == JSOP_STRICTEQ);
    4569           0 :                 return true;
    4570             :             }
    4571           4 :             if (!lhs()->mightBeType(inputType())) {
    4572           4 :                 *result = (op == JSOP_STRICTNE);
    4573           4 :                 return true;
    4574             :             }
    4575             :         } else {
    4576           1 :             MOZ_ASSERT(op == JSOP_EQ || op == JSOP_NE);
    4577           1 :             if (IsNullOrUndefined(lhs()->type())) {
    4578           1 :                 *result = (op == JSOP_EQ);
    4579           1 :                 return true;
    4580             :             }
    4581           0 :             if (!lhs()->mightBeType(MIRType::Null) &&
    4582           0 :                 !lhs()->mightBeType(MIRType::Undefined) &&
    4583           0 :                 !(lhs()->mightBeType(MIRType::Object) && operandMightEmulateUndefined()))
    4584             :             {
    4585           0 :                 *result = (op == JSOP_NE);
    4586           0 :                 return true;
    4587             :             }
    4588             :         }
    4589           0 :         return false;
    4590             :     }
    4591             : 
    4592         150 :     if (compareType_ == Compare_Boolean) {
    4593           0 :         MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
    4594           0 :         MOZ_ASSERT(rhs()->type() == MIRType::Boolean);
    4595           0 :         MOZ_ASSERT(lhs()->type() != MIRType::Boolean, "Should use Int32 comparison");
    4596             : 
    4597           0 :         if (!lhs()->mightBeType(MIRType::Boolean)) {
    4598           0 :             *result = (op == JSOP_STRICTNE);
    4599           0 :             return true;
    4600             :         }
    4601           0 :         return false;
    4602             :     }
    4603             : 
    4604         150 :     if (compareType_ == Compare_StrictString) {
    4605           0 :         MOZ_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
    4606           0 :         MOZ_ASSERT(rhs()->type() == MIRType::String);
    4607           0 :         MOZ_ASSERT(lhs()->type() != MIRType::String, "Should use String comparison");
    4608             : 
    4609           0 :         if (!lhs()->mightBeType(MIRType::String)) {
    4610           0 :             *result = (op == JSOP_STRICTNE);
    4611           0 :             return true;
    4612             :         }
    4613           0 :         return false;
    4614             :     }
    4615             : 
    4616         150 :     return false;
    4617             : }
    4618             : 
    4619             : template <typename T>
    4620             : static bool
    4621           1 : FoldComparison(JSOp op, T left, T right)
    4622             : {
    4623           1 :     switch (op) {
    4624           0 :       case JSOP_LT: return left < right;
    4625           0 :       case JSOP_LE: return left <= right;
    4626           0 :       case JSOP_GT: return left > right;
    4627           0 :       case JSOP_GE: return left >= right;
    4628           1 :       case JSOP_STRICTEQ: case JSOP_EQ: return left == right;
    4629           0 :       case JSOP_STRICTNE: case JSOP_NE: return left != right;
    4630           0 :       default: MOZ_CRASH("Unexpected op.");
    4631             :     }
    4632             : }
    4633             : 
    4634             : bool
    4635          82 : MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result)
    4636             : {
    4637          82 :     if (type() != MIRType::Boolean && type() != MIRType::Int32)
    4638           0 :         return false;
    4639             : 
    4640          82 :     MDefinition* left = getOperand(0);
    4641          82 :     MDefinition* right = getOperand(1);
    4642             : 
    4643          82 :     if (compareType() == Compare_Double) {
    4644             :         // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range).
    4645             :         // In most cases the MToDouble was added, because the constant is
    4646             :         // a double.
    4647             :         // e.g. v < 9007199254740991, where v is an int32 is always true.
    4648           0 :         if (!lhs()->isConstant() && !rhs()->isConstant())
    4649           0 :             return false;
    4650             : 
    4651           0 :         MDefinition* operand = left->isConstant() ? right : left;
    4652           0 :         MConstant* constant = left->isConstant() ? left->toConstant() : right->toConstant();
    4653           0 :         MOZ_ASSERT(constant->type() == MIRType::Double);
    4654           0 :         double cte = constant->toDouble();
    4655             : 
    4656           0 :         if (operand->isToDouble() && operand->getOperand(0)->type() == MIRType::Int32) {
    4657           0 :             bool replaced = false;
    4658           0 :             switch (jsop_) {
    4659             :               case JSOP_LT:
    4660           0 :                 if (cte > INT32_MAX || cte < INT32_MIN) {
    4661           0 :                     *result = !((constant == lhs()) ^ (cte < INT32_MIN));
    4662           0 :                     replaced = true;
    4663             :                 }
    4664           0 :                 break;
    4665             :               case JSOP_LE:
    4666           0 :                 if (constant == lhs()) {
    4667           0 :                     if (cte > INT32_MAX || cte <= INT32_MIN) {
    4668           0 :                         *result = (cte <= INT32_MIN);
    4669           0 :                         replaced = true;
    4670             :                     }
    4671             :                 } else {
    4672           0 :                     if (cte >= INT32_MAX || cte < INT32_MIN) {
    4673           0 :                         *result = (cte >= INT32_MIN);
    4674           0 :                         replaced = true;
    4675             :                     }
    4676             :                 }
    4677           0 :                 break;
    4678             :               case JSOP_GT:
    4679           0 :                 if (cte > INT32_MAX || cte < INT32_MIN) {
    4680           0 :                     *result = !((constant == rhs()) ^ (cte < INT32_MIN));
    4681           0 :                     replaced = true;
    4682             :                 }
    4683           0 :                 break;
    4684             :               case JSOP_GE:
    4685           0 :                 if (constant == lhs()) {
    4686           0 :                     if (cte >= INT32_MAX || cte < INT32_MIN) {
    4687           0 :                         *result = (cte >= INT32_MAX);
    4688           0 :                         replaced = true;
    4689             :                     }
    4690             :                 } else {
    4691           0 :                     if (cte > INT32_MAX || cte <= INT32_MIN) {
    4692           0 :                         *result = (cte <= INT32_MIN);
    4693           0 :                         replaced = true;
    4694             :                     }
    4695             :                 }
    4696           0 :                 break;
    4697             :               case JSOP_STRICTEQ: // Fall through.
    4698             :               case JSOP_EQ:
    4699           0 :                 if (cte > INT32_MAX || cte < INT32_MIN) {
    4700           0 :                     *result = false;
    4701           0 :                     replaced = true;
    4702             :                 }
    4703           0 :                 break;
    4704             :               case JSOP_STRICTNE: // Fall through.
    4705             :               case JSOP_NE:
    4706           0 :                 if (cte > INT32_MAX || cte < INT32_MIN) {
    4707           0 :                     *result = true;
    4708           0 :                     replaced = true;
    4709             :                 }
    4710           0 :                 break;
    4711             :               default:
    4712           0 :                 MOZ_CRASH("Unexpected op.");
    4713             :             }
    4714           0 :             if (replaced) {
    4715             :                 MLimitedTruncate* limit =
    4716           0 :                     MLimitedTruncate::New(alloc, operand->getOperand(0), MDefinition::NoTruncate);
    4717           0 :                 limit->setGuardUnchecked();
    4718           0 :                 block()->insertBefore(this, limit);
    4719           0 :                 return true;
    4720             :             }
    4721             :         }
    4722             :     }
    4723             : 
    4724          82 :     if (!left->isConstant() || !right->isConstant())
    4725          81 :         return false;
    4726             : 
    4727           1 :     MConstant* lhs = left->toConstant();
    4728           1 :     MConstant* rhs = right->toConstant();
    4729             : 
    4730             :     // Fold away some String equality comparisons.
    4731           1 :     if (lhs->type() == MIRType::String && rhs->type() == MIRType::String) {
    4732           0 :         int32_t comp = 0; // Default to equal.
    4733           0 :         if (left != right)
    4734           0 :             comp = CompareAtoms(&lhs->toString()->asAtom(), &rhs->toString()->asAtom());
    4735           0 :         *result = FoldComparison(jsop_, comp, 0);
    4736           0 :         return true;
    4737             :     }
    4738             : 
    4739           1 :     if (compareType_ == Compare_UInt32) {
    4740           0 :         *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()), uint32_t(rhs->toInt32()));
    4741           0 :         return true;
    4742             :     }
    4743             : 
    4744           1 :     if (compareType_ == Compare_Int64) {
    4745           0 :         *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64());
    4746           0 :         return true;
    4747             :     }
    4748             : 
    4749           1 :     if (compareType_ == Compare_UInt64) {
    4750           0 :         *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()), uint64_t(rhs->toInt64()));
    4751           0 :         return true;
    4752             :     }
    4753             : 
    4754           1 :     if (lhs->isTypeRepresentableAsDouble() && rhs->isTypeRepresentableAsDouble()) {
    4755           1 :         *result = FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble());
    4756           1 :         return true;
    4757             :     }
    4758             : 
    4759           0 :     return false;
    4760             : }
    4761             : 
    4762             : MDefinition*
    4763          90 : MCompare::foldsTo(TempAllocator& alloc)
    4764             : {
    4765             :     bool result;
    4766             : 
    4767          90 :     if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) {
    4768           9 :         if (type() == MIRType::Int32)
    4769           0 :             return MConstant::New(alloc, Int32Value(result));
    4770             : 
    4771           9 :         MOZ_ASSERT(type() == MIRType::Boolean);
    4772           9 :         return MConstant::New(alloc, BooleanValue(result));
    4773             :     }
    4774             : 
    4775          81 :     return this;
    4776             : }
    4777             : 
    4778             : void
    4779           0 : MCompare::trySpecializeFloat32(TempAllocator& alloc)
    4780             : {
    4781           0 :     MDefinition* lhs = getOperand(0);
    4782           0 :     MDefinition* rhs = getOperand(1);
    4783             : 
    4784           0 :     if (lhs->canProduceFloat32() && rhs->canProduceFloat32() && compareType_ == Compare_Double) {
    4785           0 :         compareType_ = Compare_Float32;
    4786             :     } else {
    4787           0 :         if (lhs->type() == MIRType::Float32)
    4788           0 :             ConvertDefinitionToDouble<0>(alloc, lhs, this);
    4789           0 :         if (rhs->type() == MIRType::Float32)
    4790           0 :             ConvertDefinitionToDouble<1>(alloc, rhs, this);
    4791             :     }
    4792           0 : }
    4793             : 
    4794             : void
    4795           0 : MCompare::filtersUndefinedOrNull(bool trueBranch, MDefinition** subject, bool* filtersUndefined,
    4796             :                                  bool* filtersNull)
    4797             : {
    4798           0 :     *filtersNull = *filtersUndefined = false;
    4799           0 :     *subject = nullptr;
    4800             : 
    4801           0 :     if (compareType() != Compare_Undefined && compareType() != Compare_Null)
    4802           0 :         return;
    4803             : 
    4804           0 :     MOZ_ASSERT(jsop() == JSOP_STRICTNE || jsop() == JSOP_NE ||
    4805             :                jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ);
    4806             : 
    4807             :     // JSOP_*NE only removes undefined/null from if/true branch
    4808           0 :     if (!trueBranch && (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE))
    4809           0 :         return;
    4810             : 
    4811             :     // JSOP_*EQ only removes undefined/null from else/false branch
    4812           0 :     if (trueBranch && (jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ))
    4813           0 :         return;
    4814             : 
    4815           0 :     if (jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE) {
    4816           0 :         *filtersUndefined = compareType() == Compare_Undefined;
    4817           0 :         *filtersNull = compareType() == Compare_Null;
    4818             :     } else {
    4819           0 :         *filtersUndefined = *filtersNull = true;
    4820             :     }
    4821             : 
    4822           0 :     *subject = lhs();
    4823             : }
    4824             : 
    4825             : void
    4826         127 : MNot::cacheOperandMightEmulateUndefined(CompilerConstraintList* constraints)
    4827             : {
    4828         127 :     MOZ_ASSERT(operandMightEmulateUndefined());
    4829             : 
    4830         127 :     if (!getOperand(0)->maybeEmulatesUndefined(constraints))
    4831         127 :         markNoOperandEmulatesUndefined();
    4832         127 : }
    4833             : 
    4834             : MDefinition*
    4835          21 : MNot::foldsTo(TempAllocator& alloc)
    4836             : {
    4837             :     // Fold if the input is constant
    4838          21 :     if (MConstant* inputConst = input()->maybeConstantValue()) {
    4839             :         bool b;
    4840          11 :         if (inputConst->valueToBoolean(&b)) {
    4841          11 :             if (type() == MIRType::Int32 || type() == MIRType::Int64)
    4842           0 :                 return MConstant::New(alloc, Int32Value(!b));
    4843          11 :             return MConstant::New(alloc, BooleanValue(!b));
    4844             :         }
    4845             :     }
    4846             : 
    4847             :     // If the operand of the Not is itself a Not, they cancel out. But we can't
    4848             :     // always convert Not(Not(x)) to x because that may loose the conversion to
    4849             :     // boolean. We can simplify Not(Not(Not(x))) to Not(x) though.
    4850          10 :     MDefinition* op = getOperand(0);
    4851          10 :     if (op->isNot()) {
    4852           0 :         MDefinition* opop = op->getOperand(0);
    4853           0 :         if (opop->isNot())
    4854           0 :             return opop;
    4855             :     }
    4856             : 
    4857             :     // NOT of an undefined or null value is always true
    4858          10 :     if (input()->type() == MIRType::Undefined || input()->type() == MIRType::Null)
    4859           0 :         return MConstant::New(alloc, BooleanValue(true));
    4860             : 
    4861             :     // NOT of a symbol is always false.
    4862          10 :     if (input()->type() == MIRType::Symbol)
    4863           0 :         return MConstant::New(alloc, BooleanValue(false));
    4864             : 
    4865             :     // NOT of an object that can't emulate undefined is always false.
    4866          10 :     if (input()->type() == MIRType::Object && !operandMightEmulateUndefined())
    4867           0 :         return MConstant::New(alloc, BooleanValue(false));
    4868             : 
    4869          10 :     return this;
    4870             : }
    4871             : 
    4872             : void
    4873           0 : MNot::trySpecializeFloat32(TempAllocator& alloc)
    4874             : {
    4875           0 :     MDefinition* in = input();
    4876           0 :     if (!in->canProduceFloat32() && in->type() == MIRType::Float32)
    4877           0 :         ConvertDefinitionToDouble<0>(alloc, in, this);
    4878           0 : }
    4879             : 
    4880             : void
    4881           0 : MBeta::printOpcode(GenericPrinter& out) const
    4882             : {
    4883           0 :     MDefinition::printOpcode(out);
    4884             : 
    4885           0 :     out.printf(" ");
    4886           0 :     comparison_->dump(out);
    4887           0 : }
    4888             : 
    4889             : bool
    4890           0 : MCreateThisWithTemplate::canRecoverOnBailout() const
    4891             : {
    4892           0 :     MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
    4893           0 :     MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
    4894             :                   !templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
    4895           0 :     return true;
    4896             : }
    4897             : 
    4898             : bool
    4899           0 : OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject)
    4900             : {
    4901             :     const UnboxedLayout& layout =
    4902           0 :         templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
    4903             : 
    4904           0 :     const UnboxedLayout::PropertyVector& properties = layout.properties();
    4905           0 :     MOZ_ASSERT(properties.length() < 255);
    4906             : 
    4907             :     // Allocate an array of indexes, where the top of each field correspond to
    4908             :     // the index of the operand in the MObjectState instance.
    4909           0 :     if (!map.init(alloc, layout.size()))
    4910           0 :         return false;
    4911             : 
    4912             :     // Reset all indexes to 0, which is an error code.
    4913           0 :     for (size_t i = 0; i < map.length(); i++)
    4914           0 :         map[i] = 0;
    4915             : 
    4916             :     // Map the property offsets to the indexes of MObjectState operands.
    4917           0 :     uint8_t index = 1;
    4918           0 :     for (size_t i = 0; i < properties.length(); i++, index++)
    4919           0 :         map[properties[i].offset] = index;
    4920             : 
    4921           0 :     return true;
    4922             : }
    4923             : 
    4924          64 : MObjectState::MObjectState(MObjectState* state)
    4925          64 :   : numSlots_(state->numSlots_),
    4926          64 :     numFixedSlots_(state->numFixedSlots_),
    4927         192 :     operandIndex_(state->operandIndex_)
    4928             : {
    4929             :     // This instruction is only used as a summary for bailout paths.
    4930          64 :     setResultType(MIRType::Object);
    4931          64 :     setRecoveredOnBailout();
    4932          64 : }
    4933             : 
    4934           5 : MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex)
    4935             : {
    4936             :     // This instruction is only used as a summary for bailout paths.
    4937           5 :     setResultType(MIRType::Object);
    4938           5 :     setRecoveredOnBailout();
    4939             : 
    4940           5 :     if (templateObject->is<NativeObject>()) {
    4941           5 :         NativeObject* nativeObject = &templateObject->as<NativeObject>();
    4942           5 :         numSlots_ = nativeObject->slotSpan();
    4943           5 :         numFixedSlots_ = nativeObject->numFixedSlots();
    4944             :     } else {
    4945             :         const UnboxedLayout& layout =
    4946           0 :             templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
    4947             :         // Same as UnboxedLayout::makeNativeGroup
    4948           0 :         numSlots_ = layout.properties().length();
    4949           0 :         numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind());
    4950             :     }
    4951             : 
    4952           5 :     operandIndex_ = operandIndex;
    4953           5 : }
    4954             : 
    4955             : JSObject*
    4956          18 : MObjectState::templateObjectOf(MDefinition* obj)
    4957             : {
    4958          18 :     if (obj->isNewObject())
    4959          10 :         return obj->toNewObject()->templateObject();
    4960           8 :     else if (obj->isCreateThisWithTemplate())
    4961           0 :         return obj->toCreateThisWithTemplate()->templateObject();
    4962           8 :     else if (obj->isNewCallObject())
    4963           2 :         return obj->toNewCallObject()->templateObject();
    4964           6 :     else if (obj->isNewIterator())
    4965           6 :         return obj->toNewIterator()->templateObject();
    4966             : 
    4967           0 :     MOZ_CRASH("unreachable");
    4968             : }
    4969             : 
    4970             : bool
    4971          69 : MObjectState::init(TempAllocator& alloc, MDefinition* obj)
    4972             : {
    4973          69 :     if (!MVariadicInstruction::init(alloc, numSlots() + 1))
    4974           0 :         return false;
    4975             :     // +1, for the Object.
    4976          69 :     initOperand(0, obj);
    4977          69 :     return true;
    4978             : }
    4979             : 
    4980             : bool
    4981           5 : MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal)
    4982             : {
    4983           5 :     JSObject* templateObject = templateObjectOf(object());
    4984             : 
    4985             :     // Initialize all the slots of the object state with the value contained in
    4986             :     // the template object. This is needed to account values which are baked in
    4987             :     // the template objects and not visible in IonMonkey, such as the
    4988             :     // uninitialized-lexical magic value of call objects.
    4989           5 :     if (templateObject->is<UnboxedPlainObject>()) {
    4990           0 :         UnboxedPlainObject& unboxedObject = templateObject->as<UnboxedPlainObject>();
    4991           0 :         const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration();
    4992           0 :         const UnboxedLayout::PropertyVector& properties = layout.properties();
    4993             : 
    4994           0 :         for (size_t i = 0; i < properties.length(); i++) {
    4995           0 :             Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true);
    4996           0 :             MDefinition *def = undefinedVal;
    4997           0 :             if (!val.isUndefined()) {
    4998           0 :                 MConstant* ins = val.isObject() ?
    4999           0 :                     MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
    5000           0 :                     MConstant::New(alloc, val);
    5001           0 :                 block()->insertBefore(this, ins);
    5002           0 :                 def = ins;
    5003             :             }
    5004           0 :             initSlot(i, def);
    5005             :         }
    5006             :     } else {
    5007           5 :         NativeObject& nativeObject = templateObject->as<NativeObject>();
    5008           5 :         MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
    5009             : 
    5010          17 :         for (size_t i = 0; i < numSlots(); i++) {
    5011          12 :             Value val = nativeObject.getSlot(i);
    5012          12 :             MDefinition *def = undefinedVal;
    5013          12 :             if (!val.isUndefined()) {
    5014           0 :                 MConstant* ins = val.isObject() ?
    5015           0 :                     MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
    5016           0 :                     MConstant::New(alloc, val);
    5017           0 :                 block()->insertBefore(this, ins);
    5018           0 :                 def = ins;
    5019             :             }
    5020          12 :             initSlot(i, def);
    5021             :         }
    5022             :     }
    5023           5 :     return true;
    5024             : }
    5025             : 
    5026             : MObjectState*
    5027           5 : MObjectState::New(TempAllocator& alloc, MDefinition* obj)
    5028             : {
    5029           5 :     JSObject* templateObject = templateObjectOf(obj);
    5030           5 :     MOZ_ASSERT(templateObject, "Unexpected object creation.");
    5031             : 
    5032           5 :     OperandIndexMap* operandIndex = nullptr;
    5033           5 :     if (templateObject->is<UnboxedPlainObject>()) {
    5034           0 :         operandIndex = new(alloc) OperandIndexMap;
    5035           0 :         if (!operandIndex || !operandIndex->init(alloc, templateObject))
    5036           0 :             return nullptr;
    5037             :     }
    5038             : 
    5039           5 :     MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex);
    5040           5 :     if (!res || !res->init(alloc, obj))
    5041           0 :         return nullptr;
    5042           5 :     return res;
    5043             : }
    5044             : 
    5045             : MObjectState*
    5046          64 : MObjectState::Copy(TempAllocator& alloc, MObjectState* state)
    5047             : {
    5048          64 :     MObjectState* res = new(alloc) MObjectState(state);
    5049          64 :     if (!res || !res->init(alloc, state->object()))
    5050           0 :         return nullptr;
    5051         223 :     for (size_t i = 0; i < res->numSlots(); i++)
    5052         159 :         res->initSlot(i, state->getSlot(i));
    5053          64 :     return res;
    5054             : }
    5055             : 
    5056           0 : MArrayState::MArrayState(MDefinition* arr)
    5057             : {
    5058             :     // This instruction is only used as a summary for bailout paths.
    5059           0 :     setResultType(MIRType::Object);
    5060           0 :     setRecoveredOnBailout();
    5061           0 :     numElements_ = arr->toNewArray()->length();
    5062           0 : }
    5063             : 
    5064             : bool
    5065           0 : MArrayState::init(TempAllocator& alloc, MDefinition* obj, MDefinition* len)
    5066             : {
    5067           0 :     if (!MVariadicInstruction::init(alloc, numElements() + 2))
    5068           0 :         return false;
    5069             :     // +1, for the Array object.
    5070           0 :     initOperand(0, obj);
    5071             :     // +1, for the length value of the array.
    5072           0 :     initOperand(1, len);
    5073           0 :     return true;
    5074             : }
    5075             : 
    5076             : MArrayState*
    5077           0 : MArrayState::New(TempAllocator& alloc, MDefinition* arr, MDefinition* undefinedVal,
    5078             :                  MDefinition* initLength)
    5079             : {
    5080           0 :     MArrayState* res = new(alloc) MArrayState(arr);
    5081           0 :     if (!res || !res->init(alloc, arr, initLength))
    5082           0 :         return nullptr;
    5083           0 :     for (size_t i = 0; i < res->numElements(); i++)
    5084           0 :         res->initElement(i, undefinedVal);
    5085           0 :     return res;
    5086             : }
    5087             : 
    5088             : MArrayState*
    5089           0 : MArrayState::Copy(TempAllocator& alloc, MArrayState* state)
    5090             : {
    5091           0 :     MDefinition* arr = state->array();
    5092           0 :     MDefinition* len = state->initializedLength();
    5093           0 :     MArrayState* res = new(alloc) MArrayState(arr);
    5094           0 :     if (!res || !res->init(alloc, arr, len))
    5095           0 :         return nullptr;
    5096           0 :     for (size_t i = 0; i < res->numElements(); i++)
    5097           0 :         res->initElement(i, state->getElement(i));
    5098           0 :     return res;
    5099             : }
    5100             : 
    5101           9 : MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
    5102           9 :                      gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall)
    5103             :   : MUnaryInstruction(templateConst),
    5104             :     length_(length),
    5105             :     initialHeap_(initialHeap),
    5106             :     convertDoubleElements_(false),
    5107             :     pc_(pc),
    5108           9 :     vmCall_(vmCall)
    5109             : {
    5110           9 :     setResultType(MIRType::Object);
    5111           9 :     if (templateObject()) {
    5112           9 :         if (TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, templateObject())) {
    5113           9 :             setResultTypeSet(types);
    5114           9 :             if (types->convertDoubleElements(constraints) == TemporaryTypeSet::AlwaysConvertToDoubles)
    5115           0 :                 convertDoubleElements_ = true;
    5116             :         }
    5117             :     }
    5118           9 : }
    5119             : 
    5120             : MDefinition::AliasType
    5121         343 : MLoadFixedSlot::mightAlias(const MDefinition* def) const
    5122             : {
    5123         343 :     if (def->isStoreFixedSlot()) {
    5124         121 :         const MStoreFixedSlot* store = def->toStoreFixedSlot();
    5125         121 :         if (store->slot() != slot())
    5126         100 :             return AliasType::NoAlias;
    5127          21 :         if (store->object() != object())
    5128          18 :             return AliasType::MayAlias;
    5129           3 :         return AliasType::MustAlias;
    5130             :     }
    5131         222 :     return AliasType::MayAlias;
    5132             : }
    5133             : 
    5134             : MDefinition*
    5135          70 : MLoadFixedSlot::foldsTo(TempAllocator& alloc)
    5136             : {
    5137          70 :     if (MDefinition* def = foldsToStore(alloc))
    5138           0 :         return def;
    5139             : 
    5140          70 :     return this;
    5141             : }
    5142             : 
    5143             : MDefinition::AliasType
    5144           0 : MLoadFixedSlotAndUnbox::mightAlias(const MDefinition* def) const
    5145             : {
    5146           0 :     if (def->isStoreFixedSlot()) {
    5147           0 :         const MStoreFixedSlot* store = def->toStoreFixedSlot();
    5148           0 :         if (store->slot() != slot())
    5149           0 :             return AliasType::NoAlias;
    5150           0 :         if (store->object() != object())
    5151           0 :             return AliasType::MayAlias;
    5152           0 :         return AliasType::MustAlias;
    5153             :     }
    5154           0 :     return AliasType::MayAlias;
    5155             : }
    5156             : 
    5157             : MDefinition*
    5158           0 : MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc)
    5159             : {
    5160           0 :     if (MDefinition* def = foldsToStore(alloc))
    5161           0 :         return def;
    5162             : 
    5163           0 :     return this;
    5164             : }
    5165             : 
    5166             : MDefinition*
    5167           0 : MWasmAddOffset::foldsTo(TempAllocator& alloc)
    5168             : {
    5169           0 :     MDefinition* baseArg = base();
    5170           0 :     if (!baseArg->isConstant())
    5171           0 :         return this;
    5172             : 
    5173           0 :     MOZ_ASSERT(baseArg->type() == MIRType::Int32);
    5174           0 :     CheckedInt<uint32_t> ptr = baseArg->toConstant()->toInt32();
    5175             : 
    5176           0 :     ptr += offset();
    5177             : 
    5178           0 :     if (!ptr.isValid())
    5179           0 :         return this;
    5180             : 
    5181           0 :     return MConstant::New(alloc, Int32Value(ptr.value()));
    5182             : }
    5183             : 
    5184             : MDefinition::AliasType
    5185           0 : MAsmJSLoadHeap::mightAlias(const MDefinition* def) const
    5186             : {
    5187           0 :     if (def->isAsmJSStoreHeap()) {
    5188           0 :         const MAsmJSStoreHeap* store = def->toAsmJSStoreHeap();
    5189           0 :         if (store->accessType() != accessType())
    5190           0 :             return AliasType::MayAlias;
    5191           0 :         if (!base()->isConstant() || !store->base()->isConstant())
    5192           0 :             return AliasType::MayAlias;
    5193           0 :         const MConstant* otherBase = store->base()->toConstant();
    5194           0 :         if (base()->toConstant()->equals(otherBase) && offset() == store->offset())
    5195           0 :             return AliasType::MayAlias;
    5196           0 :         return AliasType::NoAlias;
    5197             :     }
    5198           0 :     return AliasType::MayAlias;
    5199             : }
    5200             : 
    5201             : bool
    5202           0 : MAsmJSLoadHeap::congruentTo(const MDefinition* ins) const
    5203             : {
    5204           0 :     if (!ins->isAsmJSLoadHeap())
    5205           0 :         return false;
    5206           0 :     const MAsmJSLoadHeap* load = ins->toAsmJSLoadHeap();
    5207           0 :     return load->accessType() == accessType() &&
    5208           0 :            load->offset() == offset() &&
    5209           0 :            congruentIfOperandsEqual(load);
    5210             : }
    5211             : 
    5212             : MDefinition::AliasType
    5213           0 : MWasmLoadGlobalVar::mightAlias(const MDefinition* def) const
    5214             : {
    5215           0 :     if (def->isWasmStoreGlobalVar()) {
    5216           0 :         const MWasmStoreGlobalVar* store = def->toWasmStoreGlobalVar();
    5217             :         // Global variables can't alias each other or be type-reinterpreted.
    5218           0 :         return (store->globalDataOffset() == globalDataOffset_) ? AliasType::MayAlias :
    5219           0 :                                                                   AliasType::NoAlias;
    5220             :     }
    5221           0 :     return AliasType::MayAlias;
    5222             : }
    5223             : 
    5224             : HashNumber
    5225           0 : MWasmLoadGlobalVar::valueHash() const
    5226             : {
    5227           0 :     HashNumber hash = MDefinition::valueHash();
    5228           0 :     hash = addU32ToHash(hash, globalDataOffset_);
    5229           0 :     return hash;
    5230             : }
    5231             : 
    5232             : bool
    5233           0 : MWasmLoadGlobalVar::congruentTo(const MDefinition* ins) const
    5234             : {
    5235           0 :     if (ins->isWasmLoadGlobalVar())
    5236           0 :         return globalDataOffset_ == ins->toWasmLoadGlobalVar()->globalDataOffset_;
    5237           0 :     return false;
    5238             : }
    5239             : 
    5240             : MDefinition*
    5241           0 : MWasmLoadGlobalVar::foldsTo(TempAllocator& alloc)
    5242             : {
    5243           0 :     if (!dependency() || !dependency()->isWasmStoreGlobalVar())
    5244           0 :         return this;
    5245             : 
    5246           0 :     MWasmStoreGlobalVar* store = dependency()->toWasmStoreGlobalVar();
    5247           0 :     if (!store->block()->dominates(block()))
    5248           0 :         return this;
    5249             : 
    5250           0 :     if (store->globalDataOffset() != globalDataOffset())
    5251           0 :         return this;
    5252             : 
    5253           0 :     if (store->value()->type() != type())
    5254           0 :         return this;
    5255             : 
    5256           0 :     return store->value();
    5257             : }
    5258             : 
    5259             : MDefinition::AliasType
    5260          45 : MLoadSlot::mightAlias(const MDefinition* def) const
    5261             : {
    5262          45 :     if (def->isStoreSlot()) {
    5263           0 :         const MStoreSlot* store = def->toStoreSlot();
    5264           0 :         if (store->slot() != slot())
    5265           0 :             return AliasType::NoAlias;
    5266             : 
    5267           0 :         if (store->slots() != slots())
    5268           0 :             return AliasType::MayAlias;
    5269             : 
    5270           0 :         return AliasType::MustAlias;
    5271             :     }
    5272          45 :     return AliasType::MayAlias;
    5273             : }
    5274             : 
    5275             : HashNumber
    5276          14 : MLoadSlot::valueHash() const
    5277             : {
    5278          14 :     HashNumber hash = MDefinition::valueHash();
    5279          14 :     hash = addU32ToHash(hash, slot_);
    5280          14 :     return hash;
    5281             : }
    5282             : 
    5283             : MDefinition*
    5284          13 : MLoadSlot::foldsTo(TempAllocator& alloc)
    5285             : {
    5286          13 :     if (MDefinition* def = foldsToStore(alloc))
    5287           0 :         return def;
    5288             : 
    5289          13 :     return this;
    5290             : }
    5291             : 
    5292             : void
    5293           0 : MLoadSlot::printOpcode(GenericPrinter& out) const
    5294             : {
    5295           0 :     MDefinition::printOpcode(out);
    5296           0 :     out.printf(" %d", slot());
    5297           0 : }
    5298             : 
    5299             : void
    5300           0 : MStoreSlot::printOpcode(GenericPrinter& out) const
    5301             : {
    5302           0 :     PrintOpcodeName(out, op());
    5303           0 :     out.printf(" ");
    5304           0 :     getOperand(0)->printName(out);
    5305           0 :     out.printf(" %d ", slot());
    5306           0 :     getOperand(1)->printName(out);
    5307           0 : }
    5308             : 
    5309             : MDefinition*
    5310          11 : MFunctionEnvironment::foldsTo(TempAllocator& alloc)
    5311             : {
    5312          11 :     if (!input()->isLambda())
    5313          11 :         return this;
    5314             : 
    5315           0 :     return input()->toLambda()->environmentChain();
    5316             : }
    5317             : 
    5318             : static bool
    5319           0 : AddIsANonZeroAdditionOf(MAdd* add, MDefinition* ins)
    5320             : {
    5321           0 :     if (add->lhs() != ins && add->rhs() != ins)
    5322           0 :         return false;
    5323           0 :     MDefinition* other = (add->lhs() == ins) ? add->rhs() : add->lhs();
    5324           0 :     if (!IsNumberType(other->type()))
    5325           0 :         return false;
    5326           0 :     if (!other->isConstant())
    5327           0 :         return false;
    5328           0 :     if (other->toConstant()->numberToDouble() == 0)
    5329           0 :         return false;
    5330           0 :     return true;
    5331             : }
    5332             : 
    5333             : static bool
    5334           0 : DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2)
    5335             : {
    5336           0 :     if (ins1 == ins2)
    5337           0 :         return false;
    5338             : 
    5339             :     // Drop the MToInt32 added by the TypePolicy for double and float values.
    5340           0 :     if (ins1->isToInt32())
    5341           0 :         return DefinitelyDifferentValue(ins1->toToInt32()->input(), ins2);
    5342           0 :     if (ins2->isToInt32())
    5343           0 :         return DefinitelyDifferentValue(ins2->toToInt32()->input(), ins1);
    5344             : 
    5345             :     // Ignore the bounds check, which in most cases will contain the same info.
    5346           0 :     if (ins1->isBoundsCheck())
    5347           0 :         return DefinitelyDifferentValue(ins1->toBoundsCheck()->index(), ins2);
    5348           0 :     if (ins2->isBoundsCheck())
    5349           0 :         return DefinitelyDifferentValue(ins2->toBoundsCheck()->index(), ins1);
    5350             : 
    5351             :     // For constants check they are not equal.
    5352           0 :     if (ins1->isConstant() && ins2->isConstant())
    5353           0 :         return !ins1->toConstant()->equals(ins2->toConstant());
    5354             : 
    5355             :     // Check if "ins1 = ins2 + cte", which would make both instructions
    5356             :     // have different values.
    5357           0 :     if (ins1->isAdd()) {
    5358           0 :         if (AddIsANonZeroAdditionOf(ins1->toAdd(), ins2))
    5359           0 :             return true;
    5360             :     }
    5361           0 :     if (ins2->isAdd()) {
    5362           0 :         if (AddIsANonZeroAdditionOf(ins2->toAdd(), ins1))
    5363           0 :             return true;
    5364             :     }
    5365             : 
    5366           0 :     return false;
    5367             : }
    5368             : 
    5369             : MDefinition::AliasType
    5370           4 : MLoadElement::mightAlias(const MDefinition* def) const
    5371             : {
    5372           4 :     if (def->isStoreElement()) {
    5373           0 :         const MStoreElement* store = def->toStoreElement();
    5374           0 :         if (store->index() != index()) {
    5375           0 :             if (DefinitelyDifferentValue(store->index(), index()))
    5376           0 :                 return AliasType::NoAlias;
    5377           0 :             return AliasType::MayAlias;
    5378             :         }
    5379             : 
    5380           0 :         if (store->elements() != elements())
    5381           0 :             return AliasType::MayAlias;
    5382             : 
    5383           0 :         return AliasType::MustAlias;
    5384             :     }
    5385           4 :     return AliasType::MayAlias;
    5386             : }
    5387             : 
    5388             : MDefinition*
    5389           1 : MLoadElement::foldsTo(TempAllocator& alloc)
    5390             : {
    5391           1 :     if (MDefinition* def = foldsToStore(alloc))
    5392           0 :         return def;
    5393             : 
    5394           1 :     return this;
    5395             : }
    5396             : 
    5397             : MDefinition::AliasType
    5398           0 : MLoadUnboxedObjectOrNull::mightAlias(const MDefinition* def) const
    5399             : {
    5400           0 :     if (def->isStoreUnboxedObjectOrNull()) {
    5401           0 :         const MStoreUnboxedObjectOrNull* store = def->toStoreUnboxedObjectOrNull();
    5402           0 :         if (store->index() != index()) {
    5403           0 :             if (DefinitelyDifferentValue(store->index(), index()))
    5404           0 :                 return AliasType::NoAlias;
    5405           0 :             return AliasType::MayAlias;
    5406             :         }
    5407             : 
    5408           0 :         if (store->elements() != elements())
    5409           0 :             return AliasType::MayAlias;
    5410             : 
    5411           0 :         if (store->offsetAdjustment() != offsetAdjustment())
    5412           0 :             return AliasType::MayAlias;
    5413             : 
    5414           0 :         return AliasType::MustAlias;
    5415             :     }
    5416           0 :     return AliasType::MayAlias;
    5417             : }
    5418             : 
    5419             : MDefinition*
    5420           0 : MLoadUnboxedObjectOrNull::foldsTo(TempAllocator& alloc)
    5421             : {
    5422           0 :     if (MDefinition* def = foldsToStore(alloc))
    5423           0 :         return def;
    5424             : 
    5425           0 :     return this;
    5426             : }
    5427             : 
    5428             : bool
    5429           0 : MGuardReceiverPolymorphic::congruentTo(const MDefinition* ins) const
    5430             : {
    5431           0 :     if (!ins->isGuardReceiverPolymorphic())
    5432           0 :         return false;
    5433             : 
    5434           0 :     const MGuardReceiverPolymorphic* other = ins->toGuardReceiverPolymorphic();
    5435             : 
    5436           0 :     if (numReceivers() != other->numReceivers())
    5437           0 :         return false;
    5438           0 :     for (size_t i = 0; i < numReceivers(); i++) {
    5439           0 :         if (receiver(i) != other->receiver(i))
    5440           0 :             return false;
    5441             :     }
    5442             : 
    5443           0 :     return congruentIfOperandsEqual(ins);
    5444             : }
    5445             : 
    5446             : void
    5447           0 : InlinePropertyTable::trimTo(const InliningTargets& targets, const BoolVector& choiceSet)
    5448             : {
    5449           0 :     for (size_t i = 0; i < targets.length(); i++) {
    5450             :         // If the target was inlined, don't erase the entry.
    5451           0 :         if (choiceSet[i])
    5452           0 :             continue;
    5453             : 
    5454             :         // If the target wasn't a function we would have veto'ed it
    5455             :         // and it will not be in the entries list.
    5456           0 :         if (!targets[i].target->is<JSFunction>())
    5457           0 :             continue;
    5458             : 
    5459           0 :         JSFunction* target = &targets[i].target->as<JSFunction>();
    5460             : 
    5461             :         // Eliminate all entries containing the vetoed function from the map.
    5462           0 :         size_t j = 0;
    5463           0 :         while (j < numEntries()) {
    5464           0 :             if (entries_[j]->func == target)
    5465           0 :                 entries_.erase(&entries_[j]);
    5466             :             else
    5467           0 :                 j++;
    5468             :         }
    5469             :     }
    5470           0 : }
    5471             : 
    5472             : void
    5473           0 : InlinePropertyTable::trimToTargets(const InliningTargets& targets)
    5474             : {
    5475           0 :     JitSpew(JitSpew_Inlining, "Got inlineable property cache with %d cases",
    5476           0 :             (int)numEntries());
    5477             : 
    5478           0 :     size_t i = 0;
    5479           0 :     while (i < numEntries()) {
    5480           0 :         bool foundFunc = false;
    5481           0 :         for (size_t j = 0; j < targets.length(); j++) {
    5482           0 :             if (entries_[i]->func == targets[j].target) {
    5483           0 :                 foundFunc = true;
    5484           0 :                 break;
    5485             :             }
    5486             :         }
    5487           0 :         if (!foundFunc)
    5488           0 :             entries_.erase(&(entries_[i]));
    5489             :         else
    5490           0 :             i++;
    5491             :     }
    5492             : 
    5493           0 :     JitSpew(JitSpew_Inlining, "%d inlineable cases left after trimming to %d targets",
    5494           0 :             (int)numEntries(), (int)targets.length());
    5495           0 : }
    5496             : 
    5497             : bool
    5498           0 : InlinePropertyTable::hasFunction(JSFunction* func) const
    5499             : {
    5500           0 :     for (size_t i = 0; i < numEntries(); i++) {
    5501           0 :         if (entries_[i]->func == func)
    5502           0 :             return true;
    5503             :     }
    5504           0 :     return false;
    5505             : }
    5506             : 
    5507             : bool
    5508           0 : InlinePropertyTable::hasObjectGroup(ObjectGroup* group) const
    5509             : {
    5510           0 :     for (size_t i = 0; i < numEntries(); i++) {
    5511           0 :         if (entries_[i]->group == group)
    5512           0 :             return true;
    5513             :     }
    5514           0 :     return false;
    5515             : }
    5516             : 
    5517             : TemporaryTypeSet*
    5518           0 : InlinePropertyTable::buildTypeSetForFunction(JSFunction* func) const
    5519             : {
    5520           0 :     LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc();
    5521           0 :     TemporaryTypeSet* types = alloc->new_<TemporaryTypeSet>();
    5522           0 :     if (!types)
    5523           0 :         return nullptr;
    5524           0 :     for (size_t i = 0; i < numEntries(); i++) {
    5525           0 :         if (entries_[i]->func == func)
    5526           0 :             types->addType(TypeSet::ObjectType(entries_[i]->group), alloc);
    5527             :     }
    5528           0 :     return types;
    5529             : }
    5530             : 
    5531             : bool
    5532           0 : InlinePropertyTable::appendRoots(MRootList& roots) const
    5533             : {
    5534           0 :     for (const Entry* entry : entries_) {
    5535           0 :         if (!entry->appendRoots(roots))
    5536           0 :             return false;
    5537             :     }
    5538           0 :     return true;
    5539             : }
    5540             : 
    5541             : SharedMem<void*>
    5542           0 : MLoadTypedArrayElementStatic::base() const
    5543             : {
    5544           0 :     return someTypedArray_->as<TypedArrayObject>().viewDataEither();
    5545             : }
    5546             : 
    5547             : size_t
    5548           0 : MLoadTypedArrayElementStatic::length() const
    5549             : {
    5550           0 :     return someTypedArray_->as<TypedArrayObject>().byteLength();
    5551             : }
    5552             : 
    5553             : bool
    5554           0 : MLoadTypedArrayElementStatic::congruentTo(const MDefinition* ins) const
    5555             : {
    5556           0 :     if (!ins->isLoadTypedArrayElementStatic())
    5557           0 :         return false;
    5558           0 :     const MLoadTypedArrayElementStatic* other = ins->toLoadTypedArrayElementStatic();
    5559           0 :     if (offset() != other->offset())
    5560           0 :         return false;
    5561           0 :     if (needsBoundsCheck() != other->needsBoundsCheck())
    5562           0 :         return false;
    5563           0 :     if (accessType() != other->accessType())
    5564           0 :         return false;
    5565           0 :     if (base() != other->base())
    5566           0 :         return false;
    5567           0 :     return congruentIfOperandsEqual(other);
    5568             : }
    5569             : 
    5570             : SharedMem<void*>
    5571           0 : MStoreTypedArrayElementStatic::base() const
    5572             : {
    5573           0 :     return someTypedArray_->as<TypedArrayObject>().viewDataEither();
    5574             : }
    5575             : 
    5576             : bool
    5577          23 : MGetPropertyCache::allowDoubleResult() const
    5578             : {
    5579          23 :     if (!resultTypeSet())
    5580          17 :         return true;
    5581             : 
    5582           6 :     return resultTypeSet()->hasType(TypeSet::DoubleType());
    5583             : }
    5584             : 
    5585             : size_t
    5586           0 : MStoreTypedArrayElementStatic::length() const
    5587             : {
    5588           0 :     return someTypedArray_->as<TypedArrayObject>().byteLength();
    5589             : }
    5590             : 
    5591             : MDefinition::AliasType
    5592           0 : MGetPropertyPolymorphic::mightAlias(const MDefinition* store) const
    5593             : {
    5594             :     // Allow hoisting this instruction if the store does not write to a
    5595             :     // slot read by this instruction.
    5596             : 
    5597           0 :     if (!store->isStoreFixedSlot() && !store->isStoreSlot())
    5598           0 :         return AliasType::MayAlias;
    5599             : 
    5600           0 :     for (size_t i = 0; i < numReceivers(); i++) {
    5601           0 :         const Shape* shape = this->shape(i);
    5602           0 :         if (!shape)
    5603           0 :             continue;
    5604           0 :         if (shape->slot() < shape->numFixedSlots()) {
    5605             :             // Fixed slot.
    5606           0 :             uint32_t slot = shape->slot();
    5607           0 :             if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot)
    5608           0 :                 continue;
    5609           0 :             if (store->isStoreSlot())
    5610           0 :                 continue;
    5611             :         } else {
    5612             :             // Dynamic slot.
    5613           0 :             uint32_t slot = shape->slot() - shape->numFixedSlots();
    5614           0 :             if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot)
    5615           0 :                 continue;
    5616           0 :             if (store->isStoreFixedSlot())
    5617           0 :                 continue;
    5618             :         }
    5619             : 
    5620           0 :         return AliasType::MayAlias;
    5621             :     }
    5622             : 
    5623           0 :     return AliasType::NoAlias;
    5624             : }
    5625             : 
    5626             : bool
    5627           0 : MGetPropertyPolymorphic::appendRoots(MRootList& roots) const
    5628             : {
    5629           0 :     if (!roots.append(name_))
    5630           0 :         return false;
    5631             : 
    5632           0 :     for (const PolymorphicEntry& entry : receivers_) {
    5633           0 :         if (!entry.appendRoots(roots))
    5634           0 :             return false;
    5635             :     }
    5636             : 
    5637           0 :     return true;
    5638             : }
    5639             : 
    5640             : bool
    5641           0 : MSetPropertyPolymorphic::appendRoots(MRootList& roots) const
    5642             : {
    5643           0 :     if (!roots.append(name_))
    5644           0 :         return false;
    5645             : 
    5646           0 :     for (const PolymorphicEntry& entry : receivers_) {
    5647           0 :         if (!entry.appendRoots(roots))
    5648           0 :             return false;
    5649             :     }
    5650             : 
    5651           0 :     return true;
    5652             : }
    5653             : 
    5654             : bool
    5655           0 : MGuardReceiverPolymorphic::appendRoots(MRootList& roots) const
    5656             : {
    5657           0 :     for (const ReceiverGuard& guard : receivers_) {
    5658           0 :         if (!roots.append(guard))
    5659           0 :             return false;
    5660             :     }
    5661           0 :     return true;
    5662             : }
    5663             : 
    5664             : bool
    5665           3 : MDispatchInstruction::appendRoots(MRootList& roots) const
    5666             : {
    5667           6 :     for (const Entry& entry : map_) {
    5668           3 :         if (!entry.appendRoots(roots))
    5669           0 :             return false;
    5670             :     }
    5671           3 :     return true;
    5672             : }
    5673             : 
    5674             : bool
    5675           0 : MObjectGroupDispatch::appendRoots(MRootList& roots) const
    5676             : {
    5677           0 :     if (inlinePropertyTable_ && !inlinePropertyTable_->appendRoots(roots))
    5678           0 :         return false;
    5679           0 :     return MDispatchInstruction::appendRoots(roots);
    5680             : }
    5681             : 
    5682             : bool
    5683           3 : MFunctionDispatch::appendRoots(MRootList& roots) const
    5684             : {
    5685           3 :     return MDispatchInstruction::appendRoots(roots);
    5686             : }
    5687             : 
    5688             : bool
    5689         704 : MConstant::appendRoots(MRootList& roots) const
    5690             : {
    5691         704 :     switch (type()) {
    5692             :       case MIRType::String:
    5693          56 :         return roots.append(toString());
    5694             :       case MIRType::Symbol:
    5695           2 :         return roots.append(toSymbol());
    5696             :       case MIRType::Object:
    5697         190 :         return roots.append(&toObject());
    5698             :       case MIRType::Undefined:
    5699             :       case MIRType::Null:
    5700             :       case MIRType::Boolean:
    5701             :       case MIRType::Int32:
    5702             :       case MIRType::Double:
    5703             :       case MIRType::Float32:
    5704             :       case MIRType::MagicOptimizedArguments:
    5705             :       case MIRType::MagicOptimizedOut:
    5706             :       case MIRType::MagicHole:
    5707             :       case MIRType::MagicIsConstructing:
    5708             :       case MIRType::MagicUninitializedLexical:
    5709         456 :         return true;
    5710             :       default:
    5711           0 :         MOZ_CRASH("Unexpected type");
    5712             :     }
    5713             : }
    5714             : 
    5715             : MDefinition*
    5716           0 : MWasmUnsignedToDouble::foldsTo(TempAllocator& alloc)
    5717             : {
    5718           0 :     if (input()->isConstant() && input()->type() == MIRType::Int32)
    5719           0 :         return MConstant::New(alloc, DoubleValue(uint32_t(input()->toConstant()->toInt32())));
    5720             : 
    5721           0 :     return this;
    5722             : }
    5723             : 
    5724             : MDefinition*
    5725           0 : MWasmUnsignedToFloat32::foldsTo(TempAllocator& alloc)
    5726             : {
    5727           0 :     if (input()->isConstant() && input()->type() == MIRType::Int32) {
    5728           0 :         double dval = double(uint32_t(input()->toConstant()->toInt32()));
    5729           0 :         if (IsFloat32Representable(dval))
    5730           0 :             return MConstant::NewFloat32(alloc, float(dval));
    5731             :     }
    5732             : 
    5733           0 :     return this;
    5734             : }
    5735             : 
    5736             : MWasmCall*
    5737           0 : MWasmCall::New(TempAllocator& alloc, const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee,
    5738             :                const Args& args, MIRType resultType, uint32_t spIncrement, MDefinition* tableIndex)
    5739             : {
    5740           0 :     MWasmCall* call = new(alloc) MWasmCall(desc, callee, spIncrement);
    5741           0 :     call->setResultType(resultType);
    5742             : 
    5743           0 :     if (!call->argRegs_.init(alloc, args.length()))
    5744           0 :         return nullptr;
    5745           0 :     for (size_t i = 0; i < call->argRegs_.length(); i++)
    5746           0 :         call->argRegs_[i] = args[i].reg;
    5747             : 
    5748           0 :     if (!call->init(alloc, call->argRegs_.length() + (callee.isTable() ? 1 : 0)))
    5749           0 :         return nullptr;
    5750             :     // FixedList doesn't initialize its elements, so do an unchecked init.
    5751           0 :     for (size_t i = 0; i < call->argRegs_.length(); i++)
    5752           0 :         call->initOperand(i, args[i].def);
    5753           0 :     if (callee.isTable())
    5754           0 :         call->initOperand(call->argRegs_.length(), tableIndex);
    5755             : 
    5756           0 :     return call;
    5757             : }
    5758             : 
    5759             : MWasmCall*
    5760           0 : MWasmCall::NewBuiltinInstanceMethodCall(TempAllocator& alloc,
    5761             :                                         const wasm::CallSiteDesc& desc,
    5762             :                                         const wasm::SymbolicAddress builtin,
    5763             :                                         const ABIArg& instanceArg,
    5764             :                                         const Args& args,
    5765             :                                         MIRType resultType,
    5766             :                                         uint32_t spIncrement)
    5767             : {
    5768           0 :     auto callee = wasm::CalleeDesc::builtinInstanceMethod(builtin);
    5769           0 :     MWasmCall* call = MWasmCall::New(alloc, desc, callee, args, resultType, spIncrement, nullptr);
    5770           0 :     if (!call)
    5771           0 :         return nullptr;
    5772             : 
    5773           0 :     MOZ_ASSERT(instanceArg != ABIArg());
    5774           0 :     call->instanceArg_ = instanceArg;
    5775           0 :     return call;
    5776             : }
    5777             : 
    5778             : void
    5779           0 : MSqrt::trySpecializeFloat32(TempAllocator& alloc) {
    5780           0 :     if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
    5781           0 :         if (input()->type() == MIRType::Float32)
    5782           0 :             ConvertDefinitionToDouble<0>(alloc, input(), this);
    5783           0 :         return;
    5784             :     }
    5785             : 
    5786           0 :     setResultType(MIRType::Float32);
    5787           0 :     specialization_ = MIRType::Float32;
    5788             : }
    5789             : 
    5790             : MDefinition*
    5791           0 : MClz::foldsTo(TempAllocator& alloc)
    5792             : {
    5793           0 :     if (num()->isConstant()) {
    5794           0 :         MConstant* c = num()->toConstant();
    5795           0 :         if (type() == MIRType::Int32) {
    5796           0 :             int32_t n = c->toInt32();
    5797           0 :             if (n == 0)
    5798           0 :                 return MConstant::New(alloc, Int32Value(32));
    5799           0 :             return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n)));
    5800             :         }
    5801           0 :         int64_t n = c->toInt64();
    5802           0 :         if (n == 0)
    5803           0 :             return MConstant::NewInt64(alloc, int64_t(64));
    5804           0 :         return MConstant::NewInt64(alloc, int64_t(mozilla::CountLeadingZeroes64(n)));
    5805             :     }
    5806             : 
    5807           0 :     return this;
    5808             : }
    5809             : 
    5810             : MDefinition*
    5811           0 : MCtz::foldsTo(TempAllocator& alloc)
    5812             : {
    5813           0 :     if (num()->isConstant()) {
    5814           0 :         MConstant* c = num()->toConstant();
    5815           0 :         if (type() == MIRType::Int32) {
    5816           0 :             int32_t n = num()->toConstant()->toInt32();
    5817           0 :             if (n == 0)
    5818           0 :                 return MConstant::New(alloc, Int32Value(32));
    5819           0 :             return MConstant::New(alloc, Int32Value(mozilla::CountTrailingZeroes32(n)));
    5820             :         }
    5821           0 :         int64_t n = c->toInt64();
    5822           0 :         if (n == 0)
    5823           0 :             return MConstant::NewInt64(alloc, int64_t(64));
    5824           0 :         return MConstant::NewInt64(alloc, int64_t(mozilla::CountTrailingZeroes64(n)));
    5825             :     }
    5826             : 
    5827           0 :     return this;
    5828             : }
    5829             : 
    5830             : MDefinition*
    5831           0 : MPopcnt::foldsTo(TempAllocator& alloc)
    5832             : {
    5833           0 :     if (num()->isConstant()) {
    5834           0 :         MConstant* c = num()->toConstant();
    5835           0 :         if (type() == MIRType::Int32) {
    5836           0 :             int32_t n = num()->toConstant()->toInt32();
    5837           0 :             return MConstant::New(alloc, Int32Value(mozilla::CountPopulation32(n)));
    5838             :         }
    5839           0 :         int64_t n = c->toInt64();
    5840           0 :         return MConstant::NewInt64(alloc, int64_t(mozilla::CountPopulation64(n)));
    5841             :     }
    5842             : 
    5843           0 :     return this;
    5844             : }
    5845             : 
    5846             : MDefinition*
    5847           8 : MBoundsCheck::foldsTo(TempAllocator& alloc)
    5848             : {
    5849           8 :     if (index()->isConstant() && length()->isConstant()) {
    5850           0 :         uint32_t len = length()->toConstant()->toInt32();
    5851           0 :         uint32_t idx = index()->toConstant()->toInt32();
    5852           0 :         if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len)
    5853           0 :             return index();
    5854             :     }
    5855             : 
    5856           8 :     return this;
    5857             : }
    5858             : 
    5859             : MDefinition*
    5860           0 : MTableSwitch::foldsTo(TempAllocator& alloc)
    5861             : {
    5862           0 :     MDefinition* op = getOperand(0);
    5863             : 
    5864             :     // If we only have one successor, convert to a plain goto to the only
    5865             :     // successor. TableSwitch indices are numeric; other types will always go to
    5866             :     // the only successor.
    5867           0 :     if (numSuccessors() == 1 || (op->type() != MIRType::Value && !IsNumberType(op->type())))
    5868           0 :         return MGoto::New(alloc, getDefault());
    5869             : 
    5870           0 :     if (MConstant* opConst = op->maybeConstantValue()) {
    5871           0 :         if (op->type() == MIRType::Int32) {
    5872           0 :             int32_t i = opConst->toInt32() - low_;
    5873             :             MBasicBlock* target;
    5874           0 :             if (size_t(i) < numCases())
    5875           0 :                 target = getCase(size_t(i));
    5876             :             else
    5877           0 :                 target = getDefault();
    5878           0 :             MOZ_ASSERT(target);
    5879           0 :             return MGoto::New(alloc, target);
    5880             :         }
    5881             :     }
    5882             : 
    5883           0 :     return this;
    5884             : }
    5885             : 
    5886             : MDefinition*
    5887           2 : MArrayJoin::foldsTo(TempAllocator& alloc)
    5888             : {
    5889           2 :     MDefinition* arr = array();
    5890             : 
    5891           2 :     if (!arr->isStringSplit())
    5892           2 :         return this;
    5893             : 
    5894           0 :     setRecoveredOnBailout();
    5895           0 :     if (arr->hasLiveDefUses()) {
    5896           0 :         setNotRecoveredOnBailout();
    5897           0 :         return this;
    5898             :     }
    5899             : 
    5900             :     // The MStringSplit won't generate any code.
    5901           0 :     arr->setRecoveredOnBailout();
    5902             : 
    5903             :     // We're replacing foo.split(bar).join(baz) by
    5904             :     // foo.replace(bar, baz).  MStringSplit could be recovered by
    5905             :     // a bailout.  As we are removing its last use, and its result
    5906             :     // could be captured by a resume point, this MStringSplit will
    5907             :     // be executed on the bailout path.
    5908           0 :     MDefinition* string = arr->toStringSplit()->string();
    5909           0 :     MDefinition* pattern = arr->toStringSplit()->separator();
    5910           0 :     MDefinition* replacement = sep();
    5911             : 
    5912           0 :     MStringReplace *substr = MStringReplace::New(alloc, string, pattern, replacement);
    5913           0 :     substr->setFlatReplacement();
    5914           0 :     return substr;
    5915             : }
    5916             : 
    5917             : MDefinition*
    5918           0 : MGetFirstDollarIndex::foldsTo(TempAllocator& alloc)
    5919             : {
    5920           0 :     MDefinition* strArg = str();
    5921           0 :     if (!strArg->isConstant())
    5922           0 :         return this;
    5923             : 
    5924           0 :     JSAtom* atom = &strArg->toConstant()->toString()->asAtom();
    5925           0 :     int32_t index = GetFirstDollarIndexRawFlat(atom);
    5926           0 :     return MConstant::New(alloc, Int32Value(index));
    5927             : }
    5928             : 
    5929             : MConvertUnboxedObjectToNative*
    5930           0 : MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group)
    5931             : {
    5932           0 :     MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group);
    5933             : 
    5934           0 :     ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup();
    5935             : 
    5936             :     // Make a new type set for the result of this instruction which replaces
    5937             :     // the input group with the native group we will convert it to.
    5938           0 :     TemporaryTypeSet* types = obj->resultTypeSet();
    5939           0 :     if (types && !types->unknownObject()) {
    5940           0 :         TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc());
    5941           0 :         if (newTypes) {
    5942           0 :             for (size_t i = 0; i < types->getObjectCount(); i++) {
    5943           0 :                 TypeSet::ObjectKey* key = types->getObject(i);
    5944           0 :                 if (!key)
    5945           0 :                     continue;
    5946           0 :                 if (key->unknownProperties() || !key->isGroup() || key->group() != group)
    5947           0 :                     newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc());
    5948             :                 else
    5949           0 :                     newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc());
    5950             :             }
    5951           0 :             res->setResultTypeSet(newTypes);
    5952             :         }
    5953             :     }
    5954             : 
    5955           0 :     return res;
    5956             : }
    5957             : 
    5958             : bool
    5959         172 : jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
    5960             :                                 MDefinition* obj, MDefinition* id)
    5961             : {
    5962         172 :     if (obj->mightBeType(MIRType::String))
    5963           3 :         return false;
    5964             : 
    5965         169 :     if (id->type() != MIRType::Int32 && id->type() != MIRType::Double)
    5966           9 :         return false;
    5967             : 
    5968         160 :     TemporaryTypeSet* types = obj->resultTypeSet();
    5969         160 :     if (!types)
    5970           0 :         return false;
    5971             : 
    5972             :     // Typed arrays are native classes but do not have dense elements.
    5973         160 :     const Class* clasp = types->getKnownClass(constraints);
    5974         160 :     return clasp && clasp->isNative() && !IsTypedArrayClass(clasp);
    5975             : }
    5976             : 
    5977             : JSValueType
    5978         180 : jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
    5979             :                              MDefinition* id)
    5980             : {
    5981         180 :     if (obj->mightBeType(MIRType::String))
    5982           3 :         return JSVAL_TYPE_MAGIC;
    5983             : 
    5984         177 :     if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double)
    5985           9 :         return JSVAL_TYPE_MAGIC;
    5986             : 
    5987         168 :     TemporaryTypeSet* types = obj->resultTypeSet();
    5988         168 :     if (!types || types->unknownObject())
    5989          24 :         return JSVAL_TYPE_MAGIC;
    5990             : 
    5991         144 :     JSValueType elementType = JSVAL_TYPE_MAGIC;
    5992         144 :     for (unsigned i = 0; i < types->getObjectCount(); i++) {
    5993           2 :         TypeSet::ObjectKey* key = types->getObject(i);
    5994           2 :         if (!key)
    5995           0 :             continue;
    5996             : 
    5997           2 :         if (key->unknownProperties() || !key->isGroup())
    5998           0 :             return JSVAL_TYPE_MAGIC;
    5999             : 
    6000           2 :         if (key->clasp() != &UnboxedArrayObject::class_)
    6001           2 :             return JSVAL_TYPE_MAGIC;
    6002             : 
    6003           0 :         const UnboxedLayout &layout = key->group()->unboxedLayout();
    6004             : 
    6005           0 :         if (layout.nativeGroup())
    6006           0 :             return JSVAL_TYPE_MAGIC;
    6007             : 
    6008           0 :         if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC)
    6009           0 :             elementType = layout.elementType();
    6010             :         else
    6011           0 :             return JSVAL_TYPE_MAGIC;
    6012             : 
    6013           0 :         key->watchStateChangeForUnboxedConvertedToNative(constraints);
    6014             :     }
    6015             : 
    6016         142 :     return elementType;
    6017             : }
    6018             : 
    6019             : bool
    6020          52 : jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
    6021             :                                MDefinition* obj, MDefinition* id,
    6022             :                                Scalar::Type* arrayType)
    6023             : {
    6024          52 :     if (obj->mightBeType(MIRType::String))
    6025           6 :         return false;
    6026             : 
    6027          46 :     if (id->type() != MIRType::Int32 && id->type() != MIRType::Double)
    6028          16 :         return false;
    6029             : 
    6030          30 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6031          30 :     if (!types)
    6032           0 :         return false;
    6033             : 
    6034          30 :     *arrayType = types->getTypedArrayType(constraints);
    6035          30 :     return *arrayType != Scalar::MaxTypedArrayViewType;
    6036             : }
    6037             : 
    6038             : bool
    6039           2 : jit::ElementAccessIsPacked(CompilerConstraintList* constraints, MDefinition* obj)
    6040             : {
    6041           2 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6042           2 :     return types && !types->hasObjectFlags(constraints, OBJECT_FLAG_NON_PACKED);
    6043             : }
    6044             : 
    6045             : bool
    6046           3 : jit::ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, MDefinition* obj)
    6047             : {
    6048           3 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6049           3 :     return !types || types->hasObjectFlags(constraints, OBJECT_FLAG_COPY_ON_WRITE);
    6050             : }
    6051             : 
    6052             : bool
    6053           1 : jit::ElementAccessMightBeFrozen(CompilerConstraintList* constraints, MDefinition* obj)
    6054             : {
    6055           1 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6056           1 :     return !types || types->hasObjectFlags(constraints, OBJECT_FLAG_FROZEN_ELEMENTS);
    6057             : }
    6058             : 
    6059             : AbortReasonOr<bool>
    6060           3 : jit::ElementAccessHasExtraIndexedProperty(IonBuilder* builder, MDefinition* obj)
    6061             : {
    6062           3 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6063             : 
    6064           3 :     if (!types || types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_LENGTH_OVERFLOW))
    6065           0 :         return true;
    6066             : 
    6067           3 :     return TypeCanHaveExtraIndexedProperties(builder, types);
    6068             : }
    6069             : 
    6070             : MIRType
    6071           1 : jit::DenseNativeElementType(CompilerConstraintList* constraints, MDefinition* obj)
    6072             : {
    6073           1 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6074           1 :     MIRType elementType = MIRType::None;
    6075           1 :     unsigned count = types->getObjectCount();
    6076             : 
    6077           2 :     for (unsigned i = 0; i < count; i++) {
    6078           1 :         TypeSet::ObjectKey* key = types->getObject(i);
    6079           1 :         if (!key)
    6080           0 :             continue;
    6081             : 
    6082           1 :         if (key->unknownProperties())
    6083           0 :             return MIRType::None;
    6084             : 
    6085           1 :         HeapTypeSetKey elementTypes = key->property(JSID_VOID);
    6086             : 
    6087           1 :         MIRType type = elementTypes.knownMIRType(constraints);
    6088           1 :         if (type == MIRType::None)
    6089           0 :             return MIRType::None;
    6090             : 
    6091           1 :         if (elementType == MIRType::None)
    6092           1 :             elementType = type;
    6093           0 :         else if (elementType != type)
    6094           0 :             return MIRType::None;
    6095             :     }
    6096             : 
    6097           1 :     return elementType;
    6098             : }
    6099             : 
    6100             : static BarrierKind
    6101          82 : PropertyReadNeedsTypeBarrier(CompilerConstraintList* constraints,
    6102             :                              TypeSet::ObjectKey* key, PropertyName* name,
    6103             :                              TypeSet* observed)
    6104             : {
    6105             :     // If the object being read from has types for the property which haven't
    6106             :     // been observed at this access site, the read could produce a new type and
    6107             :     // a barrier is needed. Note that this only covers reads from properties
    6108             :     // which are accounted for by type information, i.e. native data properties
    6109             :     // and elements.
    6110             :     //
    6111             :     // We also need a barrier if the object is a proxy, because then all bets
    6112             :     // are off, just as if it has unknown properties.
    6113         159 :     if (key->unknownProperties() || observed->empty() ||
    6114          77 :         key->clasp()->isProxy())
    6115             :     {
    6116           5 :         return BarrierKind::TypeSet;
    6117             :     }
    6118             : 
    6119          77 :     jsid id = name ? NameToId(name) : JSID_VOID;
    6120          77 :     HeapTypeSetKey property = key->property(id);
    6121          77 :     if (property.maybeTypes()) {
    6122          42 :         if (!TypeSetIncludes(observed, MIRType::Value, property.maybeTypes())) {
    6123             :             // If all possible objects have been observed, we don't have to
    6124             :             // guard on the specific object types.
    6125           6 :             if (property.maybeTypes()->objectsAreSubset(observed)) {
    6126           0 :                 property.freeze(constraints);
    6127           0 :                 return BarrierKind::TypeTagOnly;
    6128             :             }
    6129           6 :             return BarrierKind::TypeSet;
    6130             :         }
    6131             :     }
    6132             : 
    6133             :     // Type information for global objects is not required to reflect the
    6134             :     // initial 'undefined' value for properties, in particular global
    6135             :     // variables declared with 'var'. Until the property is assigned a value
    6136             :     // other than undefined, a barrier is required.
    6137          71 :     if (key->isSingleton()) {
    6138          21 :         JSObject* obj = key->singleton();
    6139          26 :         if (name && CanHaveEmptyPropertyTypesForOwnProperty(obj) &&
    6140          10 :             (!property.maybeTypes() || property.maybeTypes()->empty()))
    6141             :         {
    6142           0 :             return BarrierKind::TypeSet;
    6143             :         }
    6144             :     }
    6145             : 
    6146          71 :     property.freeze(constraints);
    6147          71 :     return BarrierKind::NoBarrier;
    6148             : }
    6149             : 
    6150             : static bool
    6151          19 : ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
    6152             : {
    6153          54 :     if (first->isSingleton() ||
    6154          32 :         second->isSingleton() ||
    6155          32 :         first->clasp() != second->clasp() ||
    6156          51 :         first->unknownProperties() ||
    6157          16 :         second->unknownProperties())
    6158             :     {
    6159           3 :         return false;
    6160             :     }
    6161             : 
    6162          16 :     if (first->clasp() == &ArrayObject::class_) {
    6163           0 :         HeapTypeSetKey firstElements = first->property(JSID_VOID);
    6164           0 :         HeapTypeSetKey secondElements = second->property(JSID_VOID);
    6165             : 
    6166           0 :         return firstElements.maybeTypes() && secondElements.maybeTypes() &&
    6167           0 :                firstElements.maybeTypes()->equals(secondElements.maybeTypes());
    6168             :     }
    6169             : 
    6170          16 :     if (first->clasp() == &UnboxedArrayObject::class_) {
    6171           0 :         return first->group()->unboxedLayout().elementType() ==
    6172           0 :                second->group()->unboxedLayout().elementType();
    6173             :     }
    6174             : 
    6175          16 :     return false;
    6176             : }
    6177             : 
    6178             : BarrierKind
    6179          70 : jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
    6180             :                                   CompilerConstraintList* constraints,
    6181             :                                   TypeSet::ObjectKey* key, PropertyName* name,
    6182             :                                   TemporaryTypeSet* observed, bool updateObserved)
    6183             : {
    6184          70 :     if (!updateObserved)
    6185           0 :         return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
    6186             : 
    6187             :     // If this access has never executed, try to add types to the observed set
    6188             :     // according to any property which exists on the object or its prototype.
    6189          70 :     if (observed->empty() && name) {
    6190             :         JSObject* obj;
    6191           7 :         if (key->isSingleton())
    6192           2 :             obj = key->singleton();
    6193             :         else
    6194           5 :             obj = key->proto().isDynamic() ? nullptr : key->proto().toObjectOrNull();
    6195             : 
    6196          19 :         while (obj) {
    6197           8 :             if (!obj->getClass()->isNative())
    6198           0 :                 break;
    6199             : 
    6200           8 :             TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(obj);
    6201           8 :             if (propertycx)
    6202           0 :                 key->ensureTrackedProperty(propertycx, NameToId(name));
    6203             : 
    6204           8 :             if (!key->unknownProperties()) {
    6205           8 :                 HeapTypeSetKey property = key->property(NameToId(name));
    6206           8 :                 if (property.maybeTypes()) {
    6207           2 :                     TypeSet::TypeList types;
    6208           2 :                     if (!property.maybeTypes()->enumerateTypes(&types))
    6209           0 :                         break;
    6210           2 :                     if (types.length() == 1) {
    6211             :                         // Note: the return value here is ignored.
    6212           2 :                         observed->addType(types[0], GetJitContext()->temp->lifoAlloc());
    6213           2 :                         break;
    6214             :                     }
    6215             :                 }
    6216             :             }
    6217             : 
    6218           6 :             obj = obj->staticPrototype();
    6219             :         }
    6220             :     }
    6221             : 
    6222             :     // If any objects which could be observed are similar to ones that have
    6223             :     // already been observed, add them to the observed type set.
    6224          70 :     if (!key->unknownProperties()) {
    6225          70 :         HeapTypeSetKey property = key->property(name ? NameToId(name) : JSID_VOID);
    6226             : 
    6227          70 :         if (property.maybeTypes() && !property.maybeTypes()->unknownObject()) {
    6228          57 :             for (size_t i = 0; i < property.maybeTypes()->getObjectCount(); i++) {
    6229          19 :                 TypeSet::ObjectKey* key = property.maybeTypes()->getObject(i);
    6230          19 :                 if (!key || observed->unknownObject())
    6231           0 :                     continue;
    6232             : 
    6233          38 :                 for (size_t j = 0; j < observed->getObjectCount(); j++) {
    6234          19 :                     TypeSet::ObjectKey* observedKey = observed->getObject(j);
    6235          19 :                     if (observedKey && ObjectSubsumes(observedKey, key)) {
    6236             :                         // Note: the return value here is ignored.
    6237           0 :                         observed->addType(TypeSet::ObjectType(key),
    6238           0 :                                           GetJitContext()->temp->lifoAlloc());
    6239           0 :                         break;
    6240             :                     }
    6241             :                 }
    6242             :             }
    6243             :         }
    6244             :     }
    6245             : 
    6246          70 :     return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
    6247             : }
    6248             : 
    6249             : BarrierKind
    6250         496 : jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
    6251             :                                   CompilerConstraintList* constraints,
    6252             :                                   MDefinition* obj, PropertyName* name,
    6253             :                                   TemporaryTypeSet* observed)
    6254             : {
    6255         496 :     if (observed->unknown())
    6256           0 :         return BarrierKind::NoBarrier;
    6257             : 
    6258         496 :     TypeSet* types = obj->resultTypeSet();
    6259         496 :     if (!types || types->unknownObject())
    6260         244 :         return BarrierKind::TypeSet;
    6261             : 
    6262         252 :     BarrierKind res = BarrierKind::NoBarrier;
    6263             : 
    6264         252 :     bool updateObserved = types->getObjectCount() == 1;
    6265         302 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6266          61 :         if (TypeSet::ObjectKey* key = types->getObject(i)) {
    6267          61 :             BarrierKind kind = PropertyReadNeedsTypeBarrier(propertycx, constraints, key, name,
    6268          61 :                                                             observed, updateObserved);
    6269          61 :             if (kind == BarrierKind::TypeSet)
    6270          11 :                 return BarrierKind::TypeSet;
    6271             : 
    6272          50 :             if (kind == BarrierKind::TypeTagOnly) {
    6273           0 :                 MOZ_ASSERT(res == BarrierKind::NoBarrier || res == BarrierKind::TypeTagOnly);
    6274           0 :                 res = BarrierKind::TypeTagOnly;
    6275             :             } else {
    6276          50 :                 MOZ_ASSERT(kind == BarrierKind::NoBarrier);
    6277             :             }
    6278             :         }
    6279             :     }
    6280             : 
    6281         241 :     return res;
    6282             : }
    6283             : 
    6284             : AbortReasonOr<BarrierKind>
    6285           6 : jit::PropertyReadOnPrototypeNeedsTypeBarrier(IonBuilder* builder,
    6286             :                                              MDefinition* obj, PropertyName* name,
    6287             :                                              TemporaryTypeSet* observed)
    6288             : {
    6289           6 :     if (observed->unknown())
    6290           0 :         return BarrierKind::NoBarrier;
    6291             : 
    6292           6 :     TypeSet* types = obj->resultTypeSet();
    6293           6 :     if (!types || types->unknownObject())
    6294           0 :         return BarrierKind::TypeSet;
    6295             : 
    6296           6 :     BarrierKind res = BarrierKind::NoBarrier;
    6297             : 
    6298          12 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6299           6 :         TypeSet::ObjectKey* key = types->getObject(i);
    6300           6 :         if (!key)
    6301           0 :             continue;
    6302             :         while (true) {
    6303          18 :             if (!builder->alloc().ensureBallast())
    6304           0 :                 return builder->abort(AbortReason::Alloc);
    6305          18 :             if (!key->hasStableClassAndProto(builder->constraints()))
    6306           0 :                 return BarrierKind::TypeSet;
    6307          18 :             if (!key->proto().isObject())
    6308           6 :                 break;
    6309          12 :             JSObject* proto = builder->checkNurseryObject(key->proto().toObject());
    6310          12 :             key = TypeSet::ObjectKey::get(proto);
    6311          12 :             BarrierKind kind = PropertyReadNeedsTypeBarrier(builder->constraints(),
    6312          12 :                                                             key, name, observed);
    6313          12 :             if (kind == BarrierKind::TypeSet)
    6314           0 :                 return BarrierKind::TypeSet;
    6315             : 
    6316          12 :             if (kind == BarrierKind::TypeTagOnly) {
    6317           0 :                 MOZ_ASSERT(res == BarrierKind::NoBarrier || res == BarrierKind::TypeTagOnly);
    6318           0 :                 res = BarrierKind::TypeTagOnly;
    6319             :             } else {
    6320          12 :                 MOZ_ASSERT(kind == BarrierKind::NoBarrier);
    6321             :             }
    6322          12 :         }
    6323             :     }
    6324             : 
    6325           6 :     return res;
    6326             : }
    6327             : 
    6328             : bool
    6329          14 : jit::PropertyReadIsIdempotent(CompilerConstraintList* constraints,
    6330             :                               MDefinition* obj, PropertyName* name)
    6331             : {
    6332             :     // Determine if reading a property from obj is likely to be idempotent.
    6333             : 
    6334          14 :     TypeSet* types = obj->resultTypeSet();
    6335          14 :     if (!types || types->unknownObject())
    6336           8 :         return false;
    6337             : 
    6338           9 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6339           6 :         if (TypeSet::ObjectKey* key = types->getObject(i)) {
    6340           6 :             if (key->unknownProperties())
    6341           3 :                 return false;
    6342             : 
    6343             :             // Check if the property has been reconfigured or is a getter.
    6344           6 :             HeapTypeSetKey property = key->property(NameToId(name));
    6345           6 :             if (property.nonData(constraints))
    6346           3 :                 return false;
    6347             :         }
    6348             :     }
    6349             : 
    6350           3 :     return true;
    6351             : }
    6352             : 
    6353             : void
    6354           0 : jit::AddObjectsForPropertyRead(MDefinition* obj, PropertyName* name,
    6355             :                                TemporaryTypeSet* observed)
    6356             : {
    6357             :     // Add objects to observed which *could* be observed by reading name from obj,
    6358             :     // to hopefully avoid unnecessary type barriers and code invalidations.
    6359             : 
    6360           0 :     LifoAlloc* alloc = GetJitContext()->temp->lifoAlloc();
    6361             : 
    6362           0 :     TemporaryTypeSet* types = obj->resultTypeSet();
    6363           0 :     if (!types || types->unknownObject()) {
    6364           0 :         observed->addType(TypeSet::AnyObjectType(), alloc);
    6365           0 :         return;
    6366             :     }
    6367             : 
    6368           0 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6369           0 :         TypeSet::ObjectKey* key = types->getObject(i);
    6370           0 :         if (!key)
    6371           0 :             continue;
    6372             : 
    6373           0 :         if (key->unknownProperties()) {
    6374           0 :             observed->addType(TypeSet::AnyObjectType(), alloc);
    6375           0 :             return;
    6376             :         }
    6377             : 
    6378           0 :         jsid id = name ? NameToId(name) : JSID_VOID;
    6379           0 :         HeapTypeSetKey property = key->property(id);
    6380           0 :         HeapTypeSet* types = property.maybeTypes();
    6381           0 :         if (!types)
    6382           0 :             continue;
    6383             : 
    6384           0 :         if (types->unknownObject()) {
    6385           0 :             observed->addType(TypeSet::AnyObjectType(), alloc);
    6386           0 :             return;
    6387             :         }
    6388             : 
    6389           0 :         for (size_t i = 0; i < types->getObjectCount(); i++) {
    6390           0 :             if (TypeSet::ObjectKey* key = types->getObject(i))
    6391           0 :                 observed->addType(TypeSet::ObjectType(key), alloc);
    6392             :         }
    6393             :     }
    6394             : }
    6395             : 
    6396             : AbortReasonOr<bool>
    6397          10 : PrototypeHasIndexedProperty(IonBuilder* builder, JSObject* obj)
    6398             : {
    6399           5 :     do {
    6400          10 :         TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(builder->checkNurseryObject(obj));
    6401          10 :         if (ClassCanHaveExtraProperties(key->clasp()))
    6402           0 :             return true;
    6403          10 :         if (key->unknownProperties())
    6404           0 :             return true;
    6405          10 :         HeapTypeSetKey index = key->property(JSID_VOID);
    6406          10 :         if (index.nonData(builder->constraints()) || index.isOwnProperty(builder->constraints()))
    6407           0 :             return true;
    6408          10 :         obj = obj->staticPrototype();
    6409          10 :         if (!builder->alloc().ensureBallast())
    6410           0 :             return builder->abort(AbortReason::Alloc);
    6411          10 :     } while (obj);
    6412             : 
    6413           5 :     return false;
    6414             : }
    6415             : 
    6416             : // Whether Array.prototype, or an object on its proto chain, has an indexed property.
    6417             : AbortReasonOr<bool>
    6418           2 : jit::ArrayPrototypeHasIndexedProperty(IonBuilder* builder, JSScript* script)
    6419             : {
    6420           2 :     if (JSObject* proto = script->global().maybeGetArrayPrototype())
    6421           2 :         return PrototypeHasIndexedProperty(builder, proto);
    6422           0 :     return true;
    6423             : }
    6424             : 
    6425             : // Whether obj or any of its prototypes have an indexed property.
    6426             : AbortReasonOr<bool>
    6427           3 : jit::TypeCanHaveExtraIndexedProperties(IonBuilder* builder, TemporaryTypeSet* types)
    6428             : {
    6429           3 :     const Class* clasp = types->getKnownClass(builder->constraints());
    6430             : 
    6431             :     // Note: typed arrays have indexed properties not accounted for by type
    6432             :     // information, though these are all in bounds and will be accounted for
    6433             :     // by JIT paths.
    6434           3 :     if (!clasp || (ClassCanHaveExtraProperties(clasp) && !IsTypedArrayClass(clasp)))
    6435           0 :         return true;
    6436             : 
    6437           3 :     if (types->hasObjectFlags(builder->constraints(), OBJECT_FLAG_SPARSE_INDEXES))
    6438           0 :         return true;
    6439             : 
    6440             :     JSObject* proto;
    6441           3 :     if (!types->getCommonPrototype(builder->constraints(), &proto))
    6442           0 :         return true;
    6443             : 
    6444           3 :     if (!proto)
    6445           0 :         return false;
    6446             : 
    6447           3 :     return PrototypeHasIndexedProperty(builder, proto);
    6448             : }
    6449             : 
    6450             : static bool
    6451          64 : PropertyTypeIncludes(TempAllocator& alloc, HeapTypeSetKey property,
    6452             :                      MDefinition* value, MIRType implicitType)
    6453             : {
    6454             :     // If implicitType is not MIRType::None, it is an additional type which the
    6455             :     // property implicitly includes. In this case, make a new type set which
    6456             :     // explicitly contains the type.
    6457          64 :     TypeSet* types = property.maybeTypes();
    6458          64 :     if (implicitType != MIRType::None) {
    6459           0 :         TypeSet::Type newType = TypeSet::PrimitiveType(ValueTypeFromMIRType(implicitType));
    6460           0 :         if (types)
    6461           0 :             types = types->clone(alloc.lifoAlloc());
    6462             :         else
    6463           0 :             types = alloc.lifoAlloc()->new_<TemporaryTypeSet>();
    6464           0 :         if (!types) {
    6465           0 :             return false;
    6466             :         }
    6467           0 :         types->addType(newType, alloc.lifoAlloc());
    6468             :     }
    6469             : 
    6470          64 :     return TypeSetIncludes(types, value->type(), value->resultTypeSet());
    6471             : }
    6472             : 
    6473             : static bool
    6474           3 : TryAddTypeBarrierForWrite(TempAllocator& alloc, CompilerConstraintList* constraints,
    6475             :                           MBasicBlock* current, TemporaryTypeSet* objTypes,
    6476             :                           PropertyName* name, MDefinition** pvalue, MIRType implicitType)
    6477             : {
    6478             :     // Return whether pvalue was modified to include a type barrier ensuring
    6479             :     // that writing the value to objTypes/id will not require changing type
    6480             :     // information.
    6481             : 
    6482             :     // All objects in the set must have the same types for name. Otherwise, we
    6483             :     // could bail out without subsequently triggering a type change that
    6484             :     // invalidates the compiled code.
    6485           6 :     Maybe<HeapTypeSetKey> aggregateProperty;
    6486             : 
    6487           3 :     for (size_t i = 0; i < objTypes->getObjectCount(); i++) {
    6488           3 :         TypeSet::ObjectKey* key = objTypes->getObject(i);
    6489           3 :         if (!key)
    6490           0 :             continue;
    6491             : 
    6492           3 :         if (key->unknownProperties())
    6493           3 :             return false;
    6494             : 
    6495           3 :         jsid id = name ? NameToId(name) : JSID_VOID;
    6496           3 :         HeapTypeSetKey property = key->property(id);
    6497           3 :         if (!property.maybeTypes() || property.couldBeConstant(constraints))
    6498           3 :             return false;
    6499             : 
    6500           0 :         if (PropertyTypeIncludes(alloc, property, *pvalue, implicitType))
    6501           0 :             return false;
    6502             : 
    6503             :         // This freeze is not required for correctness, but ensures that we
    6504             :         // will recompile if the property types change and the barrier can
    6505             :         // potentially be removed.
    6506           0 :         property.freeze(constraints);
    6507             : 
    6508           0 :         if (!aggregateProperty) {
    6509           0 :             aggregateProperty.emplace(property);
    6510             :         } else {
    6511           0 :             if (!aggregateProperty->maybeTypes()->equals(property.maybeTypes()))
    6512           0 :                 return false;
    6513             :         }
    6514             :     }
    6515             : 
    6516           0 :     MOZ_ASSERT(aggregateProperty);
    6517             : 
    6518           0 :     MIRType propertyType = aggregateProperty->knownMIRType(constraints);
    6519           0 :     switch (propertyType) {
    6520             :       case MIRType::Boolean:
    6521             :       case MIRType::Int32:
    6522             :       case MIRType::Double:
    6523             :       case MIRType::String:
    6524             :       case MIRType::Symbol: {
    6525             :         // The property is a particular primitive type, guard by unboxing the
    6526             :         // value before the write.
    6527           0 :         if (!(*pvalue)->mightBeType(propertyType)) {
    6528             :             // The value's type does not match the property type. Just do a VM
    6529             :             // call as it will always trigger invalidation of the compiled code.
    6530           0 :             MOZ_ASSERT_IF((*pvalue)->type() != MIRType::Value, (*pvalue)->type() != propertyType);
    6531           0 :             return false;
    6532             :         }
    6533           0 :         MInstruction* ins = MUnbox::New(alloc, *pvalue, propertyType, MUnbox::Fallible);
    6534           0 :         current->add(ins);
    6535           0 :         *pvalue = ins;
    6536           0 :         return true;
    6537             :       }
    6538             :       default:;
    6539             :     }
    6540             : 
    6541           0 :     if ((*pvalue)->type() != MIRType::Value)
    6542           0 :         return false;
    6543             : 
    6544           0 :     TemporaryTypeSet* types = aggregateProperty->maybeTypes()->clone(alloc.lifoAlloc());
    6545           0 :     if (!types)
    6546           0 :         return false;
    6547             : 
    6548             :     // If all possible objects can be stored without a barrier, we don't have to
    6549             :     // guard on the specific object types.
    6550           0 :     BarrierKind kind = BarrierKind::TypeSet;
    6551           0 :     if ((*pvalue)->resultTypeSet() && (*pvalue)->resultTypeSet()->objectsAreSubset(types))
    6552           0 :         kind = BarrierKind::TypeTagOnly;
    6553             : 
    6554           0 :     MInstruction* ins = MMonitorTypes::New(alloc, *pvalue, types, kind);
    6555           0 :     current->add(ins);
    6556           0 :     return true;
    6557             : }
    6558             : 
    6559             : static MInstruction*
    6560           0 : AddGroupGuard(TempAllocator& alloc, MBasicBlock* current, MDefinition* obj,
    6561             :               TypeSet::ObjectKey* key, bool bailOnEquality)
    6562             : {
    6563             :     MInstruction* guard;
    6564             : 
    6565           0 :     if (key->isGroup()) {
    6566           0 :         guard = MGuardObjectGroup::New(alloc, obj, key->group(), bailOnEquality,
    6567           0 :                                        Bailout_ObjectIdentityOrTypeGuard);
    6568             :     } else {
    6569           0 :         MConstant* singletonConst = MConstant::NewConstraintlessObject(alloc, key->singleton());
    6570           0 :         current->add(singletonConst);
    6571           0 :         guard = MGuardObjectIdentity::New(alloc, obj, singletonConst, bailOnEquality);
    6572             :     }
    6573             : 
    6574           0 :     current->add(guard);
    6575             : 
    6576             :     // For now, never move object group / identity guards.
    6577           0 :     guard->setNotMovable();
    6578             : 
    6579           0 :     return guard;
    6580             : }
    6581             : 
    6582             : // Whether value can be written to property without changing type information.
    6583             : bool
    6584          64 : jit::CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints,
    6585             :                       HeapTypeSetKey property, MDefinition* value,
    6586             :                       MIRType implicitType /* = MIRType::None */)
    6587             : {
    6588          64 :     if (property.couldBeConstant(constraints))
    6589           0 :         return false;
    6590          64 :     return PropertyTypeIncludes(alloc, property, value, implicitType);
    6591             : }
    6592             : 
    6593             : bool
    6594          64 : jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList* constraints,
    6595             :                                    MBasicBlock* current, MDefinition** pobj,
    6596             :                                    PropertyName* name, MDefinition** pvalue,
    6597             :                                    bool canModify, MIRType implicitType)
    6598             : {
    6599             :     // If any value being written is not reflected in the type information for
    6600             :     // objects which obj could represent, a type barrier is needed when writing
    6601             :     // the value. As for propertyReadNeedsTypeBarrier, this only applies for
    6602             :     // properties that are accounted for by type information, i.e. normal data
    6603             :     // properties and elements.
    6604             : 
    6605          64 :     TemporaryTypeSet* types = (*pobj)->resultTypeSet();
    6606          64 :     if (!types || types->unknownObject())
    6607           0 :         return true;
    6608             : 
    6609             :     // If all of the objects being written to have property types which already
    6610             :     // reflect the value, no barrier at all is needed. Additionally, if all
    6611             :     // objects being written to have the same types for the property, and those
    6612             :     // types do *not* reflect the value, add a type barrier for the value.
    6613             : 
    6614          64 :     bool success = true;
    6615         123 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6616          64 :         TypeSet::ObjectKey* key = types->getObject(i);
    6617          64 :         if (!key || key->unknownProperties())
    6618           0 :             continue;
    6619             : 
    6620             :         // TI doesn't track TypedArray indexes and should never insert a type
    6621             :         // barrier for them.
    6622          64 :         if (!name && IsTypedArrayClass(key->clasp()))
    6623           0 :             continue;
    6624             : 
    6625          64 :         jsid id = name ? NameToId(name) : JSID_VOID;
    6626          64 :         HeapTypeSetKey property = key->property(id);
    6627          64 :         if (!CanWriteProperty(alloc, constraints, property, *pvalue, implicitType)) {
    6628             :             // Either pobj or pvalue needs to be modified to filter out the
    6629             :             // types which the value could have but are not in the property,
    6630             :             // or a VM call is required. A VM call is always required if pobj
    6631             :             // and pvalue cannot be modified.
    6632           5 :             if (!canModify)
    6633           2 :                 return true;
    6634             :             success = TryAddTypeBarrierForWrite(alloc, constraints, current, types, name, pvalue,
    6635           3 :                                                 implicitType);
    6636           3 :             break;
    6637             :         }
    6638             :     }
    6639             : 
    6640             :     // Perform additional filtering to make sure that any unboxed property
    6641             :     // being written can accommodate the value.
    6642         124 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6643          62 :         TypeSet::ObjectKey* key = types->getObject(i);
    6644          62 :         if (key && key->isGroup() && key->group()->maybeUnboxedLayout()) {
    6645           0 :             const UnboxedLayout& layout = key->group()->unboxedLayout();
    6646           0 :             if (name) {
    6647           0 :                 const UnboxedLayout::Property* property = layout.lookup(name);
    6648           0 :                 if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue))
    6649           0 :                     return true;
    6650             :             } else {
    6651           0 :                 if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue))
    6652           0 :                     return true;
    6653             :             }
    6654             :         }
    6655             :     }
    6656             : 
    6657          62 :     if (success)
    6658          59 :         return false;
    6659             : 
    6660             :     // If all of the objects except one have property types which reflect the
    6661             :     // value, and the remaining object has no types at all for the property,
    6662             :     // add a guard that the object does not have that remaining object's type.
    6663             : 
    6664           3 :     if (types->getObjectCount() <= 1)
    6665           3 :         return true;
    6666             : 
    6667           0 :     TypeSet::ObjectKey* excluded = nullptr;
    6668           0 :     for (size_t i = 0; i < types->getObjectCount(); i++) {
    6669           0 :         TypeSet::ObjectKey* key = types->getObject(i);
    6670           0 :         if (!key || key->unknownProperties())
    6671           0 :             continue;
    6672           0 :         if (!name && IsTypedArrayClass(key->clasp()))
    6673           0 :             continue;
    6674             : 
    6675           0 :         jsid id = name ? NameToId(name) : JSID_VOID;
    6676           0 :         HeapTypeSetKey property = key->property(id);
    6677           0 :         if (CanWriteProperty(alloc, constraints, property, *pvalue, implicitType))
    6678           0 :             continue;
    6679             : 
    6680           0 :         if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
    6681           0 :             return true;
    6682           0 :         excluded = key;
    6683             :     }
    6684             : 
    6685           0 :     MOZ_ASSERT(excluded);
    6686             : 
    6687             :     // If the excluded object is a group with an unboxed layout, make sure it
    6688             :     // does not have a corresponding native group. Objects with the native
    6689             :     // group might appear even though they are not in the type set.
    6690           0 :     if (excluded->isGroup()) {
    6691           0 :         if (UnboxedLayout* layout = excluded->group()->maybeUnboxedLayout()) {
    6692           0 :             if (layout->nativeGroup())
    6693           0 :                 return true;
    6694           0 :             excluded->watchStateChangeForUnboxedConvertedToNative(constraints);
    6695             :         }
    6696             :     }
    6697             : 
    6698           0 :     *pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
    6699           0 :     return false;
    6700             : }

Generated by: LCOV version 1.13