LCOV - code coverage report
Current view: top level - js/src/jit - BaselineInspector.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 270 651 41.5 %
Date: 2017-07-14 16:53:18 Functions: 28 42 66.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/BaselineInspector.h"
       8             : 
       9             : #include "mozilla/DebugOnly.h"
      10             : 
      11             : #include "jit/BaselineIC.h"
      12             : #include "jit/CacheIRCompiler.h"
      13             : 
      14             : #include "jsscriptinlines.h"
      15             : 
      16             : #include "vm/EnvironmentObject-inl.h"
      17             : #include "vm/ObjectGroup-inl.h"
      18             : #include "vm/ReceiverGuard-inl.h"
      19             : 
      20             : using namespace js;
      21             : using namespace js::jit;
      22             : 
      23             : using mozilla::DebugOnly;
      24             : 
      25             : bool
      26           0 : SetElemICInspector::sawOOBDenseWrite() const
      27             : {
      28           0 :     if (!icEntry_)
      29           0 :         return false;
      30             : 
      31             :     // Check for a write hole bit on the SetElem_Fallback stub.
      32           0 :     ICStub* stub = icEntry_->fallbackStub();
      33           0 :     if (stub->isSetElem_Fallback())
      34           0 :         return stub->toSetElem_Fallback()->hasDenseAdd();
      35             : 
      36           0 :     return false;
      37             : }
      38             : 
      39             : bool
      40           0 : SetElemICInspector::sawOOBTypedArrayWrite() const
      41             : {
      42           0 :     if (!icEntry_)
      43           0 :         return false;
      44             : 
      45           0 :     ICStub* stub = icEntry_->fallbackStub();
      46           0 :     if (stub->isSetElem_Fallback())
      47           0 :         return stub->toSetElem_Fallback()->hasTypedArrayOOB();
      48             : 
      49           0 :     return false;
      50             : }
      51             : 
      52             : template <typename S, typename T>
      53             : static bool
      54          10 : VectorAppendNoDuplicate(S& list, T value)
      55             : {
      56          10 :     for (size_t i = 0; i < list.length(); i++) {
      57           0 :         if (list[i] == value)
      58           0 :             return true;
      59             :     }
      60          10 :     return list.append(value);
      61             : }
      62             : 
      63             : static bool
      64          10 : AddReceiver(const ReceiverGuard& receiver,
      65             :             BaselineInspector::ReceiverVector& receivers,
      66             :             BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
      67             : {
      68          10 :     if (receiver.group && receiver.group->maybeUnboxedLayout()) {
      69           0 :         if (receiver.group->unboxedLayout().nativeGroup())
      70           0 :             return VectorAppendNoDuplicate(convertUnboxedGroups, receiver.group);
      71             :     }
      72          10 :     return VectorAppendNoDuplicate(receivers, receiver);
      73             : }
      74             : 
      75             : static bool
      76          20 : GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* receiver)
      77             : {
      78             :     // We match either:
      79             :     //
      80             :     //   GuardIsObject 0
      81             :     //   GuardShape 0
      82             :     //   LoadFixedSlotResult 0 or LoadDynamicSlotResult 0
      83             :     //
      84             :     // or
      85             :     //
      86             :     //   GuardIsObject 0
      87             :     //   GuardGroup 0
      88             :     //   1: GuardAndLoadUnboxedExpando 0
      89             :     //   GuardShape 1
      90             :     //   LoadFixedSlotResult 1 or LoadDynamicSlotResult 1
      91             : 
      92          20 :     *receiver = ReceiverGuard();
      93          20 :     CacheIRReader reader(stub->stubInfo());
      94             : 
      95          20 :     ObjOperandId objId = ObjOperandId(0);
      96          20 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId))
      97           0 :         return false;
      98             : 
      99          20 :     if (reader.matchOp(CacheOp::GuardGroup, objId)) {
     100           0 :         receiver->group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
     101             : 
     102           0 :         if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId))
     103           0 :             return false;
     104           0 :         objId = reader.objOperandId();
     105             :     }
     106             : 
     107          20 :     if (reader.matchOp(CacheOp::GuardShape, objId)) {
     108          10 :         receiver->shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
     109          10 :         return reader.matchOpEither(CacheOp::LoadFixedSlotResult, CacheOp::LoadDynamicSlotResult);
     110             :     }
     111             : 
     112          10 :     return false;
     113             : }
     114             : 
     115             : static bool
     116          10 : GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* receiver)
     117             : {
     118             :     // We match:
     119             :     //
     120             :     //   GuardIsObject 0
     121             :     //   GuardGroup 0
     122             :     //   LoadUnboxedPropertyResult 0 ..
     123             : 
     124          10 :     *receiver = ReceiverGuard();
     125          10 :     CacheIRReader reader(stub->stubInfo());
     126             : 
     127          10 :     ObjOperandId objId = ObjOperandId(0);
     128          10 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId))
     129           0 :         return false;
     130             : 
     131          10 :     if (!reader.matchOp(CacheOp::GuardGroup, objId))
     132          10 :         return false;
     133           0 :     receiver->group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
     134             : 
     135           0 :     return reader.matchOp(CacheOp::LoadUnboxedPropertyResult, objId);
     136             : }
     137             : 
     138             : static bool
     139           1 : GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub, ReceiverGuard* receiver)
     140             : {
     141             :     // We match either:
     142             :     //
     143             :     //   GuardIsObject 0
     144             :     //   GuardGroup 0
     145             :     //   GuardShape 0
     146             :     //   StoreFixedSlot 0 or StoreDynamicSlot 0
     147             :     //
     148             :     // or
     149             :     //
     150             :     //   GuardIsObject 0
     151             :     //   GuardGroup 0
     152             :     //   1: GuardAndLoadUnboxedExpando 0
     153             :     //   GuardShape 1
     154             :     //   StoreFixedSlot 1 or StoreDynamicSlot 1
     155             : 
     156           1 :     *receiver = ReceiverGuard();
     157           1 :     CacheIRReader reader(stub->stubInfo());
     158             : 
     159           1 :     ObjOperandId objId = ObjOperandId(0);
     160           1 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId))
     161           0 :         return false;
     162             : 
     163           1 :     if (!reader.matchOp(CacheOp::GuardGroup, objId))
     164           0 :         return false;
     165           1 :     ObjectGroup* group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
     166             : 
     167           1 :     if (reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId))
     168           0 :         objId = reader.objOperandId();
     169             : 
     170           1 :     if (!reader.matchOp(CacheOp::GuardShape, objId))
     171           0 :         return false;
     172           1 :     Shape* shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
     173             : 
     174           1 :     if (!reader.matchOpEither(CacheOp::StoreFixedSlot, CacheOp::StoreDynamicSlot))
     175           1 :         return false;
     176             : 
     177           0 :     *receiver = ReceiverGuard(group, shape);
     178           0 :     return true;
     179             : }
     180             : 
     181             : static bool
     182           1 : GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Updated* stub, ReceiverGuard* receiver)
     183             : {
     184             :     // We match:
     185             :     //
     186             :     //   GuardIsObject 0
     187             :     //   GuardGroup 0
     188             :     //   GuardType 1 type | GuardIsObjectOrNull 1
     189             :     //   StoreUnboxedProperty 0
     190             : 
     191           1 :     *receiver = ReceiverGuard();
     192           1 :     CacheIRReader reader(stub->stubInfo());
     193             : 
     194           1 :     ObjOperandId objId = ObjOperandId(0);
     195           1 :     ValOperandId rhsId = ValOperandId(1);
     196           1 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId))
     197           0 :         return false;
     198             : 
     199           1 :     if (!reader.matchOp(CacheOp::GuardGroup, objId))
     200           0 :         return false;
     201           1 :     ObjectGroup* group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
     202             : 
     203           1 :     if (reader.matchOp(CacheOp::GuardType, rhsId)) {
     204           0 :         reader.valueType(); // Skip.
     205             :     } else {
     206           1 :         if (!reader.matchOp(CacheOp::GuardIsObjectOrNull, rhsId))
     207           1 :             return false;
     208             :     }
     209             : 
     210           0 :     if (!reader.matchOp(CacheOp::StoreUnboxedProperty))
     211           0 :         return false;
     212             : 
     213           0 :     *receiver = ReceiverGuard(group, nullptr);
     214           0 :     return true;
     215             : }
     216             : 
     217             : bool
     218          28 : BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
     219             :                                           ObjectGroupVector& convertUnboxedGroups)
     220             : {
     221             :     // Return a list of the receivers seen by the baseline IC for the current
     222             :     // op. Empty lists indicate no receivers are known, or there was an
     223             :     // uncacheable access. convertUnboxedGroups is used for unboxed object
     224             :     // groups which have been seen, but have had instances converted to native
     225             :     // objects and should be eagerly converted by Ion.
     226          28 :     MOZ_ASSERT(receivers.empty());
     227          28 :     MOZ_ASSERT(convertUnboxedGroups.empty());
     228             : 
     229          28 :     if (!hasBaselineScript())
     230           0 :         return true;
     231             : 
     232          28 :     MOZ_ASSERT(isValidPC(pc));
     233          28 :     const ICEntry& entry = icEntryFromPC(pc);
     234             : 
     235          28 :     ICStub* stub = entry.firstStub();
     236          48 :     while (stub->next()) {
     237          21 :         ReceiverGuard receiver;
     238          21 :         if (stub->isCacheIR_Monitored()) {
     239          30 :             if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver) &&
     240          10 :                 !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Monitored(), &receiver))
     241             :             {
     242          10 :                 receivers.clear();
     243          21 :                 return true;
     244             :             }
     245           1 :         } else if (stub->isCacheIR_Updated()) {
     246           2 :             if (!GetCacheIRReceiverForNativeSetSlot(stub->toCacheIR_Updated(), &receiver) &&
     247           1 :                 !GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Updated(), &receiver))
     248             :             {
     249           1 :                 receivers.clear();
     250           1 :                 return true;
     251             :             }
     252             :         } else {
     253           0 :             receivers.clear();
     254           0 :             return true;
     255             :         }
     256             : 
     257          10 :         if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
     258           0 :             return false;
     259             : 
     260          10 :         stub = stub->next();
     261             :     }
     262             : 
     263          17 :     if (stub->isGetProp_Fallback()) {
     264          13 :         if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
     265           4 :             receivers.clear();
     266             :     } else {
     267           4 :         if (stub->toSetProp_Fallback()->hadUnoptimizableAccess())
     268           0 :             receivers.clear();
     269             :     }
     270             : 
     271             :     // Don't inline if there are more than 5 receivers.
     272          17 :     if (receivers.length() > 5)
     273           0 :         receivers.clear();
     274             : 
     275          17 :     return true;
     276             : }
     277             : 
     278             : ICStub*
     279         401 : BaselineInspector::monomorphicStub(jsbytecode* pc)
     280             : {
     281         401 :     if (!hasBaselineScript())
     282         387 :         return nullptr;
     283             : 
     284          14 :     const ICEntry& entry = icEntryFromPC(pc);
     285             : 
     286          14 :     ICStub* stub = entry.firstStub();
     287          14 :     ICStub* next = stub->next();
     288             : 
     289          14 :     if (!next || !next->isFallback())
     290           6 :         return nullptr;
     291             : 
     292           8 :     return stub;
     293             : }
     294             : 
     295             : bool
     296         195 : BaselineInspector::dimorphicStub(jsbytecode* pc, ICStub** pfirst, ICStub** psecond)
     297             : {
     298         195 :     if (!hasBaselineScript())
     299         195 :         return false;
     300             : 
     301           0 :     const ICEntry& entry = icEntryFromPC(pc);
     302             : 
     303           0 :     ICStub* stub = entry.firstStub();
     304           0 :     ICStub* next = stub->next();
     305           0 :     ICStub* after = next ? next->next() : nullptr;
     306             : 
     307           0 :     if (!after || !after->isFallback())
     308           0 :         return false;
     309             : 
     310           0 :     *pfirst = stub;
     311           0 :     *psecond = next;
     312           0 :     return true;
     313             : }
     314             : 
     315             : MIRType
     316         204 : BaselineInspector::expectedResultType(jsbytecode* pc)
     317             : {
     318             :     // Look at the IC entries for this op to guess what type it will produce,
     319             :     // returning MIRType::None otherwise.
     320             : 
     321         204 :     ICStub* stub = monomorphicStub(pc);
     322         204 :     if (!stub)
     323         198 :         return MIRType::None;
     324             : 
     325           6 :     switch (stub->kind()) {
     326             :       case ICStub::BinaryArith_Int32:
     327           6 :         if (stub->toBinaryArith_Int32()->allowDouble())
     328           0 :             return MIRType::Double;
     329           6 :         return MIRType::Int32;
     330             :       case ICStub::BinaryArith_BooleanWithInt32:
     331             :       case ICStub::UnaryArith_Int32:
     332             :       case ICStub::BinaryArith_DoubleWithInt32:
     333           0 :         return MIRType::Int32;
     334             :       case ICStub::BinaryArith_Double:
     335             :       case ICStub::UnaryArith_Double:
     336           0 :         return MIRType::Double;
     337             :       case ICStub::BinaryArith_StringConcat:
     338             :       case ICStub::BinaryArith_StringObjectConcat:
     339           0 :         return MIRType::String;
     340             :       default:
     341           0 :         return MIRType::None;
     342             :     }
     343             : }
     344             : 
     345             : // Whether a baseline stub kind is suitable for a double comparison that
     346             : // converts its operands to doubles.
     347             : static bool
     348           0 : CanUseDoubleCompare(ICStub::Kind kind)
     349             : {
     350           0 :     return kind == ICStub::Compare_Double || kind == ICStub::Compare_NumberWithUndefined;
     351             : }
     352             : 
     353             : // Whether a baseline stub kind is suitable for an int32 comparison that
     354             : // converts its operands to int32.
     355             : static bool
     356           2 : CanUseInt32Compare(ICStub::Kind kind)
     357             : {
     358           2 :     return kind == ICStub::Compare_Int32 || kind == ICStub::Compare_Int32WithBoolean;
     359             : }
     360             : 
     361             : MCompare::CompareType
     362         197 : BaselineInspector::expectedCompareType(jsbytecode* pc)
     363             : {
     364         197 :     ICStub* first = monomorphicStub(pc);
     365         197 :     ICStub* second = nullptr;
     366         197 :     if (!first && !dimorphicStub(pc, &first, &second))
     367         195 :         return MCompare::Compare_Unknown;
     368             : 
     369           2 :     if (ICStub* fallback = second ? second->next() : first->next()) {
     370           2 :         MOZ_ASSERT(fallback->isFallback());
     371           2 :         if (fallback->toCompare_Fallback()->hadUnoptimizableAccess())
     372           0 :             return MCompare::Compare_Unknown;
     373             :     }
     374             : 
     375           2 :     if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
     376             :         ICCompare_Int32WithBoolean* coerce =
     377           2 :             first->isCompare_Int32WithBoolean()
     378           4 :             ? first->toCompare_Int32WithBoolean()
     379           2 :             : ((second && second->isCompare_Int32WithBoolean())
     380           2 :                ? second->toCompare_Int32WithBoolean()
     381           2 :                : nullptr);
     382           2 :         if (coerce) {
     383           0 :             return coerce->lhsIsInt32()
     384           0 :                    ? MCompare::Compare_Int32MaybeCoerceRHS
     385           0 :                    : MCompare::Compare_Int32MaybeCoerceLHS;
     386             :         }
     387           2 :         return MCompare::Compare_Int32;
     388             :     }
     389             : 
     390           0 :     if (CanUseDoubleCompare(first->kind()) && (!second || CanUseDoubleCompare(second->kind()))) {
     391             :         ICCompare_NumberWithUndefined* coerce =
     392           0 :             first->isCompare_NumberWithUndefined()
     393           0 :             ? first->toCompare_NumberWithUndefined()
     394           0 :             : (second && second->isCompare_NumberWithUndefined())
     395           0 :               ? second->toCompare_NumberWithUndefined()
     396           0 :               : nullptr;
     397           0 :         if (coerce) {
     398           0 :             return coerce->lhsIsUndefined()
     399           0 :                    ? MCompare::Compare_DoubleMaybeCoerceLHS
     400           0 :                    : MCompare::Compare_DoubleMaybeCoerceRHS;
     401             :         }
     402           0 :         return MCompare::Compare_Double;
     403             :     }
     404             : 
     405           0 :     return MCompare::Compare_Unknown;
     406             : }
     407             : 
     408             : static bool
     409           0 : TryToSpecializeBinaryArithOp(ICStub** stubs,
     410             :                              uint32_t nstubs,
     411             :                              MIRType* result)
     412             : {
     413           0 :     DebugOnly<bool> sawInt32 = false;
     414           0 :     bool sawDouble = false;
     415           0 :     bool sawOther = false;
     416             : 
     417           0 :     for (uint32_t i = 0; i < nstubs; i++) {
     418           0 :         switch (stubs[i]->kind()) {
     419             :           case ICStub::BinaryArith_Int32:
     420           0 :             sawInt32 = true;
     421           0 :             break;
     422             :           case ICStub::BinaryArith_BooleanWithInt32:
     423           0 :             sawInt32 = true;
     424           0 :             break;
     425             :           case ICStub::BinaryArith_Double:
     426           0 :             sawDouble = true;
     427           0 :             break;
     428             :           case ICStub::BinaryArith_DoubleWithInt32:
     429           0 :             sawDouble = true;
     430           0 :             break;
     431             :           default:
     432           0 :             sawOther = true;
     433           0 :             break;
     434             :         }
     435             :     }
     436             : 
     437           0 :     if (sawOther)
     438           0 :         return false;
     439             : 
     440           0 :     if (sawDouble) {
     441           0 :         *result = MIRType::Double;
     442           0 :         return true;
     443             :     }
     444             : 
     445           0 :     MOZ_ASSERT(sawInt32);
     446           0 :     *result = MIRType::Int32;
     447           0 :     return true;
     448             : }
     449             : 
     450             : MIRType
     451           0 : BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc)
     452             : {
     453           0 :     if (!hasBaselineScript())
     454           0 :         return MIRType::None;
     455             : 
     456             :     MIRType result;
     457             :     ICStub* stubs[2];
     458             : 
     459           0 :     const ICEntry& entry = icEntryFromPC(pc);
     460           0 :     ICStub* stub = entry.fallbackStub();
     461           0 :     if (stub->isBinaryArith_Fallback() &&
     462           0 :         stub->toBinaryArith_Fallback()->hadUnoptimizableOperands())
     463             :     {
     464           0 :         return MIRType::None;
     465             :     }
     466             : 
     467           0 :     stubs[0] = monomorphicStub(pc);
     468           0 :     if (stubs[0]) {
     469           0 :         if (TryToSpecializeBinaryArithOp(stubs, 1, &result))
     470           0 :             return result;
     471             :     }
     472             : 
     473           0 :     if (dimorphicStub(pc, &stubs[0], &stubs[1])) {
     474           0 :         if (TryToSpecializeBinaryArithOp(stubs, 2, &result))
     475           0 :             return result;
     476             :     }
     477             : 
     478           0 :     return MIRType::None;
     479             : }
     480             : 
     481             : bool
     482           1 : BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode* pc)
     483             : {
     484           1 :     if (!hasBaselineScript())
     485           0 :         return false;
     486             : 
     487           1 :     const ICEntry& entry = icEntryFromPC(pc);
     488           1 :     ICStub* stub = entry.fallbackStub();
     489             : 
     490           1 :     if (stub->isGetElem_Fallback())
     491           1 :         return stub->toGetElem_Fallback()->hasNegativeIndex();
     492           0 :     return false;
     493             : }
     494             : 
     495             : bool
     496          14 : BaselineInspector::hasSeenAccessedGetter(jsbytecode* pc)
     497             : {
     498          14 :     if (!hasBaselineScript())
     499           0 :         return false;
     500             : 
     501          14 :     const ICEntry& entry = icEntryFromPC(pc);
     502          14 :     ICStub* stub = entry.fallbackStub();
     503             : 
     504          14 :     if (stub->isGetProp_Fallback())
     505          14 :         return stub->toGetProp_Fallback()->hasAccessedGetter();
     506           0 :     return false;
     507             : }
     508             : 
     509             : bool
     510           0 : BaselineInspector::hasSeenNonStringIterMore(jsbytecode* pc)
     511             : {
     512           0 :     MOZ_ASSERT(JSOp(*pc) == JSOP_MOREITER);
     513             : 
     514           0 :     if (!hasBaselineScript())
     515           0 :         return false;
     516             : 
     517           0 :     const ICEntry& entry = icEntryFromPC(pc);
     518           0 :     ICStub* stub = entry.fallbackStub();
     519             : 
     520           0 :     return stub->toIteratorMore_Fallback()->hasNonStringResult();
     521             : }
     522             : 
     523             : bool
     524         160 : BaselineInspector::hasSeenDoubleResult(jsbytecode* pc)
     525             : {
     526         160 :     if (!hasBaselineScript())
     527         147 :         return false;
     528             : 
     529          13 :     const ICEntry& entry = icEntryFromPC(pc);
     530          13 :     ICStub* stub = entry.fallbackStub();
     531             : 
     532          13 :     MOZ_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
     533             : 
     534          13 :     if (stub->isUnaryArith_Fallback())
     535           0 :         return stub->toUnaryArith_Fallback()->sawDoubleResult();
     536             :     else
     537          13 :         return stub->toBinaryArith_Fallback()->sawDoubleResult();
     538             : 
     539             :     return false;
     540             : }
     541             : 
     542             : JSObject*
     543          21 : BaselineInspector::getTemplateObject(jsbytecode* pc)
     544             : {
     545          21 :     if (!hasBaselineScript())
     546           3 :         return nullptr;
     547             : 
     548          18 :     const ICEntry& entry = icEntryFromPC(pc);
     549          25 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     550          25 :         switch (stub->kind()) {
     551             :           case ICStub::NewArray_Fallback:
     552           9 :             return stub->toNewArray_Fallback()->templateObject();
     553             :           case ICStub::NewObject_Fallback:
     554           7 :             return stub->toNewObject_Fallback()->templateObject();
     555             :           case ICStub::Rest_Fallback:
     556           2 :             return stub->toRest_Fallback()->templateObject();
     557             :           case ICStub::Call_Scripted:
     558           0 :             if (JSObject* obj = stub->toCall_Scripted()->templateObject())
     559           0 :                 return obj;
     560           0 :             break;
     561             :           default:
     562           7 :             break;
     563             :         }
     564             :     }
     565             : 
     566           0 :     return nullptr;
     567             : }
     568             : 
     569             : ObjectGroup*
     570          11 : BaselineInspector::getTemplateObjectGroup(jsbytecode* pc)
     571             : {
     572          11 :     if (!hasBaselineScript())
     573           2 :         return nullptr;
     574             : 
     575           9 :     const ICEntry& entry = icEntryFromPC(pc);
     576           9 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     577           9 :         switch (stub->kind()) {
     578             :           case ICStub::NewArray_Fallback:
     579           9 :             return stub->toNewArray_Fallback()->templateGroup();
     580             :           default:
     581           0 :             break;
     582             :         }
     583             :     }
     584             : 
     585           0 :     return nullptr;
     586             : }
     587             : 
     588             : JSFunction*
     589         139 : BaselineInspector::getSingleCallee(jsbytecode* pc)
     590             : {
     591         139 :     MOZ_ASSERT(*pc == JSOP_NEW);
     592             : 
     593         139 :     if (!hasBaselineScript())
     594         133 :         return nullptr;
     595             : 
     596           6 :     const ICEntry& entry = icEntryFromPC(pc);
     597           6 :     ICStub* stub = entry.firstStub();
     598             : 
     599           6 :     if (entry.fallbackStub()->toCall_Fallback()->hadUnoptimizableCall())
     600           0 :         return nullptr;
     601             : 
     602           6 :     if (!stub->isCall_Scripted() || stub->next() != entry.fallbackStub())
     603           6 :         return nullptr;
     604             : 
     605           0 :     return stub->toCall_Scripted()->callee();
     606             : }
     607             : 
     608             : JSObject*
     609           4 : BaselineInspector::getTemplateObjectForNative(jsbytecode* pc, Native native)
     610             : {
     611           4 :     if (!hasBaselineScript())
     612           0 :         return nullptr;
     613             : 
     614           4 :     const ICEntry& entry = icEntryFromPC(pc);
     615           4 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     616           4 :         if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
     617           4 :             return stub->toCall_Native()->templateObject();
     618             :     }
     619             : 
     620           0 :     return nullptr;
     621             : }
     622             : 
     623             : bool
     624           0 : BaselineInspector::isOptimizableConstStringSplit(jsbytecode* pc, JSString** strOut,
     625             :                                                  JSString** sepOut, JSObject** objOut)
     626             : {
     627           0 :     if (!hasBaselineScript())
     628           0 :         return false;
     629             : 
     630           0 :     const ICEntry& entry = icEntryFromPC(pc);
     631             : 
     632             :     // If ConstStringSplit stub is attached, must have only one stub attached.
     633           0 :     if (entry.fallbackStub()->numOptimizedStubs() != 1)
     634           0 :         return false;
     635             : 
     636           0 :     ICStub* stub = entry.firstStub();
     637           0 :     if (stub->kind() != ICStub::Call_ConstStringSplit)
     638           0 :         return false;
     639             : 
     640           0 :     *strOut = stub->toCall_ConstStringSplit()->expectedStr();
     641           0 :     *sepOut = stub->toCall_ConstStringSplit()->expectedSep();
     642           0 :     *objOut = stub->toCall_ConstStringSplit()->templateObject();
     643           0 :     return true;
     644             : }
     645             : 
     646             : JSObject*
     647           0 : BaselineInspector::getTemplateObjectForClassHook(jsbytecode* pc, const Class* clasp)
     648             : {
     649           0 :     if (!hasBaselineScript())
     650           0 :         return nullptr;
     651             : 
     652           0 :     const ICEntry& entry = icEntryFromPC(pc);
     653           0 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     654           0 :         if (stub->isCall_ClassHook() && stub->toCall_ClassHook()->clasp() == clasp)
     655           0 :             return stub->toCall_ClassHook()->templateObject();
     656             :     }
     657             : 
     658           0 :     return nullptr;
     659             : }
     660             : 
     661             : JSObject*
     662           0 : BaselineInspector::getTemplateObjectForSimdCtor(jsbytecode* pc, SimdType simdType)
     663             : {
     664           0 :     if (!hasBaselineScript())
     665           0 :         return nullptr;
     666             : 
     667           0 :     const ICEntry& entry = icEntryFromPC(pc);
     668           0 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     669           0 :         if (stub->isCall_ClassHook() && stub->toCall_ClassHook()->clasp() == &SimdTypeDescr::class_) {
     670           0 :             JSObject* templateObj = stub->toCall_ClassHook()->templateObject();
     671           0 :             InlineTypedObject& typedObj = templateObj->as<InlineTypedObject>();
     672           0 :             if (typedObj.typeDescr().as<SimdTypeDescr>().type() == simdType)
     673           0 :                 return templateObj;
     674             :         }
     675             :     }
     676             : 
     677           0 :     return nullptr;
     678             : }
     679             : 
     680             : LexicalEnvironmentObject*
     681           0 : BaselineInspector::templateNamedLambdaObject()
     682             : {
     683           0 :     if (!hasBaselineScript())
     684           0 :         return nullptr;
     685             : 
     686           0 :     JSObject* res = baselineScript()->templateEnvironment();
     687           0 :     if (script->bodyScope()->hasEnvironment())
     688           0 :         res = res->enclosingEnvironment();
     689           0 :     MOZ_ASSERT(res);
     690             : 
     691           0 :     return &res->as<LexicalEnvironmentObject>();
     692             : }
     693             : 
     694             : CallObject*
     695           4 : BaselineInspector::templateCallObject()
     696             : {
     697           4 :     if (!hasBaselineScript())
     698           0 :         return nullptr;
     699             : 
     700           4 :     JSObject* res = baselineScript()->templateEnvironment();
     701           4 :     MOZ_ASSERT(res);
     702             : 
     703           4 :     return &res->as<CallObject>();
     704             : }
     705             : 
     706             : static bool
     707          56 : MatchCacheIRReceiverGuard(CacheIRReader& reader, ICStub* stub, const CacheIRStubInfo* stubInfo,
     708             :                           ObjOperandId objId, ReceiverGuard* receiver)
     709             : {
     710             :     // This matches the CacheIR emitted in TestMatchingReceiver.
     711             :     //
     712             :     // Either:
     713             :     //
     714             :     //   GuardShape objId
     715             :     //
     716             :     // or:
     717             :     //
     718             :     //   GuardGroup objId
     719             :     //   [GuardNoUnboxedExpando objId]
     720             :     //
     721             :     // or:
     722             :     //
     723             :     //   GuardGroup objId
     724             :     //   expandoId: GuardAndLoadUnboxedExpando
     725             :     //   GuardShape expandoId
     726             : 
     727          56 :     *receiver = ReceiverGuard();
     728             : 
     729          56 :     if (reader.matchOp(CacheOp::GuardShape, objId)) {
     730             :         // The first case.
     731          10 :         receiver->shape = stubInfo->getStubField<Shape*>(stub, reader.stubOffset());
     732          10 :         return true;
     733             :     }
     734             : 
     735          46 :     if (!reader.matchOp(CacheOp::GuardGroup, objId))
     736          10 :         return false;
     737          36 :     receiver->group = stubInfo->getStubField<ObjectGroup*>(stub, reader.stubOffset());
     738             : 
     739          36 :     if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId)) {
     740             :         // Second case, just a group guard.
     741          36 :         reader.matchOp(CacheOp::GuardNoUnboxedExpando, objId);
     742          36 :         return true;
     743             :     }
     744             : 
     745             :     // Third case.
     746           0 :     ObjOperandId expandoId = reader.objOperandId();
     747           0 :     if (!reader.matchOp(CacheOp::GuardShape, expandoId))
     748           0 :         return false;
     749             : 
     750           0 :     receiver->shape = stubInfo->getStubField<Shape*>(stub, reader.stubOffset());
     751           0 :     return true;
     752             : }
     753             : 
     754             : static bool
     755           0 : AddCacheIRGlobalGetter(ICCacheIR_Monitored* stub, bool innerized,
     756             :                        JSObject** holder_, Shape** holderShape_,
     757             :                        JSFunction** commonGetter, Shape** globalShape_, bool* isOwnProperty,
     758             :                        BaselineInspector::ReceiverVector& receivers,
     759             :                        BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
     760             :                        JSScript* script)
     761             : {
     762             :     // We are matching on the IR generated by tryAttachGlobalNameGetter:
     763             :     //
     764             :     //   GuardShape objId
     765             :     //   globalId = LoadEnclosingEnvironment objId
     766             :     //   GuardShape globalId
     767             :     //   <holderId = LoadObject <holder>>
     768             :     //   <GuardShape holderId>
     769             :     //   CallNativeGetterResult globalId
     770             : 
     771           0 :     CacheIRReader reader(stub->stubInfo());
     772             : 
     773           0 :     ObjOperandId objId = ObjOperandId(0);
     774           0 :     if (!reader.matchOp(CacheOp::GuardShape, objId))
     775           0 :         return false;
     776           0 :     Shape* globalLexicalShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
     777             : 
     778           0 :     if (!reader.matchOp(CacheOp::LoadEnclosingEnvironment, objId))
     779           0 :         return false;
     780           0 :     ObjOperandId globalId = reader.objOperandId();
     781             : 
     782           0 :     if (!reader.matchOp(CacheOp::GuardShape, globalId))
     783           0 :         return false;
     784           0 :     Shape* globalShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
     785           0 :     MOZ_ASSERT(globalShape->getObjectClass()->flags & JSCLASS_IS_GLOBAL);
     786             : 
     787           0 :     JSObject* holder = &script->global();
     788           0 :     Shape* holderShape = globalShape;
     789           0 :     if (reader.matchOp(CacheOp::LoadObject)) {
     790           0 :         ObjOperandId holderId = reader.objOperandId();
     791           0 :         holder = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
     792             : 
     793           0 :         if (!reader.matchOp(CacheOp::GuardShape, holderId))
     794           0 :             return false;
     795           0 :         holderShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
     796             :     }
     797             : 
     798             :     // This guard will always fail, try the next stub.
     799           0 :     if (holder->as<NativeObject>().lastProperty() != holderShape)
     800           0 :         return true;
     801             : 
     802           0 :     if (!reader.matchOp(CacheOp::CallNativeGetterResult, globalId))
     803           0 :         return false;
     804           0 :     size_t offset = reader.stubOffset();
     805             :     JSFunction* getter =
     806           0 :         &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();
     807             : 
     808           0 :     ReceiverGuard receiver;
     809           0 :     receiver.shape = globalLexicalShape;
     810           0 :     if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
     811           0 :         return false;
     812             : 
     813           0 :     if (!*commonGetter) {
     814           0 :         *holder_ = holder;
     815           0 :         *holderShape_ = holderShape;
     816           0 :         *commonGetter = getter;
     817           0 :         *globalShape_ = globalShape;
     818             : 
     819             :         // This is always false, because the getters never live on the globalLexical.
     820           0 :         *isOwnProperty = false;
     821           0 :     } else if (*isOwnProperty || holderShape != *holderShape_ || globalShape != *globalShape_) {
     822           0 :         return false;
     823             :     } else {
     824           0 :         MOZ_ASSERT(*commonGetter == getter);
     825             :     }
     826             : 
     827           0 :     return true;
     828             : }
     829             : 
     830             : static bool
     831          20 : AddCacheIRGetPropFunction(ICCacheIR_Monitored* stub, bool innerized,
     832             :                           JSObject** holder, Shape** holderShape,
     833             :                           JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty,
     834             :                           BaselineInspector::ReceiverVector& receivers,
     835             :                           BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
     836             :                           JSScript* script)
     837             : {
     838             :     // We match either an own getter:
     839             :     //
     840             :     //   GuardIsObject objId
     841             :     //   [..WindowProxy innerization..]
     842             :     //   <GuardReceiver objId>
     843             :     //   Call(Scripted|Native)GetterResult objId
     844             :     //
     845             :     // Or a getter on the prototype:
     846             :     //
     847             :     //   GuardIsObject objId
     848             :     //   [..WindowProxy innerization..]
     849             :     //   <GuardReceiver objId>
     850             :     //   LoadObject holderId
     851             :     //   GuardShape holderId
     852             :     //   Call(Scripted|Native)GetterResult objId
     853             :     //
     854             :     // If |innerized| is true, we replaced a WindowProxy with the Window
     855             :     // object and we're only interested in Baseline getter stubs that performed
     856             :     // the same optimization. This means we expect the following ops for the
     857             :     // [..WindowProxy innerization..] above:
     858             :     //
     859             :     //   GuardClass objId WindowProxy
     860             :     //   objId = LoadObject <global>
     861             : 
     862          20 :     CacheIRReader reader(stub->stubInfo());
     863             : 
     864          20 :     ObjOperandId objId = ObjOperandId(0);
     865          20 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
     866           0 :         return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape, commonGetter,
     867             :                                       globalShape, isOwnProperty, receivers, convertUnboxedGroups,
     868           0 :                                       script);
     869             :     }
     870             : 
     871          20 :     if (innerized) {
     872           0 :         if (!reader.matchOp(CacheOp::GuardClass, objId) ||
     873           0 :             reader.guardClassKind() != GuardClassKind::WindowProxy)
     874             :         {
     875           0 :             return false;
     876             :         }
     877           0 :         if (!reader.matchOp(CacheOp::LoadObject))
     878           0 :             return false;
     879           0 :         objId = reader.objOperandId();
     880             :         DebugOnly<JSObject*> obj =
     881           0 :             stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
     882           0 :         MOZ_ASSERT(obj->is<GlobalObject>());
     883             :     }
     884             : 
     885          20 :     ReceiverGuard receiver;
     886          20 :     if (!MatchCacheIRReceiverGuard(reader, stub, stub->stubInfo(), objId, &receiver))
     887          10 :         return false;
     888             : 
     889          20 :     if (reader.matchOp(CacheOp::CallScriptedGetterResult, objId) ||
     890          10 :         reader.matchOp(CacheOp::CallNativeGetterResult, objId))
     891             :     {
     892             :         // This is an own property getter, the first case.
     893           0 :         MOZ_ASSERT(receiver.shape);
     894           0 :         MOZ_ASSERT(!receiver.group);
     895             : 
     896           0 :         size_t offset = reader.stubOffset();
     897             :         JSFunction* getter =
     898           0 :             &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();
     899             : 
     900           0 :         if (*commonGetter && (!*isOwnProperty || *globalShape || *holderShape != receiver.shape))
     901           0 :             return false;
     902             : 
     903           0 :         MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter);
     904           0 :         *holder = nullptr;
     905           0 :         *holderShape = receiver.shape;
     906           0 :         *commonGetter = getter;
     907           0 :         *isOwnProperty = true;
     908           0 :         return true;
     909             :     }
     910             : 
     911          10 :     if (!reader.matchOp(CacheOp::LoadObject))
     912          10 :         return false;
     913           0 :     ObjOperandId holderId = reader.objOperandId();
     914           0 :     JSObject* obj = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset());
     915             : 
     916           0 :     if (!reader.matchOp(CacheOp::GuardShape, holderId))
     917           0 :         return false;
     918           0 :     Shape* objShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
     919             : 
     920           0 :     if (!reader.matchOp(CacheOp::CallScriptedGetterResult, objId) &&
     921           0 :         !reader.matchOp(CacheOp::CallNativeGetterResult, objId))
     922             :     {
     923           0 :         return false;
     924             :     }
     925             : 
     926             :     // A getter on the prototype.
     927           0 :     size_t offset = reader.stubOffset();
     928             :     JSFunction* getter =
     929           0 :         &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();
     930             : 
     931           0 :     Shape* thisGlobalShape = nullptr;
     932           0 :     if (getter->isNative() && receiver.shape &&
     933           0 :         (receiver.shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL))
     934             :     {
     935           0 :         thisGlobalShape = receiver.shape;
     936             :     }
     937             : 
     938           0 :     if (*commonGetter &&
     939           0 :         (*isOwnProperty || *globalShape != thisGlobalShape || *holderShape != objShape))
     940             :     {
     941           0 :         return false;
     942             :     }
     943             : 
     944           0 :     MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter);
     945             : 
     946           0 :     if (obj->as<NativeObject>().lastProperty() != objShape) {
     947             :         // Skip this stub as the shape is no longer correct.
     948           0 :         return true;
     949             :     }
     950             : 
     951           0 :     if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
     952           0 :         return false;
     953             : 
     954           0 :     *holder = obj;
     955           0 :     *holderShape = objShape;
     956           0 :     *commonGetter = getter;
     957           0 :     *isOwnProperty = false;
     958           0 :     return true;
     959             : }
     960             : 
     961             : bool
     962          52 : BaselineInspector::commonGetPropFunction(jsbytecode* pc, bool innerized,
     963             :                                          JSObject** holder, Shape** holderShape,
     964             :                                          JSFunction** commonGetter, Shape** globalShape,
     965             :                                          bool* isOwnProperty,
     966             :                                          ReceiverVector& receivers,
     967             :                                          ObjectGroupVector& convertUnboxedGroups)
     968             : {
     969          52 :     if (!hasBaselineScript())
     970          29 :         return false;
     971             : 
     972          23 :     MOZ_ASSERT(receivers.empty());
     973          23 :     MOZ_ASSERT(convertUnboxedGroups.empty());
     974             : 
     975          23 :     *globalShape = nullptr;
     976          23 :     *commonGetter = nullptr;
     977          23 :     const ICEntry& entry = icEntryFromPC(pc);
     978             : 
     979          23 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
     980          23 :         if (stub->isCacheIR_Monitored()) {
     981          20 :             if (!AddCacheIRGetPropFunction(stub->toCacheIR_Monitored(), innerized,
     982             :                                            holder, holderShape,
     983             :                                            commonGetter, globalShape, isOwnProperty, receivers,
     984             :                                            convertUnboxedGroups, script))
     985             :             {
     986          20 :                 return false;
     987             :             }
     988           3 :         } else if (stub->isGetProp_Fallback()) {
     989             :             // If we have an unoptimizable access, don't try to optimize.
     990           3 :             if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
     991           3 :                 return false;
     992           0 :         } else if (stub->isGetName_Fallback()) {
     993           0 :             if (stub->toGetName_Fallback()->hadUnoptimizableAccess())
     994           0 :                 return false;
     995             :         } else {
     996           0 :             return false;
     997             :         }
     998             :     }
     999             : 
    1000           0 :     if (!*commonGetter)
    1001           0 :         return false;
    1002             : 
    1003           0 :     MOZ_ASSERT(*isOwnProperty == !*holder);
    1004           0 :     MOZ_ASSERT(*isOwnProperty == (receivers.empty() && convertUnboxedGroups.empty()));
    1005           0 :     return true;
    1006             : }
    1007             : 
    1008             : static JSFunction*
    1009          56 : GetMegamorphicGetterSetterFunction(ICStub* stub, const CacheIRStubInfo* stubInfo, bool isGetter)
    1010             : {
    1011             :     // We match:
    1012             :     //
    1013             :     //   GuardIsObject objId
    1014             :     //   GuardHasGetterSetter objId propShape
    1015             :     //
    1016             :     // propShape has the getter/setter we're interested in.
    1017             : 
    1018          56 :     CacheIRReader reader(stubInfo);
    1019             : 
    1020          56 :     ObjOperandId objId = ObjOperandId(0);
    1021          56 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId))
    1022           0 :         return nullptr;
    1023             : 
    1024          56 :     if (!reader.matchOp(CacheOp::GuardHasGetterSetter, objId))
    1025          56 :         return nullptr;
    1026           0 :     Shape* propShape = stubInfo->getStubField<Shape*>(stub, reader.stubOffset());
    1027             : 
    1028           0 :     JSObject* obj = isGetter ? propShape->getterObject() : propShape->setterObject();
    1029           0 :     return &obj->as<JSFunction>();
    1030             : }
    1031             : 
    1032             : bool
    1033         111 : BaselineInspector::megamorphicGetterSetterFunction(jsbytecode* pc, bool isGetter,
    1034             :                                                    JSFunction** getterOrSetter)
    1035             : {
    1036         111 :     if (!hasBaselineScript())
    1037          29 :         return false;
    1038             : 
    1039          82 :     *getterOrSetter = nullptr;
    1040          82 :     const ICEntry& entry = icEntryFromPC(pc);
    1041             : 
    1042          82 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
    1043          82 :         if (stub->isCacheIR_Monitored()) {
    1044          20 :             MOZ_ASSERT(isGetter);
    1045             :             JSFunction* getter =
    1046          20 :                 GetMegamorphicGetterSetterFunction(stub,
    1047             :                                                    stub->toCacheIR_Monitored()->stubInfo(),
    1048          20 :                                                    isGetter);
    1049          20 :             if (!getter || (*getterOrSetter && *getterOrSetter != getter))
    1050          20 :                 return false;
    1051           0 :             *getterOrSetter = getter;
    1052           0 :             continue;
    1053             :         }
    1054          62 :         if (stub->isCacheIR_Updated()) {
    1055          36 :             MOZ_ASSERT(!isGetter);
    1056             :             JSFunction* setter =
    1057          36 :                 GetMegamorphicGetterSetterFunction(stub,
    1058             :                                                    stub->toCacheIR_Updated()->stubInfo(),
    1059          36 :                                                    isGetter);
    1060          36 :             if (!setter || (*getterOrSetter && *getterOrSetter != setter))
    1061          36 :                 return false;
    1062           0 :             *getterOrSetter = setter;
    1063           0 :             continue;
    1064             :         }
    1065          26 :         if (stub->isGetProp_Fallback()) {
    1066           3 :             if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
    1067           3 :                 return false;
    1068           0 :             if (stub->toGetProp_Fallback()->state().mode() != ICState::Mode::Megamorphic)
    1069           0 :                 return false;
    1070           0 :             continue;
    1071             :         }
    1072          23 :         if (stub->isSetProp_Fallback()) {
    1073          23 :             if (stub->toSetProp_Fallback()->hadUnoptimizableAccess())
    1074           0 :                 return false;
    1075          23 :             if (stub->toSetProp_Fallback()->state().mode() != ICState::Mode::Megamorphic)
    1076          23 :                 return false;
    1077           0 :             continue;
    1078             :         }
    1079             : 
    1080           0 :         return false;
    1081             :     }
    1082             : 
    1083           0 :     if (!*getterOrSetter)
    1084           0 :         return false;
    1085             : 
    1086           0 :     return true;
    1087             : }
    1088             : 
    1089             : static bool
    1090          36 : AddCacheIRSetPropFunction(ICCacheIR_Updated* stub, JSObject** holder, Shape** holderShape,
    1091             :                           JSFunction** commonSetter, bool* isOwnProperty,
    1092             :                           BaselineInspector::ReceiverVector& receivers,
    1093             :                           BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
    1094             : {
    1095             :     // We match either an own setter:
    1096             :     //
    1097             :     //   GuardIsObject objId
    1098             :     //   <GuardReceiver objId>
    1099             :     //   Call(Scripted|Native)Setter objId
    1100             :     //
    1101             :     // Or a setter on the prototype:
    1102             :     //
    1103             :     //   GuardIsObject objId
    1104             :     //   <GuardReceiver objId>
    1105             :     //   LoadObject holderId
    1106             :     //   GuardShape holderId
    1107             :     //   Call(Scripted|Native)Setter objId
    1108             : 
    1109          36 :     CacheIRReader reader(stub->stubInfo());
    1110             : 
    1111          36 :     ObjOperandId objId = ObjOperandId(0);
    1112          36 :     if (!reader.matchOp(CacheOp::GuardIsObject, objId))
    1113           0 :         return false;
    1114             : 
    1115          36 :     ReceiverGuard receiver;
    1116          36 :     if (!MatchCacheIRReceiverGuard(reader, stub, stub->stubInfo(), objId, &receiver))
    1117           0 :         return false;
    1118             : 
    1119          72 :     if (reader.matchOp(CacheOp::CallScriptedSetter, objId) ||
    1120          36 :         reader.matchOp(CacheOp::CallNativeSetter, objId))
    1121             :     {
    1122             :         // This is an own property setter, the first case.
    1123           0 :         MOZ_ASSERT(receiver.shape);
    1124           0 :         MOZ_ASSERT(!receiver.group);
    1125             : 
    1126           0 :         size_t offset = reader.stubOffset();
    1127             :         JSFunction* setter =
    1128           0 :             &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();
    1129             : 
    1130           0 :         if (*commonSetter && (!*isOwnProperty || *holderShape != receiver.shape))
    1131           0 :             return false;
    1132             : 
    1133           0 :         MOZ_ASSERT_IF(*commonSetter, *commonSetter == setter);
    1134           0 :         *holder = nullptr;
    1135           0 :         *holderShape = receiver.shape;
    1136           0 :         *commonSetter = setter;
    1137           0 :         *isOwnProperty = true;
    1138           0 :         return true;
    1139             :     }
    1140             : 
    1141          36 :     if (!reader.matchOp(CacheOp::LoadObject))
    1142          36 :         return false;
    1143           0 :     ObjOperandId holderId = reader.objOperandId();
    1144           0 :     JSObject* obj = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset());
    1145             : 
    1146           0 :     if (!reader.matchOp(CacheOp::GuardShape, holderId))
    1147           0 :         return false;
    1148           0 :     Shape* objShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
    1149             : 
    1150           0 :     if (!reader.matchOp(CacheOp::CallScriptedSetter, objId) &&
    1151           0 :         !reader.matchOp(CacheOp::CallNativeSetter, objId))
    1152             :     {
    1153           0 :         return false;
    1154             :     }
    1155             : 
    1156             :     // A setter on the prototype.
    1157           0 :     size_t offset = reader.stubOffset();
    1158             :     JSFunction* setter =
    1159           0 :         &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();
    1160             : 
    1161           0 :     if (*commonSetter && (*isOwnProperty || *holderShape != objShape))
    1162           0 :         return false;
    1163             : 
    1164           0 :     MOZ_ASSERT_IF(*commonSetter, *commonSetter == setter);
    1165             : 
    1166           0 :     if (obj->as<NativeObject>().lastProperty() != objShape) {
    1167             :         // Skip this stub as the shape is no longer correct.
    1168           0 :         return true;
    1169             :     }
    1170             : 
    1171           0 :     if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
    1172           0 :         return false;
    1173             : 
    1174           0 :     *holder = obj;
    1175           0 :     *holderShape = objShape;
    1176           0 :     *commonSetter = setter;
    1177           0 :     *isOwnProperty = false;
    1178           0 :     return true;
    1179             : }
    1180             : 
    1181             : bool
    1182          59 : BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shape** holderShape,
    1183             :                                          JSFunction** commonSetter, bool* isOwnProperty,
    1184             :                                          ReceiverVector& receivers,
    1185             :                                          ObjectGroupVector& convertUnboxedGroups)
    1186             : {
    1187          59 :     if (!hasBaselineScript())
    1188           0 :         return false;
    1189             : 
    1190          59 :     MOZ_ASSERT(receivers.empty());
    1191          59 :     MOZ_ASSERT(convertUnboxedGroups.empty());
    1192             : 
    1193          59 :     *commonSetter = nullptr;
    1194          59 :     const ICEntry& entry = icEntryFromPC(pc);
    1195             : 
    1196          82 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
    1197          59 :         if (stub->isCacheIR_Updated()) {
    1198          36 :             if (!AddCacheIRSetPropFunction(stub->toCacheIR_Updated(),
    1199             :                                            holder, holderShape,
    1200             :                                            commonSetter, isOwnProperty, receivers,
    1201             :                                            convertUnboxedGroups))
    1202             :             {
    1203          36 :                 return false;
    1204             :             }
    1205          46 :         } else if (!stub->isSetProp_Fallback() ||
    1206          23 :                    stub->toSetProp_Fallback()->hadUnoptimizableAccess())
    1207             :         {
    1208             :             // We have an unoptimizable access, so don't try to optimize.
    1209           0 :             return false;
    1210             :         }
    1211             :     }
    1212             : 
    1213          23 :     if (!*commonSetter)
    1214          23 :         return false;
    1215             : 
    1216           0 :     MOZ_ASSERT(*isOwnProperty == !*holder);
    1217           0 :     return true;
    1218             : }
    1219             : 
    1220             : static MIRType
    1221           0 : GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub)
    1222             : {
    1223           0 :     CacheIRReader reader(stub->stubInfo());
    1224             : 
    1225           0 :     if (reader.matchOp(CacheOp::GuardIsObject, ValOperandId(0)))
    1226           0 :         return MIRType::Object;
    1227           0 :     if (reader.matchOp(CacheOp::GuardIsString, ValOperandId(0)))
    1228           0 :         return MIRType::String;
    1229           0 :     if (reader.matchOp(CacheOp::GuardType, ValOperandId(0))) {
    1230           0 :         JSValueType type = reader.valueType();
    1231           0 :         return MIRTypeFromValueType(type);
    1232             :     }
    1233             : 
    1234           0 :     MOZ_ASSERT_UNREACHABLE("Unexpected instruction");
    1235             :     return MIRType::Value;
    1236             : }
    1237             : 
    1238             : MIRType
    1239         190 : BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
    1240             : {
    1241         190 :     if (!hasBaselineScript())
    1242         187 :         return MIRType::Value;
    1243             : 
    1244           3 :     const ICEntry& entry = icEntryFromPC(pc);
    1245           3 :     MIRType type = MIRType::None;
    1246             : 
    1247           6 :     for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
    1248             :         MIRType stubType;
    1249           3 :         switch (stub->kind()) {
    1250             :           case ICStub::GetProp_Fallback:
    1251           3 :             if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
    1252           0 :                 return MIRType::Value;
    1253           3 :             continue;
    1254             : 
    1255             :           case ICStub::GetElem_Fallback:
    1256           0 :             if (stub->toGetElem_Fallback()->hadUnoptimizableAccess())
    1257           0 :                 return MIRType::Value;
    1258           0 :             continue;
    1259             : 
    1260             :           case ICStub::CacheIR_Monitored:
    1261           0 :             stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored());
    1262           0 :             if (stubType == MIRType::Value)
    1263           0 :                 return MIRType::Value;
    1264           0 :             break;
    1265             : 
    1266             :           default:
    1267           0 :             MOZ_CRASH("Unexpected stub");
    1268             :         }
    1269             : 
    1270           0 :         if (type != MIRType::None) {
    1271           0 :             if (type != stubType)
    1272           0 :                 return MIRType::Value;
    1273             :         } else {
    1274           0 :             type = stubType;
    1275             :         }
    1276             :     }
    1277             : 
    1278           3 :     return (type == MIRType::None) ? MIRType::Value : type;
    1279             : }
    1280             : 
    1281             : bool
    1282           0 : BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
    1283             :                                   JSObject** prototypeObject)
    1284             : {
    1285           0 :     MOZ_ASSERT(*pc == JSOP_INSTANCEOF);
    1286             : 
    1287           0 :     if (!hasBaselineScript())
    1288           0 :         return false;
    1289             : 
    1290           0 :     const ICEntry& entry = icEntryFromPC(pc);
    1291             : 
    1292           0 :     ICStub* stub = entry.firstStub();
    1293           0 :     if (!stub->isInstanceOf_Function() ||
    1294           0 :         !stub->next()->isInstanceOf_Fallback() ||
    1295           0 :         stub->next()->toInstanceOf_Fallback()->hadUnoptimizableAccess())
    1296             :     {
    1297           0 :         return false;
    1298             :     }
    1299             : 
    1300           0 :     ICInstanceOf_Function* optStub = stub->toInstanceOf_Function();
    1301           0 :     *shape = optStub->shape();
    1302           0 :     *prototypeObject = optStub->prototypeObject();
    1303           0 :     *slot = optStub->slot();
    1304             : 
    1305           0 :     if (IsInsideNursery(*prototypeObject))
    1306           0 :         return false;
    1307             : 
    1308           0 :     return true;
    1309             : }

Generated by: LCOV version 1.13