LCOV - code coverage report
Current view: top level - js/src/jit - MCallOptimize.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 241 2248 10.7 %
Date: 2017-07-14 16:53:18 Functions: 18 109 16.5 %
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 "mozilla/Casting.h"
       8             : 
       9             : #include "jsmath.h"
      10             : #include "jsobj.h"
      11             : #include "jsstr.h"
      12             : 
      13             : #include "builtin/AtomicsObject.h"
      14             : #include "builtin/Intl.h"
      15             : #include "builtin/SIMD.h"
      16             : #include "builtin/TestingFunctions.h"
      17             : #include "builtin/TypedObject.h"
      18             : #include "jit/BaselineInspector.h"
      19             : #include "jit/InlinableNatives.h"
      20             : #include "jit/IonBuilder.h"
      21             : #include "jit/Lowering.h"
      22             : #include "jit/MIR.h"
      23             : #include "jit/MIRGraph.h"
      24             : #include "vm/ArgumentsObject.h"
      25             : #include "vm/ProxyObject.h"
      26             : #include "vm/SelfHosting.h"
      27             : #include "vm/TypedArrayObject.h"
      28             : 
      29             : #include "jsscriptinlines.h"
      30             : 
      31             : #include "jit/shared/Lowering-shared-inl.h"
      32             : #include "vm/NativeObject-inl.h"
      33             : #include "vm/StringObject-inl.h"
      34             : #include "vm/UnboxedObject-inl.h"
      35             : 
      36             : using mozilla::ArrayLength;
      37             : using mozilla::AssertedCast;
      38             : 
      39             : using JS::DoubleNaNValue;
      40             : using JS::TrackedOutcome;
      41             : using JS::TrackedStrategy;
      42             : using JS::TrackedTypeSite;
      43             : 
      44             : namespace js {
      45             : namespace jit {
      46             : 
      47             : IonBuilder::InliningResult
      48         116 : IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
      49             : {
      50         116 :     MOZ_ASSERT(target->isNative());
      51             : 
      52         116 :     if (!optimizationInfo().inlineNative()) {
      53           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon);
      54           0 :         return InliningStatus_NotInlined;
      55             :     }
      56             : 
      57         116 :     if (!target->jitInfo() || target->jitInfo()->type() != JSJitInfo::InlinableNative) {
      58             :         // Reaching here means we tried to inline a native for which there is no
      59             :         // Ion specialization.
      60           6 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoSpecialization);
      61           6 :         return InliningStatus_NotInlined;
      62             :     }
      63             : 
      64             :     // Default failure reason is observing an unsupported type.
      65         110 :     trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadType);
      66             : 
      67         110 :     if (shouldAbortOnPreliminaryGroups(callInfo.thisArg()))
      68           0 :         return InliningStatus_NotInlined;
      69         304 :     for (size_t i = 0; i < callInfo.argc(); i++) {
      70         195 :         if (shouldAbortOnPreliminaryGroups(callInfo.getArg(i)))
      71           1 :             return InliningStatus_NotInlined;
      72             :     }
      73             : 
      74         109 :     switch (InlinableNative inlNative = target->jitInfo()->inlinableNative) {
      75             :       // Array natives.
      76             :       case InlinableNative::Array:
      77           0 :         return inlineArray(callInfo);
      78             :       case InlinableNative::ArrayIsArray:
      79           0 :         return inlineArrayIsArray(callInfo);
      80             :       case InlinableNative::ArrayJoin:
      81           1 :         return inlineArrayJoin(callInfo);
      82             :       case InlinableNative::ArrayPop:
      83           0 :         return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
      84             :       case InlinableNative::ArrayShift:
      85           0 :         return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
      86             :       case InlinableNative::ArrayPush:
      87           4 :         return inlineArrayPush(callInfo);
      88             :       case InlinableNative::ArraySlice:
      89           0 :         return inlineArraySlice(callInfo);
      90             : 
      91             :       // Array intrinsics.
      92             :       case InlinableNative::IntrinsicNewArrayIterator:
      93           4 :         return inlineNewIterator(callInfo, MNewIterator::ArrayIterator);
      94             : 
      95             :       // Atomic natives.
      96             :       case InlinableNative::AtomicsCompareExchange:
      97           0 :         return inlineAtomicsCompareExchange(callInfo);
      98             :       case InlinableNative::AtomicsExchange:
      99           0 :         return inlineAtomicsExchange(callInfo);
     100             :       case InlinableNative::AtomicsLoad:
     101           0 :         return inlineAtomicsLoad(callInfo);
     102             :       case InlinableNative::AtomicsStore:
     103           0 :         return inlineAtomicsStore(callInfo);
     104             :       case InlinableNative::AtomicsAdd:
     105             :       case InlinableNative::AtomicsSub:
     106             :       case InlinableNative::AtomicsAnd:
     107             :       case InlinableNative::AtomicsOr:
     108             :       case InlinableNative::AtomicsXor:
     109           0 :         return inlineAtomicsBinop(callInfo, inlNative);
     110             :       case InlinableNative::AtomicsIsLockFree:
     111           0 :         return inlineAtomicsIsLockFree(callInfo);
     112             : 
     113             :       // Boolean natives.
     114             :       case InlinableNative::Boolean:
     115           0 :         return inlineBoolean(callInfo);
     116             : 
     117             :       // Intl natives.
     118             :       case InlinableNative::IntlIsCollator:
     119           0 :         return inlineHasClass(callInfo, &CollatorObject::class_);
     120             :       case InlinableNative::IntlIsDateTimeFormat:
     121           0 :         return inlineHasClass(callInfo, &DateTimeFormatObject::class_);
     122             :       case InlinableNative::IntlIsNumberFormat:
     123           0 :         return inlineHasClass(callInfo, &NumberFormatObject::class_);
     124             :       case InlinableNative::IntlIsPluralRules:
     125           0 :         return inlineHasClass(callInfo, &PluralRulesObject::class_);
     126             : 
     127             :       // Math natives.
     128             :       case InlinableNative::MathAbs:
     129           0 :         return inlineMathAbs(callInfo);
     130             :       case InlinableNative::MathFloor:
     131           0 :         return inlineMathFloor(callInfo);
     132             :       case InlinableNative::MathCeil:
     133           0 :         return inlineMathCeil(callInfo);
     134             :       case InlinableNative::MathRound:
     135           0 :         return inlineMathRound(callInfo);
     136             :       case InlinableNative::MathClz32:
     137           0 :         return inlineMathClz32(callInfo);
     138             :       case InlinableNative::MathSqrt:
     139           0 :         return inlineMathSqrt(callInfo);
     140             :       case InlinableNative::MathATan2:
     141           0 :         return inlineMathAtan2(callInfo);
     142             :       case InlinableNative::MathHypot:
     143           0 :         return inlineMathHypot(callInfo);
     144             :       case InlinableNative::MathMax:
     145           8 :         return inlineMathMinMax(callInfo, true /* max */);
     146             :       case InlinableNative::MathMin:
     147           8 :         return inlineMathMinMax(callInfo, false /* max */);
     148             :       case InlinableNative::MathPow:
     149           0 :         return inlineMathPow(callInfo);
     150             :       case InlinableNative::MathRandom:
     151           0 :         return inlineMathRandom(callInfo);
     152             :       case InlinableNative::MathImul:
     153           0 :         return inlineMathImul(callInfo);
     154             :       case InlinableNative::MathFRound:
     155           0 :         return inlineMathFRound(callInfo);
     156             :       case InlinableNative::MathSin:
     157           0 :         return inlineMathFunction(callInfo, MMathFunction::Sin);
     158             :       case InlinableNative::MathTan:
     159           0 :         return inlineMathFunction(callInfo, MMathFunction::Tan);
     160             :       case InlinableNative::MathCos:
     161           0 :         return inlineMathFunction(callInfo, MMathFunction::Cos);
     162             :       case InlinableNative::MathExp:
     163           0 :         return inlineMathFunction(callInfo, MMathFunction::Exp);
     164             :       case InlinableNative::MathLog:
     165           0 :         return inlineMathFunction(callInfo, MMathFunction::Log);
     166             :       case InlinableNative::MathASin:
     167           0 :         return inlineMathFunction(callInfo, MMathFunction::ASin);
     168             :       case InlinableNative::MathATan:
     169           0 :         return inlineMathFunction(callInfo, MMathFunction::ATan);
     170             :       case InlinableNative::MathACos:
     171           0 :         return inlineMathFunction(callInfo, MMathFunction::ACos);
     172             :       case InlinableNative::MathLog10:
     173           0 :         return inlineMathFunction(callInfo, MMathFunction::Log10);
     174             :       case InlinableNative::MathLog2:
     175           0 :         return inlineMathFunction(callInfo, MMathFunction::Log2);
     176             :       case InlinableNative::MathLog1P:
     177           0 :         return inlineMathFunction(callInfo, MMathFunction::Log1P);
     178             :       case InlinableNative::MathExpM1:
     179           0 :         return inlineMathFunction(callInfo, MMathFunction::ExpM1);
     180             :       case InlinableNative::MathCosH:
     181           0 :         return inlineMathFunction(callInfo, MMathFunction::CosH);
     182             :       case InlinableNative::MathSinH:
     183           0 :         return inlineMathFunction(callInfo, MMathFunction::SinH);
     184             :       case InlinableNative::MathTanH:
     185           0 :         return inlineMathFunction(callInfo, MMathFunction::TanH);
     186             :       case InlinableNative::MathACosH:
     187           0 :         return inlineMathFunction(callInfo, MMathFunction::ACosH);
     188             :       case InlinableNative::MathASinH:
     189           0 :         return inlineMathFunction(callInfo, MMathFunction::ASinH);
     190             :       case InlinableNative::MathATanH:
     191           0 :         return inlineMathFunction(callInfo, MMathFunction::ATanH);
     192             :       case InlinableNative::MathSign:
     193           0 :         return inlineMathFunction(callInfo, MMathFunction::Sign);
     194             :       case InlinableNative::MathTrunc:
     195           0 :         return inlineMathFunction(callInfo, MMathFunction::Trunc);
     196             :       case InlinableNative::MathCbrt:
     197           0 :         return inlineMathFunction(callInfo, MMathFunction::Cbrt);
     198             : 
     199             :       // RegExp natives.
     200             :       case InlinableNative::RegExpMatcher:
     201           0 :         return inlineRegExpMatcher(callInfo);
     202             :       case InlinableNative::RegExpSearcher:
     203           0 :         return inlineRegExpSearcher(callInfo);
     204             :       case InlinableNative::RegExpTester:
     205           0 :         return inlineRegExpTester(callInfo);
     206             :       case InlinableNative::IsRegExpObject:
     207           0 :         return inlineIsRegExpObject(callInfo);
     208             :       case InlinableNative::RegExpPrototypeOptimizable:
     209           0 :         return inlineRegExpPrototypeOptimizable(callInfo);
     210             :       case InlinableNative::RegExpInstanceOptimizable:
     211           0 :         return inlineRegExpInstanceOptimizable(callInfo);
     212             :       case InlinableNative::GetFirstDollarIndex:
     213           0 :         return inlineGetFirstDollarIndex(callInfo);
     214             : 
     215             :       // String natives.
     216             :       case InlinableNative::String:
     217           0 :         return inlineStringObject(callInfo);
     218             :       case InlinableNative::StringCharCodeAt:
     219           3 :         return inlineStrCharCodeAt(callInfo);
     220             :       case InlinableNative::StringFromCharCode:
     221           0 :         return inlineStrFromCharCode(callInfo);
     222             :       case InlinableNative::StringFromCodePoint:
     223           0 :         return inlineStrFromCodePoint(callInfo);
     224             :       case InlinableNative::StringCharAt:
     225           0 :         return inlineStrCharAt(callInfo);
     226             : 
     227             :       // String intrinsics.
     228             :       case InlinableNative::IntrinsicStringReplaceString:
     229           0 :         return inlineStringReplaceString(callInfo);
     230             :       case InlinableNative::IntrinsicStringSplitString:
     231           0 :         return inlineStringSplitString(callInfo);
     232             :       case InlinableNative::IntrinsicNewStringIterator:
     233           0 :         return inlineNewIterator(callInfo, MNewIterator::StringIterator);
     234             : 
     235             :       // Object natives.
     236             :       case InlinableNative::ObjectCreate:
     237           0 :         return inlineObjectCreate(callInfo);
     238             : 
     239             :       // SIMD natives.
     240             :       case InlinableNative::SimdInt32x4:
     241           0 :         return inlineSimd(callInfo, target, SimdType::Int32x4);
     242             :       case InlinableNative::SimdUint32x4:
     243           0 :         return inlineSimd(callInfo, target, SimdType::Uint32x4);
     244             :       case InlinableNative::SimdInt16x8:
     245           0 :         return inlineSimd(callInfo, target, SimdType::Int16x8);
     246             :       case InlinableNative::SimdUint16x8:
     247           0 :         return inlineSimd(callInfo, target, SimdType::Uint16x8);
     248             :       case InlinableNative::SimdInt8x16:
     249           0 :         return inlineSimd(callInfo, target, SimdType::Int8x16);
     250             :       case InlinableNative::SimdUint8x16:
     251           0 :         return inlineSimd(callInfo, target, SimdType::Uint8x16);
     252             :       case InlinableNative::SimdFloat32x4:
     253           0 :         return inlineSimd(callInfo, target, SimdType::Float32x4);
     254             :       case InlinableNative::SimdBool32x4:
     255           0 :         return inlineSimd(callInfo, target, SimdType::Bool32x4);
     256             :       case InlinableNative::SimdBool16x8:
     257           0 :         return inlineSimd(callInfo, target, SimdType::Bool16x8);
     258             :       case InlinableNative::SimdBool8x16:
     259           0 :         return inlineSimd(callInfo, target, SimdType::Bool8x16);
     260             : 
     261             :       // Testing functions.
     262             :       case InlinableNative::TestBailout:
     263           0 :         return inlineBailout(callInfo);
     264             :       case InlinableNative::TestAssertFloat32:
     265           0 :         return inlineAssertFloat32(callInfo);
     266             :       case InlinableNative::TestAssertRecoveredOnBailout:
     267           0 :         return inlineAssertRecoveredOnBailout(callInfo);
     268             : 
     269             :       // Slot intrinsics.
     270             :       case InlinableNative::IntrinsicUnsafeSetReservedSlot:
     271          26 :         return inlineUnsafeSetReservedSlot(callInfo);
     272             :       case InlinableNative::IntrinsicUnsafeGetReservedSlot:
     273          14 :         return inlineUnsafeGetReservedSlot(callInfo, MIRType::Value);
     274             :       case InlinableNative::IntrinsicUnsafeGetObjectFromReservedSlot:
     275           0 :         return inlineUnsafeGetReservedSlot(callInfo, MIRType::Object);
     276             :       case InlinableNative::IntrinsicUnsafeGetInt32FromReservedSlot:
     277           7 :         return inlineUnsafeGetReservedSlot(callInfo, MIRType::Int32);
     278             :       case InlinableNative::IntrinsicUnsafeGetStringFromReservedSlot:
     279           0 :         return inlineUnsafeGetReservedSlot(callInfo, MIRType::String);
     280             :       case InlinableNative::IntrinsicUnsafeGetBooleanFromReservedSlot:
     281           0 :         return inlineUnsafeGetReservedSlot(callInfo, MIRType::Boolean);
     282             : 
     283             :       // Utility intrinsics.
     284             :       case InlinableNative::IntrinsicIsCallable:
     285           1 :         return inlineIsCallable(callInfo);
     286             :       case InlinableNative::IntrinsicIsConstructor:
     287           0 :         return inlineIsConstructor(callInfo);
     288             :       case InlinableNative::IntrinsicToObject:
     289           4 :         return inlineToObject(callInfo);
     290             :       case InlinableNative::IntrinsicIsObject:
     291           7 :         return inlineIsObject(callInfo);
     292             :       case InlinableNative::IntrinsicIsWrappedArrayConstructor:
     293           0 :         return inlineIsWrappedArrayConstructor(callInfo);
     294             :       case InlinableNative::IntrinsicToInteger:
     295           8 :         return inlineToInteger(callInfo);
     296             :       case InlinableNative::IntrinsicToString:
     297           0 :         return inlineToString(callInfo);
     298             :       case InlinableNative::IntrinsicIsConstructing:
     299           0 :         return inlineIsConstructing(callInfo);
     300             :       case InlinableNative::IntrinsicSubstringKernel:
     301           0 :         return inlineSubstringKernel(callInfo);
     302             :       case InlinableNative::IntrinsicIsArrayIterator:
     303           7 :         return inlineHasClass(callInfo, &ArrayIteratorObject::class_);
     304             :       case InlinableNative::IntrinsicIsMapIterator:
     305           0 :         return inlineHasClass(callInfo, &MapIteratorObject::class_);
     306             :       case InlinableNative::IntrinsicIsSetIterator:
     307           0 :         return inlineHasClass(callInfo, &SetIteratorObject::class_);
     308             :       case InlinableNative::IntrinsicIsStringIterator:
     309           0 :         return inlineHasClass(callInfo, &StringIteratorObject::class_);
     310             :       case InlinableNative::IntrinsicObjectHasPrototype:
     311           0 :         return inlineObjectHasPrototype(callInfo);
     312             :       case InlinableNative::IntrinsicFinishBoundFunctionInit:
     313           0 :         return inlineFinishBoundFunctionInit(callInfo);
     314             : 
     315             :       // Map intrinsics.
     316             :       case InlinableNative::IntrinsicGetNextMapEntryForIterator:
     317           0 :         return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map);
     318             : 
     319             :       // Set intrinsics.
     320             :       case InlinableNative::IntrinsicGetNextSetEntryForIterator:
     321           0 :         return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set);
     322             : 
     323             :       // ArrayBuffer intrinsics.
     324             :       case InlinableNative::IntrinsicArrayBufferByteLength:
     325           0 :         return inlineArrayBufferByteLength(callInfo);
     326             :       case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength:
     327           0 :         return inlinePossiblyWrappedArrayBufferByteLength(callInfo);
     328             : 
     329             :       // TypedArray intrinsics.
     330             :       case InlinableNative::TypedArrayConstructor:
     331           0 :         return inlineTypedArray(callInfo, target->native());
     332             :       case InlinableNative::IntrinsicIsTypedArray:
     333           0 :         return inlineIsTypedArray(callInfo);
     334             :       case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
     335           7 :         return inlineIsPossiblyWrappedTypedArray(callInfo);
     336             :       case InlinableNative::IntrinsicPossiblyWrappedTypedArrayLength:
     337           0 :         return inlinePossiblyWrappedTypedArrayLength(callInfo);
     338             :       case InlinableNative::IntrinsicTypedArrayLength:
     339           0 :         return inlineTypedArrayLength(callInfo);
     340             :       case InlinableNative::IntrinsicSetDisjointTypedElements:
     341           0 :         return inlineSetDisjointTypedElements(callInfo);
     342             : 
     343             :       // TypedObject intrinsics.
     344             :       case InlinableNative::IntrinsicObjectIsTypedObject:
     345             :         return inlineHasClass(callInfo,
     346             :                               &OutlineTransparentTypedObject::class_,
     347             :                               &OutlineOpaqueTypedObject::class_,
     348             :                               &InlineTransparentTypedObject::class_,
     349           0 :                               &InlineOpaqueTypedObject::class_);
     350             :       case InlinableNative::IntrinsicObjectIsTransparentTypedObject:
     351             :         return inlineHasClass(callInfo,
     352             :                               &OutlineTransparentTypedObject::class_,
     353           0 :                               &InlineTransparentTypedObject::class_);
     354             :       case InlinableNative::IntrinsicObjectIsOpaqueTypedObject:
     355             :         return inlineHasClass(callInfo,
     356             :                               &OutlineOpaqueTypedObject::class_,
     357           0 :                               &InlineOpaqueTypedObject::class_);
     358             :       case InlinableNative::IntrinsicObjectIsTypeDescr:
     359           0 :         return inlineObjectIsTypeDescr(callInfo);
     360             :       case InlinableNative::IntrinsicTypeDescrIsSimpleType:
     361             :         return inlineHasClass(callInfo,
     362           0 :                               &ScalarTypeDescr::class_, &ReferenceTypeDescr::class_);
     363             :       case InlinableNative::IntrinsicTypeDescrIsArrayType:
     364           0 :         return inlineHasClass(callInfo, &ArrayTypeDescr::class_);
     365             :       case InlinableNative::IntrinsicSetTypedObjectOffset:
     366           0 :         return inlineSetTypedObjectOffset(callInfo);
     367             :       case InlinableNative::Limit:
     368           0 :         break;
     369             :     }
     370             : 
     371           0 :     MOZ_CRASH("Shouldn't get here");
     372             : }
     373             : 
     374             : IonBuilder::InliningResult
     375           0 : IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target)
     376             : {
     377           0 :     MOZ_ASSERT(target->isNative());
     378           0 :     JSNative native = target->native();
     379             : 
     380           0 :     if (!optimizationInfo().inlineNative())
     381           0 :         return InliningStatus_NotInlined;
     382             : 
     383           0 :     MDefinition* thisArg = callInfo.thisArg();
     384           0 :     TemporaryTypeSet* thisTypes = thisArg->resultTypeSet();
     385           0 :     MOZ_ASSERT(callInfo.argc() == 0);
     386             : 
     387           0 :     if (!thisTypes)
     388           0 :         return InliningStatus_NotInlined;
     389             : 
     390             :     // Try to optimize typed array lengths.
     391           0 :     if (TypedArrayObject::isOriginalLengthGetter(native)) {
     392           0 :         Scalar::Type type = thisTypes->getTypedArrayType(constraints());
     393           0 :         if (type == Scalar::MaxTypedArrayViewType)
     394           0 :             return InliningStatus_NotInlined;
     395             : 
     396           0 :         MInstruction* length = addTypedArrayLength(thisArg);
     397           0 :         current->push(length);
     398           0 :         return InliningStatus_Inlined;
     399             :     }
     400             : 
     401             :     // Try to optimize RegExp getters.
     402           0 :     RegExpFlag mask = NoFlags;
     403           0 :     if (RegExpObject::isOriginalFlagGetter(native, &mask)) {
     404           0 :         const Class* clasp = thisTypes->getKnownClass(constraints());
     405           0 :         if (clasp != &RegExpObject::class_)
     406           0 :             return InliningStatus_NotInlined;
     407             : 
     408           0 :         MLoadFixedSlot* flags = MLoadFixedSlot::New(alloc(), thisArg, RegExpObject::flagsSlot());
     409           0 :         current->add(flags);
     410           0 :         flags->setResultType(MIRType::Int32);
     411           0 :         MConstant* maskConst = MConstant::New(alloc(), Int32Value(mask));
     412           0 :         current->add(maskConst);
     413           0 :         MBitAnd* maskedFlag = MBitAnd::New(alloc(), flags, maskConst);
     414           0 :         maskedFlag->setInt32Specialization();
     415           0 :         current->add(maskedFlag);
     416             : 
     417           0 :         MDefinition* result = convertToBoolean(maskedFlag);
     418           0 :         current->push(result);
     419           0 :         return InliningStatus_Inlined;
     420             :     }
     421             : 
     422           0 :     return InliningStatus_NotInlined;
     423             : }
     424             : 
     425             : IonBuilder::InliningResult
     426           0 : IonBuilder::inlineNonFunctionCall(CallInfo& callInfo, JSObject* target)
     427             : {
     428             :     // Inline a call to a non-function object, invoking the object's call or
     429             :     // construct hook.
     430             : 
     431           0 :     if (callInfo.constructing() && target->constructHook() == TypedObject::construct)
     432           0 :         return inlineConstructTypedObject(callInfo, &target->as<TypeDescr>());
     433             : 
     434           0 :     if (!callInfo.constructing() && target->callHook() == SimdTypeDescr::call)
     435           0 :         return inlineConstructSimdObject(callInfo, &target->as<SimdTypeDescr>());
     436             : 
     437           0 :     return InliningStatus_NotInlined;
     438             : }
     439             : 
     440             : TemporaryTypeSet*
     441         117 : IonBuilder::getInlineReturnTypeSet()
     442             : {
     443         117 :     return bytecodeTypes(pc);
     444             : }
     445             : 
     446             : MIRType
     447          89 : IonBuilder::getInlineReturnType()
     448             : {
     449          89 :     TemporaryTypeSet* returnTypes = getInlineReturnTypeSet();
     450          89 :     return returnTypes->getKnownMIRType();
     451             : }
     452             : 
     453             : IonBuilder::InliningResult
     454           0 : IonBuilder::inlineMathFunction(CallInfo& callInfo, MMathFunction::Function function)
     455             : {
     456           0 :     if (callInfo.constructing())
     457           0 :         return InliningStatus_NotInlined;
     458             : 
     459           0 :     if (callInfo.argc() != 1)
     460           0 :         return InliningStatus_NotInlined;
     461             : 
     462           0 :     if (getInlineReturnType() != MIRType::Double)
     463           0 :         return InliningStatus_NotInlined;
     464           0 :     if (!IsNumberType(callInfo.getArg(0)->type()))
     465           0 :         return InliningStatus_NotInlined;
     466             : 
     467           0 :     const MathCache* cache = TlsContext.get()->caches().maybeGetMathCache();
     468             : 
     469           0 :     callInfo.fun()->setImplicitlyUsedUnchecked();
     470           0 :     callInfo.thisArg()->setImplicitlyUsedUnchecked();
     471             : 
     472           0 :     MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), function, cache);
     473           0 :     current->add(ins);
     474           0 :     current->push(ins);
     475           0 :     return InliningStatus_Inlined;
     476             : }
     477             : 
     478             : IonBuilder::InliningResult
     479           0 : IonBuilder::inlineArray(CallInfo& callInfo)
     480             : {
     481           0 :     uint32_t initLength = 0;
     482             : 
     483           0 :     JSObject* templateObject = inspector->getTemplateObjectForNative(pc, ArrayConstructor);
     484             :     // This is shared by ArrayConstructor and array_construct (std_Array).
     485           0 :     if (!templateObject)
     486           0 :         templateObject = inspector->getTemplateObjectForNative(pc, array_construct);
     487             : 
     488           0 :     if (!templateObject) {
     489           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
     490           0 :         return InliningStatus_NotInlined;
     491             :     }
     492             : 
     493           0 :     if (templateObject->is<UnboxedArrayObject>()) {
     494           0 :         if (templateObject->group()->unboxedLayout().nativeGroup())
     495           0 :             return InliningStatus_NotInlined;
     496             :     }
     497             : 
     498             :     // Multiple arguments imply array initialization, not just construction.
     499           0 :     if (callInfo.argc() >= 2) {
     500           0 :         initLength = callInfo.argc();
     501             : 
     502           0 :         TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(templateObject);
     503           0 :         if (!key->unknownProperties()) {
     504           0 :             HeapTypeSetKey elemTypes = key->property(JSID_VOID);
     505             : 
     506           0 :             for (uint32_t i = 0; i < initLength; i++) {
     507           0 :                 MDefinition* value = callInfo.getArg(i);
     508           0 :                 if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
     509           0 :                     elemTypes.freeze(constraints());
     510           0 :                     return InliningStatus_NotInlined;
     511             :                 }
     512             :             }
     513             :         }
     514             :     }
     515             : 
     516             :     // A single integer argument denotes initial length.
     517           0 :     if (callInfo.argc() == 1) {
     518           0 :         MDefinition* arg = callInfo.getArg(0);
     519           0 :         if (arg->type() != MIRType::Int32)
     520           0 :             return InliningStatus_NotInlined;
     521             : 
     522           0 :         if (!arg->isConstant()) {
     523           0 :             callInfo.setImplicitlyUsedUnchecked();
     524             :             MNewArrayDynamicLength* ins =
     525           0 :                 MNewArrayDynamicLength::New(alloc(), constraints(), templateObject,
     526           0 :                                             templateObject->group()->initialHeap(constraints()),
     527           0 :                                             arg);
     528           0 :             current->add(ins);
     529           0 :             current->push(ins);
     530             : 
     531             :             // This may throw, so we need a resume point.
     532           0 :             MOZ_TRY(resumeAfter(ins));
     533             : 
     534           0 :             return InliningStatus_Inlined;
     535             :         }
     536             : 
     537             :         // The next several checks all may fail due to range conditions.
     538           0 :         trackOptimizationOutcome(TrackedOutcome::ArrayRange);
     539             : 
     540             :         // Negative lengths generate a RangeError, unhandled by the inline path.
     541           0 :         initLength = arg->toConstant()->toInt32();
     542           0 :         if (initLength > NativeObject::MAX_DENSE_ELEMENTS_COUNT)
     543           0 :             return InliningStatus_NotInlined;
     544           0 :         MOZ_ASSERT(initLength <= INT32_MAX);
     545             : 
     546             :         // Make sure initLength matches the template object's length. This is
     547             :         // not guaranteed to be the case, for instance if we're inlining the
     548             :         // MConstant may come from an outer script.
     549           0 :         if (initLength != GetAnyBoxedOrUnboxedArrayLength(templateObject))
     550           0 :             return InliningStatus_NotInlined;
     551             : 
     552             :         // Don't inline large allocations.
     553           0 :         if (initLength > ArrayObject::EagerAllocationMaxLength)
     554           0 :             return InliningStatus_NotInlined;
     555             :     }
     556             : 
     557           0 :     callInfo.setImplicitlyUsedUnchecked();
     558             : 
     559           0 :     MOZ_TRY(jsop_newarray(templateObject, initLength));
     560             : 
     561           0 :     MDefinition* array = current->peek(-1);
     562           0 :     if (callInfo.argc() >= 2) {
     563           0 :         JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
     564           0 :         for (uint32_t i = 0; i < initLength; i++) {
     565           0 :             if (!alloc().ensureBallast())
     566           0 :                 return abort(AbortReason::Alloc);
     567           0 :             MDefinition* value = callInfo.getArg(i);
     568           0 :             MOZ_TRY(initializeArrayElement(array, i, value, unboxedType,
     569             :                                            /* addResumePoint = */ false));
     570             :         }
     571             : 
     572           0 :         MInstruction* setLength = setInitializedLength(array, unboxedType, initLength);
     573           0 :         MOZ_TRY(resumeAfter(setLength));
     574             :     }
     575             : 
     576           0 :     return InliningStatus_Inlined;
     577             : }
     578             : 
     579             : static bool
     580           0 : IsArrayClass(const Class* clasp)
     581             : {
     582           0 :     return clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_;
     583             : }
     584             : 
     585             : IonBuilder::InliningResult
     586           0 : IonBuilder::inlineArrayIsArray(CallInfo& callInfo)
     587             : {
     588           0 :     if (callInfo.constructing() || callInfo.argc() != 1) {
     589           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     590           0 :         return InliningStatus_NotInlined;
     591             :     }
     592             : 
     593           0 :     if (getInlineReturnType() != MIRType::Boolean)
     594           0 :         return InliningStatus_NotInlined;
     595             : 
     596           0 :     MDefinition* arg = callInfo.getArg(0);
     597             : 
     598           0 :     if (!arg->mightBeType(MIRType::Object)) {
     599           0 :         pushConstant(BooleanValue(false));
     600           0 :         callInfo.setImplicitlyUsedUnchecked();
     601           0 :         return InliningStatus_Inlined;
     602             :     }
     603             : 
     604             :     using ForAllResult = TemporaryTypeSet::ForAllResult;
     605             : 
     606           0 :     TemporaryTypeSet* types = arg->resultTypeSet();
     607             : 
     608             :     // Fast path for non-proxy objects.
     609           0 :     if (arg->type() == MIRType::Object &&
     610           0 :         types &&
     611           0 :         types->forAllClasses(constraints(), IsProxyClass) == ForAllResult::ALL_FALSE)
     612             :     {
     613             :         // Definitely not a proxy. Now check for the array classes.
     614           0 :         ForAllResult result = types->forAllClasses(constraints(), IsArrayClass);
     615             : 
     616           0 :         if (result == ForAllResult::ALL_FALSE || result == ForAllResult::ALL_TRUE) {
     617             :             // Definitely an array or definitely not an array, so we can
     618             :             // constant fold.
     619           0 :             pushConstant(BooleanValue(result == ForAllResult::ALL_TRUE));
     620           0 :             callInfo.setImplicitlyUsedUnchecked();
     621           0 :             return InliningStatus_Inlined;
     622             :         }
     623             : 
     624             :         // We have some array classes and some non-array classes, so we have to
     625             :         // check at runtime.
     626           0 :         MOZ_ASSERT(result == ForAllResult::MIXED);
     627             : 
     628           0 :         MHasClass* hasClass1 = MHasClass::New(alloc(), arg, &ArrayObject::class_);
     629           0 :         current->add(hasClass1);
     630             : 
     631           0 :         MHasClass* hasClass2 = MHasClass::New(alloc(), arg, &UnboxedArrayObject::class_);
     632           0 :         current->add(hasClass2);
     633             : 
     634           0 :         MBitOr* either = MBitOr::New(alloc(), hasClass1, hasClass2);
     635           0 :         either->infer(inspector, pc);
     636           0 :         current->add(either);
     637             : 
     638           0 :         MDefinition* def = convertToBoolean(either);
     639           0 :         current->push(def);
     640             : 
     641           0 :         callInfo.setImplicitlyUsedUnchecked();
     642           0 :         return InliningStatus_Inlined;
     643             :     }
     644             : 
     645             :     // The value might be a primitive or a proxy. MIsArray handles these cases.
     646           0 :     MIsArray* isArray = MIsArray::New(alloc(), arg);
     647           0 :     current->add(isArray);
     648           0 :     current->push(isArray);
     649             : 
     650           0 :     MOZ_TRY(resumeAfter(isArray));
     651             : 
     652           0 :     callInfo.setImplicitlyUsedUnchecked();
     653           0 :     return InliningStatus_Inlined;
     654             : }
     655             : 
     656             : IonBuilder::InliningResult
     657           0 : IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
     658             : {
     659           0 :     if (callInfo.constructing()) {
     660           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     661           0 :         return InliningStatus_NotInlined;
     662             :     }
     663             : 
     664           0 :     MIRType returnType = getInlineReturnType();
     665           0 :     if (returnType == MIRType::Undefined || returnType == MIRType::Null)
     666           0 :         return InliningStatus_NotInlined;
     667           0 :     if (callInfo.thisArg()->type() != MIRType::Object)
     668           0 :         return InliningStatus_NotInlined;
     669             : 
     670             :     // Pop and shift are only handled for dense arrays that have never been
     671             :     // used in an iterator: popping elements does not account for suppressing
     672             :     // deleted properties in active iterators.
     673             :     ObjectGroupFlags unhandledFlags =
     674             :         OBJECT_FLAG_SPARSE_INDEXES |
     675             :         OBJECT_FLAG_LENGTH_OVERFLOW |
     676           0 :         OBJECT_FLAG_ITERATED;
     677             : 
     678           0 :     MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
     679           0 :     TemporaryTypeSet* thisTypes = obj->resultTypeSet();
     680           0 :     if (!thisTypes)
     681           0 :         return InliningStatus_NotInlined;
     682           0 :     const Class* clasp = thisTypes->getKnownClass(constraints());
     683           0 :     if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
     684           0 :         return InliningStatus_NotInlined;
     685           0 :     if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) {
     686           0 :         trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
     687           0 :         return InliningStatus_NotInlined;
     688             :     }
     689             : 
     690             :     bool hasIndexedProperty;
     691           0 :     MOZ_TRY_VAR(hasIndexedProperty, ArrayPrototypeHasIndexedProperty(this, script()));
     692           0 :     if (hasIndexedProperty) {
     693           0 :         trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
     694           0 :         return InliningStatus_NotInlined;
     695             :     }
     696             : 
     697           0 :     JSValueType unboxedType = JSVAL_TYPE_MAGIC;
     698           0 :     if (clasp == &UnboxedArrayObject::class_) {
     699           0 :         unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
     700           0 :         if (unboxedType == JSVAL_TYPE_MAGIC)
     701           0 :             return InliningStatus_NotInlined;
     702             :     }
     703             : 
     704           0 :     callInfo.setImplicitlyUsedUnchecked();
     705             : 
     706           0 :     if (clasp == &ArrayObject::class_)
     707           0 :         obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false);
     708             : 
     709           0 :     TemporaryTypeSet* returnTypes = getInlineReturnTypeSet();
     710           0 :     bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED);
     711           0 :     bool maybeUndefined = returnTypes->hasType(TypeSet::UndefinedType());
     712             : 
     713           0 :     BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
     714           0 :                                                        obj, nullptr, returnTypes);
     715           0 :     if (barrier != BarrierKind::NoBarrier)
     716           0 :         returnType = MIRType::Value;
     717             : 
     718           0 :     MArrayPopShift* ins = MArrayPopShift::New(alloc(), obj, mode,
     719           0 :                                               unboxedType, needsHoleCheck, maybeUndefined);
     720           0 :     current->add(ins);
     721           0 :     current->push(ins);
     722           0 :     ins->setResultType(returnType);
     723             : 
     724           0 :     MOZ_TRY(resumeAfter(ins));
     725           0 :     MOZ_TRY(pushTypeBarrier(ins, returnTypes, barrier));
     726           0 :     return InliningStatus_Inlined;
     727             : }
     728             : 
     729             : IonBuilder::InliningResult
     730           1 : IonBuilder::inlineArrayJoin(CallInfo& callInfo)
     731             : {
     732           1 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
     733           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     734           0 :         return InliningStatus_NotInlined;
     735             :     }
     736             : 
     737           1 :     if (getInlineReturnType() != MIRType::String)
     738           0 :         return InliningStatus_NotInlined;
     739           1 :     if (callInfo.thisArg()->type() != MIRType::Object)
     740           0 :         return InliningStatus_NotInlined;
     741           1 :     if (callInfo.getArg(0)->type() != MIRType::String)
     742           0 :         return InliningStatus_NotInlined;
     743             : 
     744           1 :     callInfo.setImplicitlyUsedUnchecked();
     745             : 
     746           1 :     MArrayJoin* ins = MArrayJoin::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
     747             : 
     748           1 :     current->add(ins);
     749           1 :     current->push(ins);
     750             : 
     751           1 :     MOZ_TRY(resumeAfter(ins));
     752           1 :     return InliningStatus_Inlined;
     753             : }
     754             : 
     755             : IonBuilder::InliningResult
     756           4 : IonBuilder::inlineArrayPush(CallInfo& callInfo)
     757             : {
     758           4 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
     759           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     760           0 :         return InliningStatus_NotInlined;
     761             :     }
     762             : 
     763           4 :     MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
     764           4 :     MDefinition* value = callInfo.getArg(0);
     765           4 :     if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
     766             :                                       &obj, nullptr, &value, /* canModify = */ false))
     767             :     {
     768           2 :         trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
     769           2 :         return InliningStatus_NotInlined;
     770             :     }
     771             : 
     772           2 :     if (getInlineReturnType() != MIRType::Int32)
     773           0 :         return InliningStatus_NotInlined;
     774           2 :     if (obj->type() != MIRType::Object)
     775           0 :         return InliningStatus_NotInlined;
     776             : 
     777           2 :     TemporaryTypeSet* thisTypes = obj->resultTypeSet();
     778           2 :     if (!thisTypes)
     779           0 :         return InliningStatus_NotInlined;
     780           2 :     const Class* clasp = thisTypes->getKnownClass(constraints());
     781           2 :     if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
     782           0 :         return InliningStatus_NotInlined;
     783           2 :     if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
     784             :                                   OBJECT_FLAG_LENGTH_OVERFLOW))
     785             :     {
     786           0 :         trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
     787           0 :         return InliningStatus_NotInlined;
     788             :     }
     789             : 
     790             :     bool hasIndexedProperty;
     791           2 :     MOZ_TRY_VAR(hasIndexedProperty, ArrayPrototypeHasIndexedProperty(this, script()));
     792           2 :     if (hasIndexedProperty) {
     793           0 :         trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
     794           0 :         return InliningStatus_NotInlined;
     795             :     }
     796             : 
     797             :     TemporaryTypeSet::DoubleConversion conversion =
     798           2 :         thisTypes->convertDoubleElements(constraints());
     799           2 :     if (conversion == TemporaryTypeSet::AmbiguousDoubleConversion) {
     800           0 :         trackOptimizationOutcome(TrackedOutcome::ArrayDoubleConversion);
     801           0 :         return InliningStatus_NotInlined;
     802             :     }
     803             : 
     804           2 :     JSValueType unboxedType = JSVAL_TYPE_MAGIC;
     805           2 :     if (clasp == &UnboxedArrayObject::class_) {
     806           0 :         unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
     807           0 :         if (unboxedType == JSVAL_TYPE_MAGIC)
     808           0 :             return InliningStatus_NotInlined;
     809             :     }
     810             : 
     811           2 :     callInfo.setImplicitlyUsedUnchecked();
     812             : 
     813           2 :     if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles ||
     814             :         conversion == TemporaryTypeSet::MaybeConvertToDoubles)
     815             :     {
     816           0 :         MInstruction* valueDouble = MToDouble::New(alloc(), value);
     817           0 :         current->add(valueDouble);
     818           0 :         value = valueDouble;
     819             :     }
     820             : 
     821           2 :     if (unboxedType == JSVAL_TYPE_MAGIC)
     822           2 :         obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false);
     823             : 
     824           2 :     if (NeedsPostBarrier(value))
     825           0 :         current->add(MPostWriteBarrier::New(alloc(), obj, value));
     826             : 
     827           2 :     MArrayPush* ins = MArrayPush::New(alloc(), obj, value, unboxedType);
     828           2 :     current->add(ins);
     829           2 :     current->push(ins);
     830             : 
     831           2 :     MOZ_TRY(resumeAfter(ins));
     832           2 :     return InliningStatus_Inlined;
     833             : }
     834             : 
     835             : IonBuilder::InliningResult
     836           0 : IonBuilder::inlineArraySlice(CallInfo& callInfo)
     837             : {
     838           0 :     if (callInfo.constructing()) {
     839           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     840           0 :         return InliningStatus_NotInlined;
     841             :     }
     842             : 
     843           0 :     MDefinition* obj = convertUnboxedObjects(callInfo.thisArg());
     844             : 
     845             :     // Ensure |this| and result are objects.
     846           0 :     if (getInlineReturnType() != MIRType::Object)
     847           0 :         return InliningStatus_NotInlined;
     848           0 :     if (obj->type() != MIRType::Object)
     849           0 :         return InliningStatus_NotInlined;
     850             : 
     851             :     // Arguments for the sliced region must be integers.
     852           0 :     if (callInfo.argc() > 0) {
     853           0 :         if (callInfo.getArg(0)->type() != MIRType::Int32)
     854           0 :             return InliningStatus_NotInlined;
     855           0 :         if (callInfo.argc() > 1) {
     856           0 :             if (callInfo.getArg(1)->type() != MIRType::Int32)
     857           0 :                 return InliningStatus_NotInlined;
     858             :         }
     859             :     }
     860             : 
     861             :     // |this| must be a dense array.
     862           0 :     TemporaryTypeSet* thisTypes = obj->resultTypeSet();
     863           0 :     if (!thisTypes)
     864           0 :         return InliningStatus_NotInlined;
     865             : 
     866           0 :     const Class* clasp = thisTypes->getKnownClass(constraints());
     867           0 :     if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
     868           0 :         return InliningStatus_NotInlined;
     869           0 :     if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES |
     870             :                                   OBJECT_FLAG_LENGTH_OVERFLOW))
     871             :     {
     872           0 :         trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
     873           0 :         return InliningStatus_NotInlined;
     874             :     }
     875             : 
     876           0 :     JSValueType unboxedType = JSVAL_TYPE_MAGIC;
     877           0 :     if (clasp == &UnboxedArrayObject::class_) {
     878           0 :         unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
     879           0 :         if (unboxedType == JSVAL_TYPE_MAGIC)
     880           0 :             return InliningStatus_NotInlined;
     881             :     }
     882             : 
     883             :     // Watch out for indexed properties on the prototype.
     884             :     bool hasIndexedProperty;
     885           0 :     MOZ_TRY_VAR(hasIndexedProperty, ArrayPrototypeHasIndexedProperty(this, script()));
     886           0 :     if (hasIndexedProperty) {
     887           0 :         trackOptimizationOutcome(TrackedOutcome::ProtoIndexedProps);
     888           0 :         return InliningStatus_NotInlined;
     889             :     }
     890             : 
     891             :     // The group of the result will be dynamically fixed up to match the input
     892             :     // object, allowing us to handle 'this' objects that might have more than
     893             :     // one group. Make sure that no singletons can be sliced here.
     894           0 :     for (unsigned i = 0; i < thisTypes->getObjectCount(); i++) {
     895           0 :         TypeSet::ObjectKey* key = thisTypes->getObject(i);
     896           0 :         if (key && key->isSingleton())
     897           0 :             return InliningStatus_NotInlined;
     898             :     }
     899             : 
     900             :     // Inline the call.
     901           0 :     JSObject* templateObj = inspector->getTemplateObjectForNative(pc, js::array_slice);
     902           0 :     if (!templateObj)
     903           0 :         return InliningStatus_NotInlined;
     904             : 
     905           0 :     if (unboxedType == JSVAL_TYPE_MAGIC) {
     906           0 :         if (!templateObj->is<ArrayObject>())
     907           0 :             return InliningStatus_NotInlined;
     908             :     } else {
     909           0 :         if (!templateObj->is<UnboxedArrayObject>())
     910           0 :             return InliningStatus_NotInlined;
     911           0 :         if (templateObj->as<UnboxedArrayObject>().elementType() != unboxedType)
     912           0 :             return InliningStatus_NotInlined;
     913             :     }
     914             : 
     915           0 :     callInfo.setImplicitlyUsedUnchecked();
     916             : 
     917             :     MDefinition* begin;
     918           0 :     if (callInfo.argc() > 0)
     919           0 :         begin = callInfo.getArg(0);
     920             :     else
     921           0 :         begin = constant(Int32Value(0));
     922             : 
     923             :     MDefinition* end;
     924           0 :     if (callInfo.argc() > 1) {
     925           0 :         end = callInfo.getArg(1);
     926           0 :     } else if (clasp == &ArrayObject::class_) {
     927           0 :         MElements* elements = MElements::New(alloc(), obj);
     928           0 :         current->add(elements);
     929             : 
     930           0 :         end = MArrayLength::New(alloc(), elements);
     931           0 :         current->add(end->toInstruction());
     932             :     } else {
     933           0 :         end = MUnboxedArrayLength::New(alloc(), obj);
     934           0 :         current->add(end->toInstruction());
     935             :     }
     936             : 
     937           0 :     MArraySlice* ins = MArraySlice::New(alloc(), constraints(),
     938             :                                         obj, begin, end,
     939             :                                         templateObj,
     940           0 :                                         templateObj->group()->initialHeap(constraints()),
     941           0 :                                         unboxedType);
     942           0 :     current->add(ins);
     943           0 :     current->push(ins);
     944             : 
     945           0 :     MOZ_TRY(resumeAfter(ins));
     946           0 :     MOZ_TRY(pushTypeBarrier(ins, getInlineReturnTypeSet(), BarrierKind::TypeSet));
     947           0 :     return InliningStatus_Inlined;
     948             : }
     949             : 
     950             : IonBuilder::InliningResult
     951           0 : IonBuilder::inlineBoolean(CallInfo& callInfo)
     952             : {
     953           0 :     if (callInfo.constructing()) {
     954           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     955           0 :         return InliningStatus_NotInlined;
     956             :     }
     957             : 
     958           0 :     if (getInlineReturnType() != MIRType::Boolean)
     959           0 :         return InliningStatus_NotInlined;
     960             : 
     961           0 :     callInfo.setImplicitlyUsedUnchecked();
     962             : 
     963           0 :     if (callInfo.argc() > 0) {
     964           0 :         MDefinition* result = convertToBoolean(callInfo.getArg(0));
     965           0 :         current->push(result);
     966             :     } else {
     967           0 :         pushConstant(BooleanValue(false));
     968             :     }
     969           0 :     return InliningStatus_Inlined;
     970             : }
     971             : 
     972             : IonBuilder::InliningResult
     973           4 : IonBuilder::inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type)
     974             : {
     975           4 :     if (callInfo.argc() != 0 || callInfo.constructing()) {
     976           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
     977           0 :         return InliningStatus_NotInlined;
     978             :     }
     979             : 
     980           4 :     JSObject* templateObject = nullptr;
     981           4 :     switch (type) {
     982             :       case MNewIterator::ArrayIterator:
     983           4 :         templateObject = inspector->getTemplateObjectForNative(pc, js::intrinsic_NewArrayIterator);
     984           4 :         MOZ_ASSERT_IF(templateObject, templateObject->is<ArrayIteratorObject>());
     985           4 :         break;
     986             :       case MNewIterator::StringIterator:
     987           0 :         templateObject = inspector->getTemplateObjectForNative(pc, js::intrinsic_NewStringIterator);
     988           0 :         MOZ_ASSERT_IF(templateObject, templateObject->is<StringIteratorObject>());
     989           0 :         break;
     990             :     }
     991             : 
     992           4 :     if (!templateObject)
     993           0 :         return InliningStatus_NotInlined;
     994             : 
     995           4 :     callInfo.setImplicitlyUsedUnchecked();
     996             : 
     997           4 :     MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     998           4 :     current->add(templateConst);
     999             : 
    1000           4 :     MNewIterator* ins = MNewIterator::New(alloc(), constraints(), templateConst, type);
    1001           4 :     current->add(ins);
    1002           4 :     current->push(ins);
    1003             : 
    1004           4 :     MOZ_TRY(resumeAfter(ins));
    1005           4 :     return InliningStatus_Inlined;
    1006             : }
    1007             : 
    1008             : IonBuilder::InliningResult
    1009           0 : IonBuilder::inlineMathAbs(CallInfo& callInfo)
    1010             : {
    1011           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1012           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1013           0 :         return InliningStatus_NotInlined;
    1014             :     }
    1015             : 
    1016           0 :     MIRType returnType = getInlineReturnType();
    1017           0 :     MIRType argType = callInfo.getArg(0)->type();
    1018           0 :     if (!IsNumberType(argType))
    1019           0 :         return InliningStatus_NotInlined;
    1020             : 
    1021             :     // Either argType == returnType, or
    1022             :     //        argType == Double or Float32, returnType == Int, or
    1023             :     //        argType == Float32, returnType == Double
    1024           0 :     if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType::Int32)
    1025           0 :         && !(argType == MIRType::Float32 && returnType == MIRType::Double))
    1026             :     {
    1027           0 :         return InliningStatus_NotInlined;
    1028             :     }
    1029             : 
    1030           0 :     callInfo.setImplicitlyUsedUnchecked();
    1031             : 
    1032             :     // If the arg is a Float32, we specialize the op as double, it will be specialized
    1033             :     // as float32 if necessary later.
    1034           0 :     MIRType absType = (argType == MIRType::Float32) ? MIRType::Double : argType;
    1035           0 :     MInstruction* ins = MAbs::New(alloc(), callInfo.getArg(0), absType);
    1036           0 :     current->add(ins);
    1037             : 
    1038           0 :     current->push(ins);
    1039           0 :     return InliningStatus_Inlined;
    1040             : }
    1041             : 
    1042             : IonBuilder::InliningResult
    1043           0 : IonBuilder::inlineMathFloor(CallInfo& callInfo)
    1044             : {
    1045           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1046           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1047           0 :         return InliningStatus_NotInlined;
    1048             :     }
    1049             : 
    1050           0 :     MIRType argType = callInfo.getArg(0)->type();
    1051           0 :     MIRType returnType = getInlineReturnType();
    1052             : 
    1053             :     // Math.floor(int(x)) == int(x)
    1054           0 :     if (argType == MIRType::Int32 && returnType == MIRType::Int32) {
    1055           0 :         callInfo.setImplicitlyUsedUnchecked();
    1056             :         // The int operand may be something which bails out if the actual value
    1057             :         // is not in the range of the result type of the MIR. We need to tell
    1058             :         // the optimizer to preserve this bailout even if the final result is
    1059             :         // fully truncated.
    1060           0 :         MLimitedTruncate* ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
    1061           0 :                                                       MDefinition::IndirectTruncate);
    1062           0 :         current->add(ins);
    1063           0 :         current->push(ins);
    1064           0 :         return InliningStatus_Inlined;
    1065             :     }
    1066             : 
    1067           0 :     if (IsFloatingPointType(argType)) {
    1068           0 :         if (returnType == MIRType::Int32) {
    1069           0 :             callInfo.setImplicitlyUsedUnchecked();
    1070           0 :             MFloor* ins = MFloor::New(alloc(), callInfo.getArg(0));
    1071           0 :             current->add(ins);
    1072           0 :             current->push(ins);
    1073           0 :             return InliningStatus_Inlined;
    1074             :         }
    1075             : 
    1076           0 :         if (returnType == MIRType::Double) {
    1077           0 :             callInfo.setImplicitlyUsedUnchecked();
    1078             : 
    1079           0 :             MInstruction* ins = nullptr;
    1080           0 :             if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down)) {
    1081           0 :                 ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, RoundingMode::Down);
    1082             :             } else {
    1083           0 :                 ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor,
    1084           0 :                                          /* cache */ nullptr);
    1085             :             }
    1086             : 
    1087           0 :             current->add(ins);
    1088           0 :             current->push(ins);
    1089           0 :             return InliningStatus_Inlined;
    1090             :         }
    1091             :     }
    1092             : 
    1093           0 :     return InliningStatus_NotInlined;
    1094             : }
    1095             : 
    1096             : IonBuilder::InliningResult
    1097           0 : IonBuilder::inlineMathCeil(CallInfo& callInfo)
    1098             : {
    1099           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1100           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1101           0 :         return InliningStatus_NotInlined;
    1102             :     }
    1103             : 
    1104           0 :     MIRType argType = callInfo.getArg(0)->type();
    1105           0 :     MIRType returnType = getInlineReturnType();
    1106             : 
    1107             :     // Math.ceil(int(x)) == int(x)
    1108           0 :     if (argType == MIRType::Int32 && returnType == MIRType::Int32) {
    1109           0 :         callInfo.setImplicitlyUsedUnchecked();
    1110             :         // The int operand may be something which bails out if the actual value
    1111             :         // is not in the range of the result type of the MIR. We need to tell
    1112             :         // the optimizer to preserve this bailout even if the final result is
    1113             :         // fully truncated.
    1114           0 :         MLimitedTruncate* ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
    1115           0 :                                                       MDefinition::IndirectTruncate);
    1116           0 :         current->add(ins);
    1117           0 :         current->push(ins);
    1118           0 :         return InliningStatus_Inlined;
    1119             :     }
    1120             : 
    1121           0 :     if (IsFloatingPointType(argType)) {
    1122           0 :         if (returnType == MIRType::Int32) {
    1123           0 :             callInfo.setImplicitlyUsedUnchecked();
    1124           0 :             MCeil* ins = MCeil::New(alloc(), callInfo.getArg(0));
    1125           0 :             current->add(ins);
    1126           0 :             current->push(ins);
    1127           0 :             return InliningStatus_Inlined;
    1128             :         }
    1129             : 
    1130           0 :         if (returnType == MIRType::Double) {
    1131           0 :             callInfo.setImplicitlyUsedUnchecked();
    1132             : 
    1133           0 :             MInstruction* ins = nullptr;
    1134           0 :             if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up)) {
    1135           0 :                 ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, RoundingMode::Up);
    1136             :             } else {
    1137           0 :                 ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil,
    1138           0 :                                          /* cache */ nullptr);
    1139             :             }
    1140             : 
    1141           0 :             current->add(ins);
    1142           0 :             current->push(ins);
    1143           0 :             return InliningStatus_Inlined;
    1144             :         }
    1145             :     }
    1146             : 
    1147           0 :     return InliningStatus_NotInlined;
    1148             : }
    1149             : 
    1150             : IonBuilder::InliningResult
    1151           0 : IonBuilder::inlineMathClz32(CallInfo& callInfo)
    1152             : {
    1153           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1154           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1155           0 :         return InliningStatus_NotInlined;
    1156             :     }
    1157             : 
    1158           0 :     MIRType returnType = getInlineReturnType();
    1159           0 :     if (returnType != MIRType::Int32)
    1160           0 :         return InliningStatus_NotInlined;
    1161             : 
    1162           0 :     if (!IsNumberType(callInfo.getArg(0)->type()))
    1163           0 :         return InliningStatus_NotInlined;
    1164             : 
    1165           0 :     callInfo.setImplicitlyUsedUnchecked();
    1166             : 
    1167           0 :     MClz* ins = MClz::New(alloc(), callInfo.getArg(0), MIRType::Int32);
    1168           0 :     current->add(ins);
    1169           0 :     current->push(ins);
    1170           0 :     return InliningStatus_Inlined;
    1171             : 
    1172             : }
    1173             : 
    1174             : IonBuilder::InliningResult
    1175           0 : IonBuilder::inlineMathRound(CallInfo& callInfo)
    1176             : {
    1177           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1178           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1179           0 :         return InliningStatus_NotInlined;
    1180             :     }
    1181             : 
    1182           0 :     MIRType returnType = getInlineReturnType();
    1183           0 :     MIRType argType = callInfo.getArg(0)->type();
    1184             : 
    1185             :     // Math.round(int(x)) == int(x)
    1186           0 :     if (argType == MIRType::Int32 && returnType == MIRType::Int32) {
    1187           0 :         callInfo.setImplicitlyUsedUnchecked();
    1188             :         // The int operand may be something which bails out if the actual value
    1189             :         // is not in the range of the result type of the MIR. We need to tell
    1190             :         // the optimizer to preserve this bailout even if the final result is
    1191             :         // fully truncated.
    1192           0 :         MLimitedTruncate* ins = MLimitedTruncate::New(alloc(), callInfo.getArg(0),
    1193           0 :                                                       MDefinition::IndirectTruncate);
    1194           0 :         current->add(ins);
    1195           0 :         current->push(ins);
    1196           0 :         return InliningStatus_Inlined;
    1197             :     }
    1198             : 
    1199           0 :     if (IsFloatingPointType(argType) && returnType == MIRType::Int32) {
    1200           0 :         callInfo.setImplicitlyUsedUnchecked();
    1201           0 :         MRound* ins = MRound::New(alloc(), callInfo.getArg(0));
    1202           0 :         current->add(ins);
    1203           0 :         current->push(ins);
    1204           0 :         return InliningStatus_Inlined;
    1205             :     }
    1206             : 
    1207           0 :     if (IsFloatingPointType(argType) && returnType == MIRType::Double) {
    1208           0 :         callInfo.setImplicitlyUsedUnchecked();
    1209           0 :         MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round,
    1210           0 :                                                 /* cache */ nullptr);
    1211           0 :         current->add(ins);
    1212           0 :         current->push(ins);
    1213           0 :         return InliningStatus_Inlined;
    1214             :     }
    1215             : 
    1216           0 :     return InliningStatus_NotInlined;
    1217             : }
    1218             : 
    1219             : IonBuilder::InliningResult
    1220           0 : IonBuilder::inlineMathSqrt(CallInfo& callInfo)
    1221             : {
    1222           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1223           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1224           0 :         return InliningStatus_NotInlined;
    1225             :     }
    1226             : 
    1227           0 :     MIRType argType = callInfo.getArg(0)->type();
    1228           0 :     if (getInlineReturnType() != MIRType::Double)
    1229           0 :         return InliningStatus_NotInlined;
    1230           0 :     if (!IsNumberType(argType))
    1231           0 :         return InliningStatus_NotInlined;
    1232             : 
    1233           0 :     callInfo.setImplicitlyUsedUnchecked();
    1234             : 
    1235           0 :     MSqrt* sqrt = MSqrt::New(alloc(), callInfo.getArg(0), MIRType::Double);
    1236           0 :     current->add(sqrt);
    1237           0 :     current->push(sqrt);
    1238           0 :     return InliningStatus_Inlined;
    1239             : }
    1240             : 
    1241             : IonBuilder::InliningResult
    1242           0 : IonBuilder::inlineMathAtan2(CallInfo& callInfo)
    1243             : {
    1244           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    1245           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1246           0 :         return InliningStatus_NotInlined;
    1247             :     }
    1248             : 
    1249           0 :     if (getInlineReturnType() != MIRType::Double)
    1250           0 :         return InliningStatus_NotInlined;
    1251             : 
    1252           0 :     MIRType argType0 = callInfo.getArg(0)->type();
    1253           0 :     MIRType argType1 = callInfo.getArg(1)->type();
    1254             : 
    1255           0 :     if (!IsNumberType(argType0) || !IsNumberType(argType1))
    1256           0 :         return InliningStatus_NotInlined;
    1257             : 
    1258           0 :     callInfo.setImplicitlyUsedUnchecked();
    1259             : 
    1260           0 :     MAtan2* atan2 = MAtan2::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
    1261           0 :     current->add(atan2);
    1262           0 :     current->push(atan2);
    1263           0 :     return InliningStatus_Inlined;
    1264             : }
    1265             : 
    1266             : IonBuilder::InliningResult
    1267           0 : IonBuilder::inlineMathHypot(CallInfo& callInfo)
    1268             : {
    1269           0 :     if (callInfo.constructing()) {
    1270           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1271           0 :         return InliningStatus_NotInlined;
    1272             :     }
    1273             : 
    1274           0 :     uint32_t argc = callInfo.argc();
    1275           0 :     if (argc < 2 || argc > 4) {
    1276           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1277           0 :         return InliningStatus_NotInlined;
    1278             :     }
    1279             : 
    1280           0 :     if (getInlineReturnType() != MIRType::Double)
    1281           0 :         return InliningStatus_NotInlined;
    1282             : 
    1283           0 :     MDefinitionVector vector(alloc());
    1284           0 :     if (!vector.reserve(argc))
    1285           0 :         return InliningStatus_NotInlined;
    1286             : 
    1287           0 :     for (uint32_t i = 0; i < argc; ++i) {
    1288           0 :         MDefinition * arg = callInfo.getArg(i);
    1289           0 :         if (!IsNumberType(arg->type()))
    1290           0 :             return InliningStatus_NotInlined;
    1291           0 :         vector.infallibleAppend(arg);
    1292             :     }
    1293             : 
    1294           0 :     callInfo.setImplicitlyUsedUnchecked();
    1295           0 :     MHypot* hypot = MHypot::New(alloc(), vector);
    1296             : 
    1297           0 :     if (!hypot)
    1298           0 :         return InliningStatus_NotInlined;
    1299             : 
    1300           0 :     current->add(hypot);
    1301           0 :     current->push(hypot);
    1302           0 :     return InliningStatus_Inlined;
    1303             : }
    1304             : 
    1305             : IonBuilder::InliningResult
    1306           0 : IonBuilder::inlineMathPow(CallInfo& callInfo)
    1307             : {
    1308           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    1309           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1310           0 :         return InliningStatus_NotInlined;
    1311             :     }
    1312             : 
    1313           0 :     bool emitted = false;
    1314           0 :     MOZ_TRY(powTrySpecialized(&emitted, callInfo.getArg(0), callInfo.getArg(1),
    1315             :                               getInlineReturnType()));
    1316             : 
    1317           0 :     if (!emitted)
    1318           0 :         return InliningStatus_NotInlined;
    1319             : 
    1320           0 :     callInfo.setImplicitlyUsedUnchecked();
    1321           0 :     return InliningStatus_Inlined;
    1322             : }
    1323             : 
    1324             : IonBuilder::InliningResult
    1325           0 : IonBuilder::inlineMathRandom(CallInfo& callInfo)
    1326             : {
    1327           0 :     if (callInfo.constructing()) {
    1328           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1329           0 :         return InliningStatus_NotInlined;
    1330             :     }
    1331             : 
    1332           0 :     if (getInlineReturnType() != MIRType::Double)
    1333           0 :         return InliningStatus_NotInlined;
    1334             : 
    1335             :     // MRandom JIT code directly accesses the RNG. It's (barely) possible to
    1336             :     // inline Math.random without it having been called yet, so ensure RNG
    1337             :     // state that isn't guaranteed to be initialized already.
    1338           0 :     script()->compartment()->ensureRandomNumberGenerator();
    1339             : 
    1340           0 :     callInfo.setImplicitlyUsedUnchecked();
    1341             : 
    1342           0 :     MRandom* rand = MRandom::New(alloc());
    1343           0 :     current->add(rand);
    1344           0 :     current->push(rand);
    1345           0 :     return InliningStatus_Inlined;
    1346             : }
    1347             : 
    1348             : IonBuilder::InliningResult
    1349           0 : IonBuilder::inlineMathImul(CallInfo& callInfo)
    1350             : {
    1351           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    1352           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1353           0 :         return InliningStatus_NotInlined;
    1354             :     }
    1355             : 
    1356           0 :     MIRType returnType = getInlineReturnType();
    1357           0 :     if (returnType != MIRType::Int32)
    1358           0 :         return InliningStatus_NotInlined;
    1359             : 
    1360           0 :     if (!IsNumberType(callInfo.getArg(0)->type()))
    1361           0 :         return InliningStatus_NotInlined;
    1362           0 :     if (!IsNumberType(callInfo.getArg(1)->type()))
    1363           0 :         return InliningStatus_NotInlined;
    1364             : 
    1365           0 :     callInfo.setImplicitlyUsedUnchecked();
    1366             : 
    1367           0 :     MInstruction* first = MTruncateToInt32::New(alloc(), callInfo.getArg(0));
    1368           0 :     current->add(first);
    1369             : 
    1370           0 :     MInstruction* second = MTruncateToInt32::New(alloc(), callInfo.getArg(1));
    1371           0 :     current->add(second);
    1372             : 
    1373           0 :     MMul* ins = MMul::New(alloc(), first, second, MIRType::Int32, MMul::Integer);
    1374           0 :     current->add(ins);
    1375           0 :     current->push(ins);
    1376           0 :     return InliningStatus_Inlined;
    1377             : }
    1378             : 
    1379             : IonBuilder::InliningResult
    1380           0 : IonBuilder::inlineMathFRound(CallInfo& callInfo)
    1381             : {
    1382           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1383           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1384           0 :         return InliningStatus_NotInlined;
    1385             :     }
    1386             : 
    1387             :     // MIRType can't be Float32, as this point, as getInlineReturnType uses JSVal types
    1388             :     // to infer the returned MIR type.
    1389           0 :     TemporaryTypeSet* returned = getInlineReturnTypeSet();
    1390           0 :     if (returned->empty()) {
    1391             :         // As there's only one possible returned type, just add it to the observed
    1392             :         // returned typeset
    1393           0 :         returned->addType(TypeSet::DoubleType(), alloc_->lifoAlloc());
    1394             :     } else {
    1395           0 :         MIRType returnType = getInlineReturnType();
    1396           0 :         if (!IsNumberType(returnType))
    1397           0 :             return InliningStatus_NotInlined;
    1398             :     }
    1399             : 
    1400           0 :     MIRType arg = callInfo.getArg(0)->type();
    1401           0 :     if (!IsNumberType(arg))
    1402           0 :         return InliningStatus_NotInlined;
    1403             : 
    1404           0 :     callInfo.setImplicitlyUsedUnchecked();
    1405             : 
    1406           0 :     MToFloat32* ins = MToFloat32::New(alloc(), callInfo.getArg(0));
    1407           0 :     current->add(ins);
    1408           0 :     current->push(ins);
    1409           0 :     return InliningStatus_Inlined;
    1410             : }
    1411             : 
    1412             : IonBuilder::InliningResult
    1413          16 : IonBuilder::inlineMathMinMax(CallInfo& callInfo, bool max)
    1414             : {
    1415          16 :     if (callInfo.argc() < 1 || callInfo.constructing()) {
    1416           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1417           0 :         return InliningStatus_NotInlined;
    1418             :     }
    1419             : 
    1420          16 :     MIRType returnType = getInlineReturnType();
    1421          16 :     if (!IsNumberType(returnType))
    1422           0 :         return InliningStatus_NotInlined;
    1423             : 
    1424          32 :     MDefinitionVector int32_cases(alloc());
    1425          48 :     for (unsigned i = 0; i < callInfo.argc(); i++) {
    1426          32 :         MDefinition* arg = callInfo.getArg(i);
    1427             : 
    1428          32 :         switch (arg->type()) {
    1429             :           case MIRType::Int32:
    1430          24 :             if (!int32_cases.append(arg))
    1431           0 :                 return abort(AbortReason::Alloc);
    1432          24 :             break;
    1433             :           case MIRType::Double:
    1434             :           case MIRType::Float32:
    1435             :             // Don't force a double MMinMax for arguments that would be a NOP
    1436             :             // when doing an integer MMinMax.
    1437           8 :             if (arg->isConstant()) {
    1438           8 :                 double cte = arg->toConstant()->numberToDouble();
    1439             :                 // min(int32, cte >= INT32_MAX) = int32
    1440           8 :                 if (cte >= INT32_MAX && !max)
    1441           8 :                     break;
    1442             :                 // max(int32, cte <= INT32_MIN) = int32
    1443           0 :                 if (cte <= INT32_MIN && max)
    1444           0 :                     break;
    1445             :             }
    1446             : 
    1447             :             // Force double MMinMax if argument is a "effectfull" double.
    1448           0 :             returnType = MIRType::Double;
    1449           0 :             break;
    1450             :           default:
    1451           0 :             return InliningStatus_NotInlined;
    1452             :         }
    1453             :     }
    1454             : 
    1455          16 :     if (int32_cases.length() == 0)
    1456           0 :         returnType = MIRType::Double;
    1457             : 
    1458          16 :     callInfo.setImplicitlyUsedUnchecked();
    1459             : 
    1460          16 :     MDefinitionVector& cases = (returnType == MIRType::Int32) ? int32_cases : callInfo.argv();
    1461             : 
    1462          16 :     if (cases.length() == 1) {
    1463           8 :         MLimitedTruncate* limit = MLimitedTruncate::New(alloc(), cases[0], MDefinition::NoTruncate);
    1464           8 :         current->add(limit);
    1465           8 :         current->push(limit);
    1466           8 :         return InliningStatus_Inlined;
    1467             :     }
    1468             : 
    1469             :     // Chain N-1 MMinMax instructions to compute the MinMax.
    1470           8 :     MMinMax* last = MMinMax::New(alloc(), cases[0], cases[1], returnType, max);
    1471           8 :     current->add(last);
    1472             : 
    1473           8 :     for (unsigned i = 2; i < cases.length(); i++) {
    1474           0 :         MMinMax* ins = MMinMax::New(alloc().fallible(), last, cases[i], returnType, max);
    1475           0 :         if (!ins)
    1476           0 :             return abort(AbortReason::Alloc);
    1477           0 :         current->add(ins);
    1478           0 :         last = ins;
    1479             :     }
    1480             : 
    1481           8 :     current->push(last);
    1482           8 :     return InliningStatus_Inlined;
    1483             : }
    1484             : 
    1485             : IonBuilder::InliningResult
    1486           0 : IonBuilder::inlineStringObject(CallInfo& callInfo)
    1487             : {
    1488           0 :     if (callInfo.argc() != 1 || !callInfo.constructing()) {
    1489           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1490           0 :         return InliningStatus_NotInlined;
    1491             :     }
    1492             : 
    1493             :     // ConvertToString doesn't support objects.
    1494           0 :     if (callInfo.getArg(0)->mightBeType(MIRType::Object))
    1495           0 :         return InliningStatus_NotInlined;
    1496             : 
    1497           0 :     JSObject* templateObj = inspector->getTemplateObjectForNative(pc, StringConstructor);
    1498           0 :     if (!templateObj)
    1499           0 :         return InliningStatus_NotInlined;
    1500           0 :     MOZ_ASSERT(templateObj->is<StringObject>());
    1501             : 
    1502           0 :     callInfo.setImplicitlyUsedUnchecked();
    1503             : 
    1504           0 :     MNewStringObject* ins = MNewStringObject::New(alloc(), callInfo.getArg(0), templateObj);
    1505           0 :     current->add(ins);
    1506           0 :     current->push(ins);
    1507             : 
    1508           0 :     MOZ_TRY(resumeAfter(ins));
    1509           0 :     return InliningStatus_Inlined;
    1510             : }
    1511             : 
    1512             : IonBuilder::InliningResult
    1513           0 : IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
    1514             : {
    1515           0 :     if (!callInfo.getArg(0)->isConstant())
    1516           0 :         return InliningStatus_NotInlined;
    1517             : 
    1518           0 :     if (!callInfo.getArg(1)->isConstant())
    1519           0 :         return InliningStatus_NotInlined;
    1520             : 
    1521           0 :     MConstant* strval = callInfo.getArg(0)->toConstant();
    1522           0 :     if (strval->type() != MIRType::String)
    1523           0 :         return InliningStatus_NotInlined;
    1524             : 
    1525           0 :     MConstant* sepval = callInfo.getArg(1)->toConstant();
    1526           0 :     if (strval->type() != MIRType::String)
    1527           0 :         return InliningStatus_NotInlined;
    1528             : 
    1529             :     // Check if exist a template object in stub.
    1530           0 :     JSString* stringStr = nullptr;
    1531           0 :     JSString* stringSep = nullptr;
    1532           0 :     JSObject* templateObject = nullptr;
    1533           0 :     if (!inspector->isOptimizableConstStringSplit(pc, &stringStr, &stringSep, &templateObject))
    1534           0 :         return InliningStatus_NotInlined;
    1535             : 
    1536           0 :     MOZ_ASSERT(stringStr);
    1537           0 :     MOZ_ASSERT(stringSep);
    1538           0 :     MOZ_ASSERT(templateObject);
    1539             : 
    1540           0 :     if (strval->toString() != stringStr)
    1541           0 :         return InliningStatus_NotInlined;
    1542             : 
    1543           0 :     if (sepval->toString() != stringSep)
    1544           0 :         return InliningStatus_NotInlined;
    1545             : 
    1546             :     // Check if |templateObject| is valid.
    1547           0 :     TypeSet::ObjectKey* retType = TypeSet::ObjectKey::get(templateObject);
    1548           0 :     if (retType->unknownProperties())
    1549           0 :         return InliningStatus_NotInlined;
    1550             : 
    1551           0 :     HeapTypeSetKey key = retType->property(JSID_VOID);
    1552           0 :     if (!key.maybeTypes())
    1553           0 :         return InliningStatus_NotInlined;
    1554             : 
    1555           0 :     if (!key.maybeTypes()->hasType(TypeSet::StringType()))
    1556           0 :         return InliningStatus_NotInlined;
    1557             : 
    1558           0 :     uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(templateObject);
    1559           0 :     if (GetAnyBoxedOrUnboxedInitializedLength(templateObject) != initLength)
    1560           0 :         return InliningStatus_NotInlined;
    1561             : 
    1562           0 :     Vector<MConstant*, 0, SystemAllocPolicy> arrayValues;
    1563           0 :     for (uint32_t i = 0; i < initLength; i++) {
    1564           0 :         Value str = GetAnyBoxedOrUnboxedDenseElement(templateObject, i);
    1565           0 :         MOZ_ASSERT(str.toString()->isAtom());
    1566           0 :         MConstant* value = MConstant::New(alloc().fallible(), str, constraints());
    1567           0 :         if (!value)
    1568           0 :             return abort(AbortReason::Alloc);
    1569           0 :         if (!TypeSetIncludes(key.maybeTypes(), value->type(), value->resultTypeSet()))
    1570           0 :             return InliningStatus_NotInlined;
    1571             : 
    1572           0 :         if (!arrayValues.append(value))
    1573           0 :             return abort(AbortReason::Alloc);
    1574             :     }
    1575           0 :     callInfo.setImplicitlyUsedUnchecked();
    1576             : 
    1577             :     TemporaryTypeSet::DoubleConversion conversion =
    1578           0 :             getInlineReturnTypeSet()->convertDoubleElements(constraints());
    1579           0 :     if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles)
    1580           0 :         return InliningStatus_NotInlined;
    1581             : 
    1582           0 :     MOZ_TRY(jsop_newarray(templateObject, initLength));
    1583             : 
    1584           0 :     MDefinition* array = current->peek(-1);
    1585             : 
    1586           0 :     if (!initLength) {
    1587           0 :         if (!array->isResumePoint())
    1588           0 :             MOZ_TRY(resumeAfter(array->toNewArray()));
    1589           0 :         return InliningStatus_Inlined;
    1590             :     }
    1591             : 
    1592           0 :     JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
    1593             : 
    1594             :     // Store all values, no need to initialize the length after each as
    1595             :     // jsop_initelem_array is doing because we do not expect to bailout
    1596             :     // because the memory is supposed to be allocated by now.
    1597           0 :     for (uint32_t i = 0; i < initLength; i++) {
    1598           0 :         if (!alloc().ensureBallast())
    1599           0 :             return abort(AbortReason::Alloc);
    1600             : 
    1601           0 :         MConstant* value = arrayValues[i];
    1602           0 :         current->add(value);
    1603             : 
    1604           0 :         MOZ_TRY(initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false));
    1605             :     }
    1606             : 
    1607           0 :     MInstruction* setLength = setInitializedLength(array, unboxedType, initLength);
    1608           0 :     MOZ_TRY(resumeAfter(setLength));
    1609           0 :     return InliningStatus_Inlined;
    1610             : }
    1611             : 
    1612             : IonBuilder::InliningResult
    1613           0 : IonBuilder::inlineStringSplitString(CallInfo& callInfo)
    1614             : {
    1615           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    1616           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1617           0 :         return InliningStatus_NotInlined;
    1618             :     }
    1619             : 
    1620           0 :     MDefinition* strArg = callInfo.getArg(0);
    1621           0 :     MDefinition* sepArg = callInfo.getArg(1);
    1622             : 
    1623           0 :     if (strArg->type() != MIRType::String)
    1624           0 :         return InliningStatus_NotInlined;
    1625             : 
    1626           0 :     if (sepArg->type() != MIRType::String)
    1627           0 :         return InliningStatus_NotInlined;
    1628             : 
    1629             :     IonBuilder::InliningStatus resultConstStringSplit;
    1630           0 :     MOZ_TRY_VAR(resultConstStringSplit, inlineConstantStringSplitString(callInfo));
    1631           0 :     if (resultConstStringSplit != InliningStatus_NotInlined)
    1632           0 :         return resultConstStringSplit;
    1633             : 
    1634           0 :     JSContext* cx = GetJitContext()->cx;
    1635           0 :     ObjectGroup* group = ObjectGroupCompartment::getStringSplitStringGroup(cx);
    1636           0 :     if (!group)
    1637           0 :         return InliningStatus_NotInlined;
    1638           0 :     if (group->maybePreliminaryObjects())
    1639           0 :         return InliningStatus_NotInlined;
    1640             : 
    1641           0 :     TypeSet::ObjectKey* retKey = TypeSet::ObjectKey::get(group);
    1642           0 :     if (retKey->unknownProperties())
    1643           0 :         return InliningStatus_NotInlined;
    1644             : 
    1645           0 :     HeapTypeSetKey key = retKey->property(JSID_VOID);
    1646           0 :     if (!key.maybeTypes())
    1647           0 :         return InliningStatus_NotInlined;
    1648             : 
    1649           0 :     if (!key.maybeTypes()->hasType(TypeSet::StringType())) {
    1650           0 :         key.freeze(constraints());
    1651           0 :         return InliningStatus_NotInlined;
    1652             :     }
    1653             : 
    1654           0 :     callInfo.setImplicitlyUsedUnchecked();
    1655           0 :     MStringSplit* ins = MStringSplit::New(alloc(), constraints(), strArg, sepArg, group);
    1656           0 :     current->add(ins);
    1657           0 :     current->push(ins);
    1658             : 
    1659           0 :     return InliningStatus_Inlined;
    1660             : }
    1661             : 
    1662             : IonBuilder::InliningResult
    1663           0 : IonBuilder::inlineObjectHasPrototype(CallInfo& callInfo)
    1664             : {
    1665           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    1666           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1667           0 :         return InliningStatus_NotInlined;
    1668             :     }
    1669             : 
    1670           0 :     MDefinition* objArg = callInfo.getArg(0);
    1671           0 :     MDefinition* protoArg = callInfo.getArg(1);
    1672             : 
    1673           0 :     if (objArg->type() != MIRType::Object)
    1674           0 :         return InliningStatus_NotInlined;
    1675           0 :     if (protoArg->type() != MIRType::Object)
    1676           0 :         return InliningStatus_NotInlined;
    1677             : 
    1678             :     // Inline only when both obj and proto are singleton objects and
    1679             :     // obj does not have uncacheable proto and obj.__proto__ is proto.
    1680           0 :     TemporaryTypeSet* objTypes = objArg->resultTypeSet();
    1681           0 :     if (!objTypes || objTypes->unknownObject() || objTypes->getObjectCount() != 1)
    1682           0 :         return InliningStatus_NotInlined;
    1683             : 
    1684           0 :     TypeSet::ObjectKey* objKey = objTypes->getObject(0);
    1685           0 :     if (!objKey || !objKey->hasStableClassAndProto(constraints()))
    1686           0 :         return InliningStatus_NotInlined;
    1687           0 :     if (!objKey->isSingleton() || !objKey->singleton()->is<NativeObject>())
    1688           0 :         return InliningStatus_NotInlined;
    1689             : 
    1690           0 :     JSObject* obj = &objKey->singleton()->as<NativeObject>();
    1691           0 :     if (obj->hasUncacheableProto())
    1692           0 :         return InliningStatus_NotInlined;
    1693             : 
    1694           0 :     JSObject* actualProto = checkNurseryObject(objKey->proto().toObjectOrNull());
    1695           0 :     if (actualProto == nullptr)
    1696           0 :         return InliningStatus_NotInlined;
    1697             : 
    1698           0 :     TemporaryTypeSet* protoTypes = protoArg->resultTypeSet();
    1699           0 :     if (!protoTypes || protoTypes->unknownObject() || protoTypes->getObjectCount() != 1)
    1700           0 :         return InliningStatus_NotInlined;
    1701             : 
    1702           0 :     TypeSet::ObjectKey* protoKey = protoTypes->getObject(0);
    1703           0 :     if (!protoKey || !protoKey->hasStableClassAndProto(constraints()))
    1704           0 :         return InliningStatus_NotInlined;
    1705           0 :     if (!protoKey->isSingleton() || !protoKey->singleton()->is<NativeObject>())
    1706           0 :         return InliningStatus_NotInlined;
    1707             : 
    1708           0 :     JSObject* proto = &protoKey->singleton()->as<NativeObject>();
    1709           0 :     pushConstant(BooleanValue(proto == actualProto));
    1710           0 :     callInfo.setImplicitlyUsedUnchecked();
    1711           0 :     return InliningStatus_Inlined;
    1712             : }
    1713             : 
    1714             : IonBuilder::InliningResult
    1715           0 : IonBuilder::inlineFinishBoundFunctionInit(CallInfo& callInfo)
    1716             : {
    1717           0 :     MOZ_ASSERT(!callInfo.constructing());
    1718           0 :     MOZ_ASSERT(callInfo.argc() == 3);
    1719           0 :     MOZ_ASSERT(BytecodeIsPopped(pc));
    1720             : 
    1721           0 :     MDefinition* boundFunction = callInfo.getArg(0);
    1722           0 :     MDefinition* targetFunction = callInfo.getArg(1);
    1723           0 :     MDefinition* argCount = callInfo.getArg(2);
    1724             : 
    1725           0 :     if (boundFunction->type() != MIRType::Object)
    1726           0 :         return InliningStatus_NotInlined;
    1727           0 :     if (targetFunction->type() != MIRType::Object)
    1728           0 :         return InliningStatus_NotInlined;
    1729           0 :     if (argCount->type() != MIRType::Int32)
    1730           0 :         return InliningStatus_NotInlined;
    1731             : 
    1732           0 :     callInfo.setImplicitlyUsedUnchecked();
    1733             : 
    1734           0 :     auto* ins = MFinishBoundFunctionInit::New(alloc(), boundFunction, targetFunction, argCount);
    1735           0 :     current->add(ins);
    1736             : 
    1737           0 :     pushConstant(UndefinedValue());
    1738             : 
    1739           0 :     MOZ_TRY(resumeAfter(ins));
    1740           0 :     return InliningStatus_Inlined;
    1741             : }
    1742             : 
    1743             : IonBuilder::InliningResult
    1744           3 : IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo)
    1745             : {
    1746           3 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1747           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1748           0 :         return InliningStatus_NotInlined;
    1749             :     }
    1750             : 
    1751           3 :     if (getInlineReturnType() != MIRType::Int32)
    1752           0 :         return InliningStatus_NotInlined;
    1753           3 :     if (callInfo.thisArg()->type() != MIRType::String && callInfo.thisArg()->type() != MIRType::Value)
    1754           0 :         return InliningStatus_NotInlined;
    1755           3 :     MIRType argType = callInfo.getArg(0)->type();
    1756           3 :     if (argType != MIRType::Int32 && argType != MIRType::Double)
    1757           0 :         return InliningStatus_NotInlined;
    1758             : 
    1759             :     // Check for STR.charCodeAt(IDX) where STR is a constant string and IDX is a
    1760             :     // constant integer.
    1761             :     InliningStatus constInlineStatus;
    1762           3 :     MOZ_TRY_VAR(constInlineStatus, inlineConstantCharCodeAt(callInfo));
    1763           3 :     if (constInlineStatus != InliningStatus_NotInlined)
    1764           0 :         return constInlineStatus;
    1765             : 
    1766           3 :     callInfo.setImplicitlyUsedUnchecked();
    1767             : 
    1768           3 :     MInstruction* index = MToInt32::New(alloc(), callInfo.getArg(0));
    1769           3 :     current->add(index);
    1770             : 
    1771           3 :     MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
    1772           3 :     current->add(length);
    1773             : 
    1774           3 :     index = addBoundsCheck(index, length);
    1775             : 
    1776           3 :     MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
    1777           3 :     current->add(charCode);
    1778           3 :     current->push(charCode);
    1779           3 :     return InliningStatus_Inlined;
    1780             : }
    1781             : 
    1782             : IonBuilder::InliningResult
    1783           3 : IonBuilder::inlineConstantCharCodeAt(CallInfo& callInfo)
    1784             : {
    1785           3 :     if (!callInfo.thisArg()->maybeConstantValue() || !callInfo.getArg(0)->maybeConstantValue()) {
    1786           3 :         trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
    1787           3 :         return InliningStatus_NotInlined;
    1788             :     }
    1789             : 
    1790           0 :     MConstant* strval = callInfo.thisArg()->maybeConstantValue();
    1791           0 :     MConstant* idxval = callInfo.getArg(0)->maybeConstantValue();
    1792             : 
    1793           0 :     if (strval->type() != MIRType::String || idxval->type() != MIRType::Int32)
    1794           0 :         return InliningStatus_NotInlined;
    1795             : 
    1796           0 :     JSString* str = strval->toString();
    1797           0 :     if (!str->isLinear()) {
    1798           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
    1799           0 :         return InliningStatus_NotInlined;
    1800             :     }
    1801             : 
    1802           0 :     int32_t idx = idxval->toInt32();
    1803           0 :     if (idx < 0 || (uint32_t(idx) >= str->length())) {
    1804           0 :         trackOptimizationOutcome(TrackedOutcome::OutOfBounds);
    1805           0 :         return InliningStatus_NotInlined;
    1806             :     }
    1807             : 
    1808           0 :     callInfo.setImplicitlyUsedUnchecked();
    1809             : 
    1810           0 :     JSLinearString& linstr = str->asLinear();
    1811           0 :     char16_t ch = linstr.latin1OrTwoByteChar(idx);
    1812           0 :     MConstant* result = MConstant::New(alloc(), Int32Value(ch));
    1813           0 :     current->add(result);
    1814           0 :     current->push(result);
    1815           0 :     return InliningStatus_Inlined;
    1816             : }
    1817             : 
    1818             : IonBuilder::InliningResult
    1819           0 : IonBuilder::inlineStrFromCharCode(CallInfo& callInfo)
    1820             : {
    1821           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1822           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1823           0 :         return InliningStatus_NotInlined;
    1824             :     }
    1825             : 
    1826           0 :     if (getInlineReturnType() != MIRType::String)
    1827           0 :         return InliningStatus_NotInlined;
    1828           0 :     if (callInfo.getArg(0)->type() != MIRType::Int32)
    1829           0 :         return InliningStatus_NotInlined;
    1830             : 
    1831           0 :     callInfo.setImplicitlyUsedUnchecked();
    1832             : 
    1833           0 :     MFromCharCode* string = MFromCharCode::New(alloc(), callInfo.getArg(0));
    1834           0 :     current->add(string);
    1835           0 :     current->push(string);
    1836           0 :     return InliningStatus_Inlined;
    1837             : }
    1838             : 
    1839             : IonBuilder::InliningResult
    1840           0 : IonBuilder::inlineStrFromCodePoint(CallInfo& callInfo)
    1841             : {
    1842           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1843           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1844           0 :         return InliningStatus_NotInlined;
    1845             :     }
    1846             : 
    1847           0 :     if (getInlineReturnType() != MIRType::String)
    1848           0 :         return InliningStatus_NotInlined;
    1849           0 :     if (callInfo.getArg(0)->type() != MIRType::Int32)
    1850           0 :         return InliningStatus_NotInlined;
    1851             : 
    1852           0 :     callInfo.setImplicitlyUsedUnchecked();
    1853             : 
    1854           0 :     MFromCodePoint* string = MFromCodePoint::New(alloc(), callInfo.getArg(0));
    1855           0 :     current->add(string);
    1856           0 :     current->push(string);
    1857           0 :     return InliningStatus_Inlined;
    1858             : }
    1859             : 
    1860             : IonBuilder::InliningResult
    1861           0 : IonBuilder::inlineStrCharAt(CallInfo& callInfo)
    1862             : {
    1863           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    1864           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1865           0 :         return InliningStatus_NotInlined;
    1866             :     }
    1867             : 
    1868           0 :     if (getInlineReturnType() != MIRType::String)
    1869           0 :         return InliningStatus_NotInlined;
    1870           0 :     if (callInfo.thisArg()->type() != MIRType::String)
    1871           0 :         return InliningStatus_NotInlined;
    1872           0 :     MIRType argType = callInfo.getArg(0)->type();
    1873           0 :     if (argType != MIRType::Int32 && argType != MIRType::Double)
    1874           0 :         return InliningStatus_NotInlined;
    1875             : 
    1876           0 :     callInfo.setImplicitlyUsedUnchecked();
    1877             : 
    1878           0 :     MInstruction* index = MToInt32::New(alloc(), callInfo.getArg(0));
    1879           0 :     current->add(index);
    1880             : 
    1881           0 :     MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
    1882           0 :     current->add(length);
    1883             : 
    1884           0 :     index = addBoundsCheck(index, length);
    1885             : 
    1886             :     // String.charAt(x) = String.fromCharCode(String.charCodeAt(x))
    1887           0 :     MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
    1888           0 :     current->add(charCode);
    1889             : 
    1890           0 :     MFromCharCode* string = MFromCharCode::New(alloc(), charCode);
    1891           0 :     current->add(string);
    1892           0 :     current->push(string);
    1893           0 :     return InliningStatus_Inlined;
    1894             : }
    1895             : 
    1896             : IonBuilder::InliningResult
    1897           0 : IonBuilder::inlineRegExpMatcher(CallInfo& callInfo)
    1898             : {
    1899             :     // This is called from Self-hosted JS, after testing each argument,
    1900             :     // most of following tests should be passed.
    1901             : 
    1902           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    1903           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1904           0 :         return InliningStatus_NotInlined;
    1905             :     }
    1906             : 
    1907           0 :     MDefinition* rxArg = callInfo.getArg(0);
    1908           0 :     MDefinition* strArg = callInfo.getArg(1);
    1909           0 :     MDefinition* lastIndexArg = callInfo.getArg(2);
    1910             : 
    1911           0 :     if (rxArg->type() != MIRType::Object)
    1912           0 :         return InliningStatus_NotInlined;
    1913             : 
    1914           0 :     TemporaryTypeSet* rxTypes = rxArg->resultTypeSet();
    1915           0 :     const Class* clasp = rxTypes ? rxTypes->getKnownClass(constraints()) : nullptr;
    1916           0 :     if (clasp != &RegExpObject::class_)
    1917           0 :         return InliningStatus_NotInlined;
    1918             : 
    1919           0 :     if (strArg->mightBeType(MIRType::Object))
    1920           0 :         return InliningStatus_NotInlined;
    1921             : 
    1922           0 :     if (lastIndexArg->type() != MIRType::Int32)
    1923           0 :         return InliningStatus_NotInlined;
    1924             : 
    1925           0 :     JSContext* cx = GetJitContext()->cx;
    1926           0 :     if (!cx->compartment()->jitCompartment()->ensureRegExpMatcherStubExists(cx)) {
    1927           0 :         cx->clearPendingException(); // OOM or overrecursion.
    1928           0 :         return InliningStatus_NotInlined;
    1929             :     }
    1930             : 
    1931           0 :     callInfo.setImplicitlyUsedUnchecked();
    1932             : 
    1933           0 :     MInstruction* matcher = MRegExpMatcher::New(alloc(), rxArg, strArg, lastIndexArg);
    1934           0 :     current->add(matcher);
    1935           0 :     current->push(matcher);
    1936             : 
    1937           0 :     MOZ_TRY(resumeAfter(matcher));
    1938           0 :     MOZ_TRY(pushTypeBarrier(matcher, getInlineReturnTypeSet(), BarrierKind::TypeSet));
    1939           0 :     return InliningStatus_Inlined;
    1940             : }
    1941             : 
    1942             : IonBuilder::InliningResult
    1943           0 : IonBuilder::inlineRegExpSearcher(CallInfo& callInfo)
    1944             : {
    1945             :     // This is called from Self-hosted JS, after testing each argument,
    1946             :     // most of following tests should be passed.
    1947             : 
    1948           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    1949           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1950           0 :         return InliningStatus_NotInlined;
    1951             :     }
    1952             : 
    1953           0 :     MDefinition* rxArg = callInfo.getArg(0);
    1954           0 :     MDefinition* strArg = callInfo.getArg(1);
    1955           0 :     MDefinition* lastIndexArg = callInfo.getArg(2);
    1956             : 
    1957           0 :     if (rxArg->type() != MIRType::Object)
    1958           0 :         return InliningStatus_NotInlined;
    1959             : 
    1960           0 :     TemporaryTypeSet* regexpTypes = rxArg->resultTypeSet();
    1961           0 :     const Class* clasp = regexpTypes ? regexpTypes->getKnownClass(constraints()) : nullptr;
    1962           0 :     if (clasp != &RegExpObject::class_)
    1963           0 :         return InliningStatus_NotInlined;
    1964             : 
    1965           0 :     if (strArg->mightBeType(MIRType::Object))
    1966           0 :         return InliningStatus_NotInlined;
    1967             : 
    1968           0 :     if (lastIndexArg->type() != MIRType::Int32)
    1969           0 :         return InliningStatus_NotInlined;
    1970             : 
    1971           0 :     JSContext* cx = GetJitContext()->cx;
    1972           0 :     if (!cx->compartment()->jitCompartment()->ensureRegExpSearcherStubExists(cx)) {
    1973           0 :         cx->clearPendingException(); // OOM or overrecursion.
    1974           0 :         return abort(AbortReason::Error);
    1975             :     }
    1976             : 
    1977           0 :     callInfo.setImplicitlyUsedUnchecked();
    1978             : 
    1979           0 :     MInstruction* searcher = MRegExpSearcher::New(alloc(), rxArg, strArg, lastIndexArg);
    1980           0 :     current->add(searcher);
    1981           0 :     current->push(searcher);
    1982             : 
    1983           0 :     MOZ_TRY(resumeAfter(searcher));
    1984           0 :     MOZ_TRY(pushTypeBarrier(searcher, getInlineReturnTypeSet(), BarrierKind::TypeSet));
    1985           0 :     return InliningStatus_Inlined;
    1986             : }
    1987             : 
    1988             : IonBuilder::InliningResult
    1989           0 : IonBuilder::inlineRegExpTester(CallInfo& callInfo)
    1990             : {
    1991             :     // This is called from Self-hosted JS, after testing each argument,
    1992             :     // most of following tests should be passed.
    1993             : 
    1994           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    1995           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    1996           0 :         return InliningStatus_NotInlined;
    1997             :     }
    1998             : 
    1999           0 :     MDefinition* rxArg = callInfo.getArg(0);
    2000           0 :     MDefinition* strArg = callInfo.getArg(1);
    2001           0 :     MDefinition* lastIndexArg = callInfo.getArg(2);
    2002             : 
    2003           0 :     if (rxArg->type() != MIRType::Object)
    2004           0 :         return InliningStatus_NotInlined;
    2005             : 
    2006           0 :     TemporaryTypeSet* rxTypes = rxArg->resultTypeSet();
    2007           0 :     const Class* clasp = rxTypes ? rxTypes->getKnownClass(constraints()) : nullptr;
    2008           0 :     if (clasp != &RegExpObject::class_)
    2009           0 :         return InliningStatus_NotInlined;
    2010             : 
    2011           0 :     if (strArg->mightBeType(MIRType::Object))
    2012           0 :         return InliningStatus_NotInlined;
    2013             : 
    2014           0 :     if (lastIndexArg->type() != MIRType::Int32)
    2015           0 :         return InliningStatus_NotInlined;
    2016             : 
    2017           0 :     JSContext* cx = GetJitContext()->cx;
    2018           0 :     if (!cx->compartment()->jitCompartment()->ensureRegExpTesterStubExists(cx)) {
    2019           0 :         cx->clearPendingException(); // OOM or overrecursion.
    2020           0 :         return InliningStatus_NotInlined;
    2021             :     }
    2022             : 
    2023           0 :     callInfo.setImplicitlyUsedUnchecked();
    2024             : 
    2025           0 :     MInstruction* tester = MRegExpTester::New(alloc(), rxArg, strArg, lastIndexArg);
    2026           0 :     current->add(tester);
    2027           0 :     current->push(tester);
    2028             : 
    2029           0 :     MOZ_TRY(resumeAfter(tester));
    2030           0 :     return InliningStatus_Inlined;
    2031             : }
    2032             : 
    2033             : IonBuilder::InliningResult
    2034           0 : IonBuilder::inlineIsRegExpObject(CallInfo& callInfo)
    2035             : {
    2036           0 :     if (callInfo.constructing() || callInfo.argc() != 1) {
    2037           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2038           0 :         return InliningStatus_NotInlined;
    2039             :     }
    2040             : 
    2041           0 :     if (getInlineReturnType() != MIRType::Boolean)
    2042           0 :         return InliningStatus_NotInlined;
    2043             : 
    2044           0 :     MDefinition* arg = callInfo.getArg(0);
    2045             : 
    2046             :     bool isRegExpObject;
    2047           0 :     if (!arg->mightBeType(MIRType::Object)) {
    2048           0 :         isRegExpObject = false;
    2049             :     } else {
    2050           0 :         if (arg->type() != MIRType::Object)
    2051           0 :             return InliningStatus_NotInlined;
    2052             : 
    2053           0 :         TemporaryTypeSet* types = arg->resultTypeSet();
    2054           0 :         const Class* clasp = types ? types->getKnownClass(constraints()) : nullptr;
    2055           0 :         if (!clasp || clasp->isProxy())
    2056           0 :             return InliningStatus_NotInlined;
    2057             : 
    2058           0 :         isRegExpObject = (clasp == &RegExpObject::class_);
    2059             :     }
    2060             : 
    2061           0 :     pushConstant(BooleanValue(isRegExpObject));
    2062             : 
    2063           0 :     callInfo.setImplicitlyUsedUnchecked();
    2064           0 :     return InliningStatus_Inlined;
    2065             : }
    2066             : 
    2067             : IonBuilder::InliningResult
    2068           0 : IonBuilder::inlineRegExpPrototypeOptimizable(CallInfo& callInfo)
    2069             : {
    2070           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    2071           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2072           0 :         return InliningStatus_NotInlined;
    2073             :     }
    2074             : 
    2075           0 :     MDefinition* protoArg = callInfo.getArg(0);
    2076             : 
    2077           0 :     if (protoArg->type() != MIRType::Object)
    2078           0 :         return InliningStatus_NotInlined;
    2079             : 
    2080           0 :     if (getInlineReturnType() != MIRType::Boolean)
    2081           0 :         return InliningStatus_NotInlined;
    2082             : 
    2083           0 :     callInfo.setImplicitlyUsedUnchecked();
    2084             : 
    2085           0 :     MInstruction* opt = MRegExpPrototypeOptimizable::New(alloc(), protoArg);
    2086           0 :     current->add(opt);
    2087           0 :     current->push(opt);
    2088             : 
    2089           0 :     return InliningStatus_Inlined;
    2090             : }
    2091             : 
    2092             : IonBuilder::InliningResult
    2093           0 : IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo)
    2094             : {
    2095           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    2096           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2097           0 :         return InliningStatus_NotInlined;
    2098             :     }
    2099             : 
    2100           0 :     MDefinition* rxArg = callInfo.getArg(0);
    2101           0 :     MDefinition* protoArg = callInfo.getArg(1);
    2102             : 
    2103           0 :     if (rxArg->type() != MIRType::Object)
    2104           0 :         return InliningStatus_NotInlined;
    2105             : 
    2106           0 :     if (protoArg->type() != MIRType::Object)
    2107           0 :         return InliningStatus_NotInlined;
    2108             : 
    2109           0 :     if (getInlineReturnType() != MIRType::Boolean)
    2110           0 :         return InliningStatus_NotInlined;
    2111             : 
    2112           0 :     callInfo.setImplicitlyUsedUnchecked();
    2113             : 
    2114           0 :     MInstruction* opt = MRegExpInstanceOptimizable::New(alloc(), rxArg, protoArg);
    2115           0 :     current->add(opt);
    2116           0 :     current->push(opt);
    2117             : 
    2118           0 :     return InliningStatus_Inlined;
    2119             : }
    2120             : 
    2121             : IonBuilder::InliningResult
    2122           0 : IonBuilder::inlineGetFirstDollarIndex(CallInfo& callInfo)
    2123             : {
    2124           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    2125           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2126           0 :         return InliningStatus_NotInlined;
    2127             :     }
    2128             : 
    2129           0 :     MDefinition* strArg = callInfo.getArg(0);
    2130             : 
    2131           0 :     if (strArg->type() != MIRType::String)
    2132           0 :         return InliningStatus_NotInlined;
    2133             : 
    2134           0 :     if (getInlineReturnType() != MIRType::Int32)
    2135           0 :         return InliningStatus_NotInlined;
    2136             : 
    2137           0 :     callInfo.setImplicitlyUsedUnchecked();
    2138             : 
    2139           0 :     MInstruction* ins = MGetFirstDollarIndex::New(alloc(), strArg);
    2140           0 :     current->add(ins);
    2141           0 :     current->push(ins);
    2142             : 
    2143           0 :     return InliningStatus_Inlined;
    2144             : }
    2145             : 
    2146             : IonBuilder::InliningResult
    2147           0 : IonBuilder::inlineStringReplaceString(CallInfo& callInfo)
    2148             : {
    2149           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    2150           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2151           0 :         return InliningStatus_NotInlined;
    2152             :     }
    2153             : 
    2154           0 :     if (getInlineReturnType() != MIRType::String)
    2155           0 :         return InliningStatus_NotInlined;
    2156             : 
    2157           0 :     MDefinition* strArg = callInfo.getArg(0);
    2158           0 :     MDefinition* patArg = callInfo.getArg(1);
    2159           0 :     MDefinition* replArg = callInfo.getArg(2);
    2160             : 
    2161           0 :     if (strArg->type() != MIRType::String)
    2162           0 :         return InliningStatus_NotInlined;
    2163             : 
    2164           0 :     if (patArg->type() != MIRType::String)
    2165           0 :         return InliningStatus_NotInlined;
    2166             : 
    2167           0 :     if (replArg->type() != MIRType::String)
    2168           0 :         return InliningStatus_NotInlined;
    2169             : 
    2170           0 :     callInfo.setImplicitlyUsedUnchecked();
    2171             : 
    2172           0 :     MInstruction* cte = MStringReplace::New(alloc(), strArg, patArg, replArg);
    2173           0 :     current->add(cte);
    2174           0 :     current->push(cte);
    2175           0 :     if (cte->isEffectful())
    2176           0 :         MOZ_TRY(resumeAfter(cte));
    2177           0 :     return InliningStatus_Inlined;
    2178             : }
    2179             : 
    2180             : IonBuilder::InliningResult
    2181           0 : IonBuilder::inlineSubstringKernel(CallInfo& callInfo)
    2182             : {
    2183           0 :     MOZ_ASSERT(callInfo.argc() == 3);
    2184           0 :     MOZ_ASSERT(!callInfo.constructing());
    2185             : 
    2186             :     // Return: String.
    2187           0 :     if (getInlineReturnType() != MIRType::String)
    2188           0 :         return InliningStatus_NotInlined;
    2189             : 
    2190             :     // Arg 0: String.
    2191           0 :     if (callInfo.getArg(0)->type() != MIRType::String)
    2192           0 :         return InliningStatus_NotInlined;
    2193             : 
    2194             :     // Arg 1: Int.
    2195           0 :     if (callInfo.getArg(1)->type() != MIRType::Int32)
    2196           0 :         return InliningStatus_NotInlined;
    2197             : 
    2198             :     // Arg 2: Int.
    2199           0 :     if (callInfo.getArg(2)->type() != MIRType::Int32)
    2200           0 :         return InliningStatus_NotInlined;
    2201             : 
    2202           0 :     callInfo.setImplicitlyUsedUnchecked();
    2203             : 
    2204           0 :     MSubstr* substr = MSubstr::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
    2205           0 :                                             callInfo.getArg(2));
    2206           0 :     current->add(substr);
    2207           0 :     current->push(substr);
    2208             : 
    2209           0 :     return InliningStatus_Inlined;
    2210             : }
    2211             : 
    2212             : IonBuilder::InliningResult
    2213           0 : IonBuilder::inlineObjectCreate(CallInfo& callInfo)
    2214             : {
    2215           0 :     if (callInfo.argc() != 1 || callInfo.constructing())
    2216           0 :         return InliningStatus_NotInlined;
    2217             : 
    2218           0 :     JSObject* templateObject = inspector->getTemplateObjectForNative(pc, obj_create);
    2219           0 :     if (!templateObject)
    2220           0 :         return InliningStatus_NotInlined;
    2221             : 
    2222           0 :     MOZ_ASSERT(templateObject->is<PlainObject>());
    2223           0 :     MOZ_ASSERT(!templateObject->isSingleton());
    2224             : 
    2225             :     // Ensure the argument matches the template object's prototype.
    2226           0 :     MDefinition* arg = callInfo.getArg(0);
    2227           0 :     if (JSObject* proto = templateObject->staticPrototype()) {
    2228           0 :         if (IsInsideNursery(proto))
    2229           0 :             return InliningStatus_NotInlined;
    2230             : 
    2231           0 :         TemporaryTypeSet* types = arg->resultTypeSet();
    2232           0 :         if (!types || types->maybeSingleton() != proto)
    2233           0 :             return InliningStatus_NotInlined;
    2234             : 
    2235           0 :         MOZ_ASSERT(types->getKnownMIRType() == MIRType::Object);
    2236             :     } else {
    2237           0 :         if (arg->type() != MIRType::Null)
    2238           0 :             return InliningStatus_NotInlined;
    2239             :     }
    2240             : 
    2241           0 :     callInfo.setImplicitlyUsedUnchecked();
    2242             : 
    2243           0 :     bool emitted = false;
    2244           0 :     MOZ_TRY(newObjectTryTemplateObject(&emitted, templateObject));
    2245             : 
    2246           0 :     MOZ_ASSERT(emitted);
    2247           0 :     return InliningStatus_Inlined;
    2248             : }
    2249             : 
    2250             : IonBuilder::InliningResult
    2251           7 : IonBuilder::inlineHasClass(CallInfo& callInfo,
    2252             :                            const Class* clasp1, const Class* clasp2,
    2253             :                            const Class* clasp3, const Class* clasp4)
    2254             : {
    2255           7 :     if (callInfo.constructing() || callInfo.argc() != 1) {
    2256           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2257           0 :         return InliningStatus_NotInlined;
    2258             :     }
    2259             : 
    2260           7 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2261           0 :         return InliningStatus_NotInlined;
    2262           7 :     if (getInlineReturnType() != MIRType::Boolean)
    2263           0 :         return InliningStatus_NotInlined;
    2264             : 
    2265           7 :     TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
    2266           7 :     const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr;
    2267           7 :     if (knownClass) {
    2268          21 :         pushConstant(BooleanValue(knownClass == clasp1 ||
    2269           0 :                                   knownClass == clasp2 ||
    2270           7 :                                   knownClass == clasp3 ||
    2271          14 :                                   knownClass == clasp4));
    2272             :     } else {
    2273           0 :         MHasClass* hasClass1 = MHasClass::New(alloc(), callInfo.getArg(0), clasp1);
    2274           0 :         current->add(hasClass1);
    2275             : 
    2276           0 :         if (!clasp2 && !clasp3 && !clasp4) {
    2277           0 :             current->push(hasClass1);
    2278             :         } else {
    2279           0 :             const Class* remaining[] = { clasp2, clasp3, clasp4 };
    2280           0 :             MDefinition* last = hasClass1;
    2281           0 :             for (size_t i = 0; i < ArrayLength(remaining); i++) {
    2282           0 :                 MHasClass* hasClass = MHasClass::New(alloc(), callInfo.getArg(0), remaining[i]);
    2283           0 :                 current->add(hasClass);
    2284           0 :                 MBitOr* either = MBitOr::New(alloc(), last, hasClass);
    2285           0 :                 either->infer(inspector, pc);
    2286           0 :                 current->add(either);
    2287           0 :                 last = either;
    2288             :             }
    2289             : 
    2290           0 :             MDefinition* result = convertToBoolean(last);
    2291           0 :             current->push(result);
    2292             :         }
    2293             :     }
    2294             : 
    2295           7 :     callInfo.setImplicitlyUsedUnchecked();
    2296           7 :     return InliningStatus_Inlined;
    2297             : }
    2298             : 
    2299             : IonBuilder::InliningResult
    2300           0 : IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode)
    2301             : {
    2302           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    2303           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2304           0 :         return InliningStatus_NotInlined;
    2305             :     }
    2306             : 
    2307           0 :     MDefinition* iterArg = callInfo.getArg(0);
    2308           0 :     MDefinition* resultArg = callInfo.getArg(1);
    2309             : 
    2310           0 :     if (iterArg->type() != MIRType::Object)
    2311           0 :         return InliningStatus_NotInlined;
    2312             : 
    2313           0 :     TemporaryTypeSet* iterTypes = iterArg->resultTypeSet();
    2314           0 :     const Class* iterClasp = iterTypes ? iterTypes->getKnownClass(constraints()) : nullptr;
    2315           0 :     if (mode == MGetNextEntryForIterator::Map) {
    2316           0 :         if (iterClasp != &MapIteratorObject::class_)
    2317           0 :             return InliningStatus_NotInlined;
    2318             :     } else {
    2319           0 :         MOZ_ASSERT(mode == MGetNextEntryForIterator::Set);
    2320             : 
    2321           0 :         if (iterClasp != &SetIteratorObject::class_)
    2322           0 :             return InliningStatus_NotInlined;
    2323             :     }
    2324             : 
    2325           0 :     if (resultArg->type() != MIRType::Object)
    2326           0 :         return InliningStatus_NotInlined;
    2327             : 
    2328           0 :     TemporaryTypeSet* resultTypes = resultArg->resultTypeSet();
    2329           0 :     const Class* resultClasp = resultTypes ? resultTypes->getKnownClass(constraints()) : nullptr;
    2330           0 :     if (resultClasp != &ArrayObject::class_)
    2331           0 :         return InliningStatus_NotInlined;
    2332             : 
    2333           0 :     callInfo.setImplicitlyUsedUnchecked();
    2334             : 
    2335           0 :     MInstruction* next = MGetNextEntryForIterator::New(alloc(), iterArg, resultArg, mode);
    2336           0 :     current->add(next);
    2337           0 :     current->push(next);
    2338             : 
    2339           0 :     MOZ_TRY(resumeAfter(next));
    2340           0 :     return InliningStatus_Inlined;
    2341             : }
    2342             : 
    2343             : static bool
    2344           0 : IsArrayBufferObject(CompilerConstraintList* constraints, MDefinition* def)
    2345             : {
    2346           0 :     MOZ_ASSERT(def->type() == MIRType::Object);
    2347             : 
    2348           0 :     TemporaryTypeSet* types = def->resultTypeSet();
    2349           0 :     if (!types)
    2350           0 :         return false;
    2351             : 
    2352           0 :     return types->getKnownClass(constraints) == &ArrayBufferObject::class_;
    2353             : }
    2354             : 
    2355             : IonBuilder::InliningResult
    2356           0 : IonBuilder::inlineArrayBufferByteLength(CallInfo& callInfo)
    2357             : {
    2358           0 :     MOZ_ASSERT(!callInfo.constructing());
    2359           0 :     MOZ_ASSERT(callInfo.argc() == 1);
    2360             : 
    2361           0 :     MDefinition* objArg = callInfo.getArg(0);
    2362           0 :     if (objArg->type() != MIRType::Object)
    2363           0 :         return InliningStatus_NotInlined;
    2364           0 :     if (getInlineReturnType() != MIRType::Int32)
    2365           0 :         return InliningStatus_NotInlined;
    2366             : 
    2367           0 :     MInstruction* ins = addArrayBufferByteLength(objArg);
    2368           0 :     current->push(ins);
    2369             : 
    2370           0 :     callInfo.setImplicitlyUsedUnchecked();
    2371           0 :     return InliningStatus_Inlined;
    2372             : }
    2373             : 
    2374             : IonBuilder::InliningResult
    2375           0 : IonBuilder::inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo)
    2376             : {
    2377           0 :     MOZ_ASSERT(!callInfo.constructing());
    2378           0 :     MOZ_ASSERT(callInfo.argc() == 1);
    2379             : 
    2380           0 :     MDefinition* objArg = callInfo.getArg(0);
    2381           0 :     if (objArg->type() != MIRType::Object)
    2382           0 :         return InliningStatus_NotInlined;
    2383           0 :     if (getInlineReturnType() != MIRType::Int32)
    2384           0 :         return InliningStatus_NotInlined;
    2385             : 
    2386           0 :     if (!IsArrayBufferObject(constraints(), objArg))
    2387           0 :         return InliningStatus_NotInlined;
    2388             : 
    2389           0 :     MInstruction* ins = addArrayBufferByteLength(objArg);
    2390           0 :     current->push(ins);
    2391             : 
    2392           0 :     callInfo.setImplicitlyUsedUnchecked();
    2393           0 :     return InliningStatus_Inlined;
    2394             : }
    2395             : 
    2396             : IonBuilder::InliningResult
    2397           0 : IonBuilder::inlineTypedArray(CallInfo& callInfo, Native native)
    2398             : {
    2399           0 :     if (!callInfo.constructing()) {
    2400           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2401           0 :         return InliningStatus_NotInlined;
    2402             :     }
    2403             : 
    2404           0 :     if (getInlineReturnType() != MIRType::Object)
    2405           0 :         return InliningStatus_NotInlined;
    2406           0 :     if (callInfo.argc() != 1)
    2407           0 :         return InliningStatus_NotInlined;
    2408             : 
    2409           0 :     MDefinition* arg = callInfo.getArg(0);
    2410             : 
    2411           0 :     if (arg->type() != MIRType::Int32)
    2412           0 :         return InliningStatus_NotInlined;
    2413             : 
    2414           0 :     JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native);
    2415             : 
    2416           0 :     if (!templateObject) {
    2417           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
    2418           0 :         return InliningStatus_NotInlined;
    2419             :     }
    2420             : 
    2421           0 :     MOZ_ASSERT(templateObject->is<TypedArrayObject>());
    2422           0 :     TypedArrayObject* obj = &templateObject->as<TypedArrayObject>();
    2423             : 
    2424             :     // Do not optimize when we see a template object with a singleton type,
    2425             :     // since it hits at most once.
    2426           0 :     if (templateObject->isSingleton())
    2427           0 :         return InliningStatus_NotInlined;
    2428             : 
    2429           0 :     MInstruction* ins = nullptr;
    2430             : 
    2431           0 :     if (!arg->isConstant()) {
    2432           0 :         callInfo.setImplicitlyUsedUnchecked();
    2433           0 :         ins = MNewTypedArrayDynamicLength::New(alloc(), constraints(), templateObject,
    2434             :                                                templateObject->group()->initialHeap(constraints()),
    2435           0 :                                                arg);
    2436             :     } else {
    2437             :         // Negative lengths must throw a RangeError.  (We don't track that this
    2438             :         // might have previously thrown, when determining whether to inline, so we
    2439             :         // have to deal with this error case when inlining.)
    2440           0 :         int32_t providedLen = arg->maybeConstantValue()->toInt32();
    2441           0 :         if (providedLen <= 0)
    2442           0 :             return InliningStatus_NotInlined;
    2443             : 
    2444           0 :         uint32_t len = AssertedCast<uint32_t>(providedLen);
    2445             : 
    2446           0 :         if (obj->length() != len)
    2447           0 :             return InliningStatus_NotInlined;
    2448             : 
    2449           0 :         callInfo.setImplicitlyUsedUnchecked();
    2450           0 :         MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), obj);
    2451           0 :         current->add(templateConst);
    2452           0 :         ins = MNewTypedArray::New(alloc(), constraints(), templateConst,
    2453           0 :                                   obj->group()->initialHeap(constraints()));
    2454             :     }
    2455             : 
    2456           0 :     current->add(ins);
    2457           0 :     current->push(ins);
    2458           0 :     MOZ_TRY(resumeAfter(ins));
    2459           0 :     return InliningStatus_Inlined;
    2460             : }
    2461             : 
    2462             : IonBuilder::InliningResult
    2463           7 : IonBuilder::inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior)
    2464             : {
    2465           7 :     MOZ_ASSERT(!callInfo.constructing());
    2466           7 :     MOZ_ASSERT(callInfo.argc() == 1);
    2467             : 
    2468           7 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2469           0 :         return InliningStatus_NotInlined;
    2470           7 :     if (getInlineReturnType() != MIRType::Boolean)
    2471           0 :         return InliningStatus_NotInlined;
    2472             : 
    2473             :     // The test is elaborate: in-line only if there is exact
    2474             :     // information.
    2475             : 
    2476           7 :     TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
    2477           7 :     if (!types)
    2478           0 :         return InliningStatus_NotInlined;
    2479             : 
    2480           7 :     bool result = false;
    2481           7 :     switch (types->forAllClasses(constraints(), IsTypedArrayClass)) {
    2482             :       case TemporaryTypeSet::ForAllResult::ALL_FALSE:
    2483             :         // Wrapped typed arrays won't appear to be typed arrays per a
    2484             :         // |forAllClasses| query.  If wrapped typed arrays are to be considered
    2485             :         // typed arrays, a negative answer is not conclusive.  Don't inline in
    2486             :         // that case.
    2487           0 :         if (wrappingBehavior == AllowWrappedTypedArrays) {
    2488           0 :             switch (types->forAllClasses(constraints(), IsProxyClass)) {
    2489             :               case TemporaryTypeSet::ForAllResult::ALL_FALSE:
    2490             :               case TemporaryTypeSet::ForAllResult::EMPTY:
    2491           0 :                 break;
    2492             :               case TemporaryTypeSet::ForAllResult::ALL_TRUE:
    2493             :               case TemporaryTypeSet::ForAllResult::MIXED:
    2494           0 :                 return InliningStatus_NotInlined;
    2495             :             }
    2496             :         }
    2497             : 
    2498             :         MOZ_FALLTHROUGH;
    2499             : 
    2500             :       case TemporaryTypeSet::ForAllResult::EMPTY:
    2501           0 :         result = false;
    2502           0 :         break;
    2503             : 
    2504             :       case TemporaryTypeSet::ForAllResult::ALL_TRUE:
    2505           0 :         result = true;
    2506           0 :         break;
    2507             : 
    2508             :       case TemporaryTypeSet::ForAllResult::MIXED:
    2509           7 :         return InliningStatus_NotInlined;
    2510             :     }
    2511             : 
    2512           0 :     pushConstant(BooleanValue(result));
    2513             : 
    2514           0 :     callInfo.setImplicitlyUsedUnchecked();
    2515           0 :     return InliningStatus_Inlined;
    2516             : }
    2517             : 
    2518             : IonBuilder::InliningResult
    2519           0 : IonBuilder::inlineIsTypedArray(CallInfo& callInfo)
    2520             : {
    2521           0 :     return inlineIsTypedArrayHelper(callInfo, RejectWrappedTypedArrays);
    2522             : }
    2523             : 
    2524             : IonBuilder::InliningResult
    2525           7 : IonBuilder::inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo)
    2526             : {
    2527           7 :     return inlineIsTypedArrayHelper(callInfo, AllowWrappedTypedArrays);
    2528             : }
    2529             : 
    2530             : static bool
    2531           0 : IsTypedArrayObject(CompilerConstraintList* constraints, MDefinition* def)
    2532             : {
    2533           0 :     MOZ_ASSERT(def->type() == MIRType::Object);
    2534             : 
    2535           0 :     TemporaryTypeSet* types = def->resultTypeSet();
    2536           0 :     if (!types)
    2537           0 :         return false;
    2538             : 
    2539           0 :     return types->forAllClasses(constraints, IsTypedArrayClass) ==
    2540           0 :            TemporaryTypeSet::ForAllResult::ALL_TRUE;
    2541             : }
    2542             : 
    2543             : IonBuilder::InliningResult
    2544           0 : IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo)
    2545             : {
    2546           0 :     MOZ_ASSERT(!callInfo.constructing());
    2547           0 :     MOZ_ASSERT(callInfo.argc() == 1);
    2548           0 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2549           0 :         return InliningStatus_NotInlined;
    2550           0 :     if (getInlineReturnType() != MIRType::Int32)
    2551           0 :         return InliningStatus_NotInlined;
    2552             : 
    2553           0 :     if (!IsTypedArrayObject(constraints(), callInfo.getArg(0)))
    2554           0 :         return InliningStatus_NotInlined;
    2555             : 
    2556           0 :     MInstruction* length = addTypedArrayLength(callInfo.getArg(0));
    2557           0 :     current->push(length);
    2558             : 
    2559           0 :     callInfo.setImplicitlyUsedUnchecked();
    2560           0 :     return InliningStatus_Inlined;
    2561             : }
    2562             : 
    2563             : IonBuilder::InliningResult
    2564           0 : IonBuilder::inlineTypedArrayLength(CallInfo& callInfo)
    2565             : {
    2566           0 :     return inlinePossiblyWrappedTypedArrayLength(callInfo);
    2567             : }
    2568             : 
    2569             : IonBuilder::InliningResult
    2570           0 : IonBuilder::inlineSetDisjointTypedElements(CallInfo& callInfo)
    2571             : {
    2572           0 :     MOZ_ASSERT(!callInfo.constructing());
    2573           0 :     MOZ_ASSERT(callInfo.argc() == 3);
    2574             : 
    2575             :     // Initial argument requirements.
    2576             : 
    2577           0 :     MDefinition* target = callInfo.getArg(0);
    2578           0 :     if (target->type() != MIRType::Object)
    2579           0 :         return InliningStatus_NotInlined;
    2580             : 
    2581           0 :     if (getInlineReturnType() != MIRType::Undefined)
    2582           0 :         return InliningStatus_NotInlined;
    2583             : 
    2584           0 :     MDefinition* targetOffset = callInfo.getArg(1);
    2585           0 :     MOZ_ASSERT(targetOffset->type() == MIRType::Int32);
    2586             : 
    2587           0 :     MDefinition* sourceTypedArray = callInfo.getArg(2);
    2588           0 :     if (sourceTypedArray->type() != MIRType::Object)
    2589           0 :         return InliningStatus_NotInlined;
    2590             : 
    2591             :     // Only attempt to optimize if |target| and |sourceTypedArray| are both
    2592             :     // definitely typed arrays.  (The former always is.  The latter is not,
    2593             :     // necessarily, because of wrappers.)
    2594           0 :     if (!IsTypedArrayObject(constraints(), target) ||
    2595           0 :         !IsTypedArrayObject(constraints(), sourceTypedArray))
    2596             :     {
    2597           0 :         return InliningStatus_NotInlined;
    2598             :     }
    2599             : 
    2600           0 :     auto sets = MSetDisjointTypedElements::New(alloc(), target, targetOffset, sourceTypedArray);
    2601           0 :     current->add(sets);
    2602             : 
    2603           0 :     pushConstant(UndefinedValue());
    2604             : 
    2605           0 :     MOZ_TRY(resumeAfter(sets));
    2606           0 :     callInfo.setImplicitlyUsedUnchecked();
    2607           0 :     return InliningStatus_Inlined;
    2608             : }
    2609             : 
    2610             : IonBuilder::InliningResult
    2611           0 : IonBuilder::inlineObjectIsTypeDescr(CallInfo& callInfo)
    2612             : {
    2613           0 :     if (callInfo.constructing() || callInfo.argc() != 1) {
    2614           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2615           0 :         return InliningStatus_NotInlined;
    2616             :     }
    2617             : 
    2618           0 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2619           0 :         return InliningStatus_NotInlined;
    2620           0 :     if (getInlineReturnType() != MIRType::Boolean)
    2621           0 :         return InliningStatus_NotInlined;
    2622             : 
    2623             :     // The test is elaborate: in-line only if there is exact
    2624             :     // information.
    2625             : 
    2626           0 :     TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
    2627           0 :     if (!types)
    2628           0 :         return InliningStatus_NotInlined;
    2629             : 
    2630           0 :     bool result = false;
    2631           0 :     switch (types->forAllClasses(constraints(), IsTypeDescrClass)) {
    2632             :     case TemporaryTypeSet::ForAllResult::ALL_FALSE:
    2633             :     case TemporaryTypeSet::ForAllResult::EMPTY:
    2634           0 :         result = false;
    2635           0 :         break;
    2636             :     case TemporaryTypeSet::ForAllResult::ALL_TRUE:
    2637           0 :         result = true;
    2638           0 :         break;
    2639             :     case TemporaryTypeSet::ForAllResult::MIXED:
    2640           0 :         return InliningStatus_NotInlined;
    2641             :     }
    2642             : 
    2643           0 :     pushConstant(BooleanValue(result));
    2644             : 
    2645           0 :     callInfo.setImplicitlyUsedUnchecked();
    2646           0 :     return InliningStatus_Inlined;
    2647             : }
    2648             : 
    2649             : IonBuilder::InliningResult
    2650           0 : IonBuilder::inlineSetTypedObjectOffset(CallInfo& callInfo)
    2651             : {
    2652           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    2653           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2654           0 :         return InliningStatus_NotInlined;
    2655             :     }
    2656             : 
    2657           0 :     MDefinition* typedObj = callInfo.getArg(0);
    2658           0 :     MDefinition* offset = callInfo.getArg(1);
    2659             : 
    2660             :     // Return type should be undefined or something wacky is going on.
    2661           0 :     if (getInlineReturnType() != MIRType::Undefined)
    2662           0 :         return InliningStatus_NotInlined;
    2663             : 
    2664             :     // Check typedObj is a, well, typed object. Go ahead and use TI
    2665             :     // data. If this check should fail, that is almost certainly a bug
    2666             :     // in self-hosted code -- either because it's not being careful
    2667             :     // with TI or because of something else -- but we'll just let it
    2668             :     // fall through to the SetTypedObjectOffset intrinsic in such
    2669             :     // cases.
    2670           0 :     TemporaryTypeSet* types = typedObj->resultTypeSet();
    2671           0 :     if (typedObj->type() != MIRType::Object || !types)
    2672           0 :         return InliningStatus_NotInlined;
    2673           0 :     switch (types->forAllClasses(constraints(), IsTypedObjectClass)) {
    2674             :       case TemporaryTypeSet::ForAllResult::ALL_FALSE:
    2675             :       case TemporaryTypeSet::ForAllResult::EMPTY:
    2676             :       case TemporaryTypeSet::ForAllResult::MIXED:
    2677           0 :         return InliningStatus_NotInlined;
    2678             :       case TemporaryTypeSet::ForAllResult::ALL_TRUE:
    2679           0 :         break;
    2680             :     }
    2681             : 
    2682             :     // Check type of offset argument is an integer.
    2683           0 :     if (offset->type() != MIRType::Int32)
    2684           0 :         return InliningStatus_NotInlined;
    2685             : 
    2686           0 :     callInfo.setImplicitlyUsedUnchecked();
    2687           0 :     MInstruction* ins = MSetTypedObjectOffset::New(alloc(), typedObj, offset);
    2688           0 :     current->add(ins);
    2689           0 :     current->push(ins);
    2690           0 :     return InliningStatus_Inlined;
    2691             : }
    2692             : 
    2693             : IonBuilder::InliningResult
    2694          26 : IonBuilder::inlineUnsafeSetReservedSlot(CallInfo& callInfo)
    2695             : {
    2696          26 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    2697           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2698           0 :         return InliningStatus_NotInlined;
    2699             :     }
    2700          26 :     if (getInlineReturnType() != MIRType::Undefined)
    2701           0 :         return InliningStatus_NotInlined;
    2702          26 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2703           0 :         return InliningStatus_NotInlined;
    2704          26 :     if (callInfo.getArg(1)->type() != MIRType::Int32)
    2705           0 :         return InliningStatus_NotInlined;
    2706             : 
    2707             :     // Don't inline if we don't have a constant slot.
    2708          26 :     MDefinition* arg = callInfo.getArg(1);
    2709          26 :     if (!arg->isConstant())
    2710           0 :         return InliningStatus_NotInlined;
    2711          26 :     uint32_t slot = uint32_t(arg->toConstant()->toInt32());
    2712             : 
    2713          26 :     callInfo.setImplicitlyUsedUnchecked();
    2714             : 
    2715             :     MStoreFixedSlot* store =
    2716          26 :         MStoreFixedSlot::NewBarriered(alloc(), callInfo.getArg(0), slot, callInfo.getArg(2));
    2717          26 :     current->add(store);
    2718          26 :     current->push(store);
    2719             : 
    2720          26 :     if (NeedsPostBarrier(callInfo.getArg(2)))
    2721           4 :         current->add(MPostWriteBarrier::New(alloc(), callInfo.getArg(0), callInfo.getArg(2)));
    2722             : 
    2723          26 :     return InliningStatus_Inlined;
    2724             : }
    2725             : 
    2726             : IonBuilder::InliningResult
    2727          21 : IonBuilder::inlineUnsafeGetReservedSlot(CallInfo& callInfo, MIRType knownValueType)
    2728             : {
    2729          21 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    2730           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2731           0 :         return InliningStatus_NotInlined;
    2732             :     }
    2733          21 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2734           0 :         return InliningStatus_NotInlined;
    2735          21 :     if (callInfo.getArg(1)->type() != MIRType::Int32)
    2736           0 :         return InliningStatus_NotInlined;
    2737             : 
    2738             :     // Don't inline if we don't have a constant slot.
    2739          21 :     MDefinition* arg = callInfo.getArg(1);
    2740          21 :     if (!arg->isConstant())
    2741           0 :         return InliningStatus_NotInlined;
    2742          21 :     uint32_t slot = uint32_t(arg->toConstant()->toInt32());
    2743             : 
    2744          21 :     callInfo.setImplicitlyUsedUnchecked();
    2745             : 
    2746          21 :     MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot);
    2747          21 :     current->add(load);
    2748          21 :     current->push(load);
    2749          21 :     if (knownValueType != MIRType::Value) {
    2750             :         // We know what type we have in this slot.  Assert that this is in fact
    2751             :         // what we've seen coming from this slot in the past, then tell the
    2752             :         // MLoadFixedSlot about its result type.  That will make us do an
    2753             :         // infallible unbox as part of the slot load and then we'll barrier on
    2754             :         // the unbox result.  That way the type barrier code won't end up doing
    2755             :         // MIRType checks and conditional unboxing.
    2756           7 :         MOZ_ASSERT_IF(!getInlineReturnTypeSet()->empty(),
    2757             :                       getInlineReturnType() == knownValueType);
    2758           7 :         load->setResultType(knownValueType);
    2759             :     }
    2760             : 
    2761             :     // We don't track reserved slot types, so always emit a barrier.
    2762          21 :     MOZ_TRY(pushTypeBarrier(load, getInlineReturnTypeSet(), BarrierKind::TypeSet));
    2763          21 :     return InliningStatus_Inlined;
    2764             : }
    2765             : 
    2766             : IonBuilder::InliningResult
    2767           1 : IonBuilder::inlineIsCallable(CallInfo& callInfo)
    2768             : {
    2769           1 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    2770           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2771           0 :         return InliningStatus_NotInlined;
    2772             :     }
    2773             : 
    2774           1 :     if (getInlineReturnType() != MIRType::Boolean)
    2775           0 :         return InliningStatus_NotInlined;
    2776             : 
    2777           1 :     MDefinition* arg = callInfo.getArg(0);
    2778             :     // Do not inline if the type of arg is neither primitive nor object.
    2779           1 :     if (arg->type() > MIRType::Object)
    2780           0 :         return InliningStatus_NotInlined;
    2781             : 
    2782             :     // Try inlining with constant true/false: only objects may be callable at
    2783             :     // all, and if we know the class check if it is callable.
    2784           1 :     bool isCallableKnown = false;
    2785             :     bool isCallableConstant;
    2786           1 :     if (arg->type() != MIRType::Object) {
    2787             :         // Primitive (including undefined and null).
    2788           0 :         isCallableKnown = true;
    2789           0 :         isCallableConstant = false;
    2790             :     } else {
    2791           1 :         TemporaryTypeSet* types = arg->resultTypeSet();
    2792           1 :         const Class* clasp = types ? types->getKnownClass(constraints()) : nullptr;
    2793           1 :         if (clasp && !clasp->isProxy()) {
    2794           1 :             isCallableKnown = true;
    2795           1 :             isCallableConstant = clasp->nonProxyCallable();
    2796             :         }
    2797             :     }
    2798             : 
    2799           1 :     callInfo.setImplicitlyUsedUnchecked();
    2800             : 
    2801           1 :     if (isCallableKnown) {
    2802           1 :         MConstant* constant = MConstant::New(alloc(), BooleanValue(isCallableConstant));
    2803           1 :         current->add(constant);
    2804           1 :         current->push(constant);
    2805           1 :         return InliningStatus_Inlined;
    2806             :     }
    2807             : 
    2808           0 :     MIsCallable* isCallable = MIsCallable::New(alloc(), arg);
    2809           0 :     current->add(isCallable);
    2810           0 :     current->push(isCallable);
    2811             : 
    2812           0 :     return InliningStatus_Inlined;
    2813             : }
    2814             : 
    2815             : IonBuilder::InliningResult
    2816           0 : IonBuilder::inlineIsConstructor(CallInfo& callInfo)
    2817             : {
    2818           0 :     MOZ_ASSERT(!callInfo.constructing());
    2819           0 :     MOZ_ASSERT(callInfo.argc() == 1);
    2820             : 
    2821           0 :     if (getInlineReturnType() != MIRType::Boolean)
    2822           0 :         return InliningStatus_NotInlined;
    2823           0 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2824           0 :         return InliningStatus_NotInlined;
    2825             : 
    2826           0 :     callInfo.setImplicitlyUsedUnchecked();
    2827             : 
    2828           0 :     MIsConstructor* ins = MIsConstructor::New(alloc(), callInfo.getArg(0));
    2829           0 :     current->add(ins);
    2830           0 :     current->push(ins);
    2831             : 
    2832           0 :     return InliningStatus_Inlined;
    2833             : }
    2834             : 
    2835             : IonBuilder::InliningResult
    2836           7 : IonBuilder::inlineIsObject(CallInfo& callInfo)
    2837             : {
    2838           7 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    2839           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2840           0 :         return InliningStatus_NotInlined;
    2841             :     }
    2842           7 :     if (getInlineReturnType() != MIRType::Boolean)
    2843           0 :         return InliningStatus_NotInlined;
    2844             : 
    2845           7 :     callInfo.setImplicitlyUsedUnchecked();
    2846           7 :     if (callInfo.getArg(0)->type() == MIRType::Object) {
    2847           7 :         pushConstant(BooleanValue(true));
    2848             :     } else {
    2849           0 :         MIsObject* isObject = MIsObject::New(alloc(), callInfo.getArg(0));
    2850           0 :         current->add(isObject);
    2851           0 :         current->push(isObject);
    2852             :     }
    2853           7 :     return InliningStatus_Inlined;
    2854             : }
    2855             : 
    2856             : IonBuilder::InliningResult
    2857           4 : IonBuilder::inlineToObject(CallInfo& callInfo)
    2858             : {
    2859           4 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    2860           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2861           0 :         return InliningStatus_NotInlined;
    2862             :     }
    2863             : 
    2864             :     // If we know the input type is an object, nop ToObject.
    2865           4 :     if (getInlineReturnType() != MIRType::Object)
    2866           0 :         return InliningStatus_NotInlined;
    2867           4 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    2868           0 :         return InliningStatus_NotInlined;
    2869             : 
    2870           4 :     callInfo.setImplicitlyUsedUnchecked();
    2871           4 :     MDefinition* object = callInfo.getArg(0);
    2872             : 
    2873           4 :     current->push(object);
    2874           4 :     return InliningStatus_Inlined;
    2875             : }
    2876             : 
    2877             : IonBuilder::InliningResult
    2878           0 : IonBuilder::inlineIsWrappedArrayConstructor(CallInfo& callInfo)
    2879             : {
    2880           0 :     if (callInfo.constructing() || callInfo.argc() != 1) {
    2881           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2882           0 :         return InliningStatus_NotInlined;
    2883             :     }
    2884             : 
    2885           0 :     if (getInlineReturnType() != MIRType::Boolean)
    2886           0 :         return InliningStatus_NotInlined;
    2887           0 :     MDefinition* arg = callInfo.getArg(0);
    2888           0 :     if (arg->type() != MIRType::Object)
    2889           0 :         return InliningStatus_NotInlined;
    2890             : 
    2891           0 :     TemporaryTypeSet* types = arg->resultTypeSet();
    2892           0 :     switch (types->forAllClasses(constraints(), IsProxyClass)) {
    2893             :       case TemporaryTypeSet::ForAllResult::ALL_FALSE:
    2894           0 :         break;
    2895             :       case TemporaryTypeSet::ForAllResult::EMPTY:
    2896             :       case TemporaryTypeSet::ForAllResult::ALL_TRUE:
    2897             :       case TemporaryTypeSet::ForAllResult::MIXED:
    2898           0 :         return InliningStatus_NotInlined;
    2899             :     }
    2900             : 
    2901           0 :     callInfo.setImplicitlyUsedUnchecked();
    2902             : 
    2903             :     // Inline only if argument is absolutely *not* a Proxy.
    2904           0 :     pushConstant(BooleanValue(false));
    2905           0 :     return InliningStatus_Inlined;
    2906             : }
    2907             : 
    2908             : IonBuilder::InliningResult
    2909           8 : IonBuilder::inlineToInteger(CallInfo& callInfo)
    2910             : {
    2911           8 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    2912           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    2913           0 :         return InliningStatus_NotInlined;
    2914             :     }
    2915             : 
    2916           8 :     MDefinition* input = callInfo.getArg(0);
    2917             : 
    2918             :     // Only optimize cases where input contains only number, null or boolean
    2919          24 :     if (input->mightBeType(MIRType::Object) ||
    2920          16 :         input->mightBeType(MIRType::String) ||
    2921          16 :         input->mightBeType(MIRType::Symbol) ||
    2922          24 :         input->mightBeType(MIRType::Undefined) ||
    2923           8 :         input->mightBeMagicType())
    2924             :     {
    2925           0 :         return InliningStatus_NotInlined;
    2926             :     }
    2927             : 
    2928           8 :     MOZ_ASSERT(input->type() == MIRType::Value || input->type() == MIRType::Null ||
    2929             :                input->type() == MIRType::Boolean || IsNumberType(input->type()));
    2930             : 
    2931             :     // Only optimize cases where output is int32
    2932           8 :     if (getInlineReturnType() != MIRType::Int32)
    2933           0 :         return InliningStatus_NotInlined;
    2934             : 
    2935           8 :     callInfo.setImplicitlyUsedUnchecked();
    2936             : 
    2937           8 :     MToInt32* toInt32 = MToInt32::New(alloc(), callInfo.getArg(0));
    2938           8 :     current->add(toInt32);
    2939           8 :     current->push(toInt32);
    2940           8 :     return InliningStatus_Inlined;
    2941             : }
    2942             : 
    2943             : IonBuilder::InliningResult
    2944           0 : IonBuilder::inlineToString(CallInfo& callInfo)
    2945             : {
    2946           0 :     if (callInfo.argc() != 1 || callInfo.constructing())
    2947           0 :         return InliningStatus_NotInlined;
    2948             : 
    2949           0 :     if (getInlineReturnType() != MIRType::String)
    2950           0 :         return InliningStatus_NotInlined;
    2951             : 
    2952           0 :     callInfo.setImplicitlyUsedUnchecked();
    2953           0 :     MToString* toString = MToString::New(alloc(), callInfo.getArg(0));
    2954           0 :     current->add(toString);
    2955           0 :     current->push(toString);
    2956           0 :     return InliningStatus_Inlined;
    2957             : }
    2958             : 
    2959             : IonBuilder::InliningResult
    2960           0 : IonBuilder::inlineBailout(CallInfo& callInfo)
    2961             : {
    2962           0 :     callInfo.setImplicitlyUsedUnchecked();
    2963             : 
    2964           0 :     current->add(MBail::New(alloc()));
    2965             : 
    2966           0 :     MConstant* undefined = MConstant::New(alloc(), UndefinedValue());
    2967           0 :     current->add(undefined);
    2968           0 :     current->push(undefined);
    2969           0 :     return InliningStatus_Inlined;
    2970             : }
    2971             : 
    2972             : IonBuilder::InliningResult
    2973           0 : IonBuilder::inlineAssertFloat32(CallInfo& callInfo)
    2974             : {
    2975           0 :     if (callInfo.argc() != 2)
    2976           0 :         return InliningStatus_NotInlined;
    2977             : 
    2978           0 :     MDefinition* secondArg = callInfo.getArg(1);
    2979             : 
    2980           0 :     MOZ_ASSERT(secondArg->type() == MIRType::Boolean);
    2981           0 :     MOZ_ASSERT(secondArg->isConstant());
    2982             : 
    2983           0 :     bool mustBeFloat32 = secondArg->toConstant()->toBoolean();
    2984           0 :     current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32));
    2985             : 
    2986           0 :     MConstant* undefined = MConstant::New(alloc(), UndefinedValue());
    2987           0 :     current->add(undefined);
    2988           0 :     current->push(undefined);
    2989           0 :     callInfo.setImplicitlyUsedUnchecked();
    2990           0 :     return InliningStatus_Inlined;
    2991             : }
    2992             : 
    2993             : IonBuilder::InliningResult
    2994           0 : IonBuilder::inlineAssertRecoveredOnBailout(CallInfo& callInfo)
    2995             : {
    2996           0 :     if (callInfo.argc() != 2)
    2997           0 :         return InliningStatus_NotInlined;
    2998             : 
    2999             :     // Don't assert for recovered instructions when recovering is disabled.
    3000           0 :     if (JitOptions.disableRecoverIns)
    3001           0 :         return InliningStatus_NotInlined;
    3002             : 
    3003           0 :     if (JitOptions.checkRangeAnalysis) {
    3004             :         // If we are checking the range of all instructions, then the guards
    3005             :         // inserted by Range Analysis prevent the use of recover
    3006             :         // instruction. Thus, we just disable these checks.
    3007           0 :         current->push(constant(UndefinedValue()));
    3008           0 :         callInfo.setImplicitlyUsedUnchecked();
    3009           0 :         return InliningStatus_Inlined;
    3010             :     }
    3011             : 
    3012           0 :     MDefinition* secondArg = callInfo.getArg(1);
    3013             : 
    3014           0 :     MOZ_ASSERT(secondArg->type() == MIRType::Boolean);
    3015           0 :     MOZ_ASSERT(secondArg->isConstant());
    3016             : 
    3017           0 :     bool mustBeRecovered = secondArg->toConstant()->toBoolean();
    3018             :     MAssertRecoveredOnBailout* assert =
    3019           0 :         MAssertRecoveredOnBailout::New(alloc(), callInfo.getArg(0), mustBeRecovered);
    3020           0 :     current->add(assert);
    3021           0 :     current->push(assert);
    3022             : 
    3023             :     // Create an instruction sequence which implies that the argument of the
    3024             :     // assertRecoveredOnBailout function would be encoded at least in one
    3025             :     // Snapshot.
    3026           0 :     MNop* nop = MNop::New(alloc());
    3027           0 :     current->add(nop);
    3028           0 :     MOZ_TRY(resumeAfter(nop));
    3029           0 :     current->add(MEncodeSnapshot::New(alloc()));
    3030             : 
    3031           0 :     current->pop();
    3032           0 :     current->push(constant(UndefinedValue()));
    3033           0 :     callInfo.setImplicitlyUsedUnchecked();
    3034           0 :     return InliningStatus_Inlined;
    3035             : }
    3036             : 
    3037             : IonBuilder::InliningResult
    3038           0 : IonBuilder::inlineAtomicsCompareExchange(CallInfo& callInfo)
    3039             : {
    3040           0 :     if (callInfo.argc() != 4 || callInfo.constructing()) {
    3041           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3042           0 :         return InliningStatus_NotInlined;
    3043             :     }
    3044             : 
    3045             :     // These guards are desirable here and in subsequent atomics to
    3046             :     // avoid bad bailouts with MTruncateToInt32, see https://bugzilla.mozilla.org/show_bug.cgi?id=1141986#c20.
    3047           0 :     MDefinition* oldval = callInfo.getArg(2);
    3048           0 :     if (oldval->mightBeType(MIRType::Object) || oldval->mightBeType(MIRType::Symbol))
    3049           0 :         return InliningStatus_NotInlined;
    3050             : 
    3051           0 :     MDefinition* newval = callInfo.getArg(3);
    3052           0 :     if (newval->mightBeType(MIRType::Object) || newval->mightBeType(MIRType::Symbol))
    3053           0 :         return InliningStatus_NotInlined;
    3054             : 
    3055             :     Scalar::Type arrayType;
    3056           0 :     bool requiresCheck = false;
    3057           0 :     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
    3058           0 :         return InliningStatus_NotInlined;
    3059             : 
    3060           0 :     callInfo.setImplicitlyUsedUnchecked();
    3061             : 
    3062             :     MInstruction* elements;
    3063             :     MDefinition* index;
    3064           0 :     atomicsCheckBounds(callInfo, &elements, &index);
    3065             : 
    3066           0 :     if (requiresCheck)
    3067           0 :         addSharedTypedArrayGuard(callInfo.getArg(0));
    3068             : 
    3069             :     MCompareExchangeTypedArrayElement* cas =
    3070           0 :         MCompareExchangeTypedArrayElement::New(alloc(), elements, index, arrayType, oldval, newval);
    3071           0 :     cas->setResultType(getInlineReturnType());
    3072           0 :     current->add(cas);
    3073           0 :     current->push(cas);
    3074             : 
    3075           0 :     MOZ_TRY(resumeAfter(cas));
    3076           0 :     return InliningStatus_Inlined;
    3077             : }
    3078             : 
    3079             : IonBuilder::InliningResult
    3080           0 : IonBuilder::inlineAtomicsExchange(CallInfo& callInfo)
    3081             : {
    3082           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    3083           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3084           0 :         return InliningStatus_NotInlined;
    3085             :     }
    3086             : 
    3087           0 :     MDefinition* value = callInfo.getArg(2);
    3088           0 :     if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol))
    3089           0 :         return InliningStatus_NotInlined;
    3090             : 
    3091             :     Scalar::Type arrayType;
    3092           0 :     bool requiresCheck = false;
    3093           0 :     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
    3094           0 :         return InliningStatus_NotInlined;
    3095             : 
    3096           0 :     callInfo.setImplicitlyUsedUnchecked();
    3097             : 
    3098             :     MInstruction* elements;
    3099             :     MDefinition* index;
    3100           0 :     atomicsCheckBounds(callInfo, &elements, &index);
    3101             : 
    3102           0 :     if (requiresCheck)
    3103           0 :         addSharedTypedArrayGuard(callInfo.getArg(0));
    3104             : 
    3105             :     MInstruction* exchange =
    3106           0 :         MAtomicExchangeTypedArrayElement::New(alloc(), elements, index, value, arrayType);
    3107           0 :     exchange->setResultType(getInlineReturnType());
    3108           0 :     current->add(exchange);
    3109           0 :     current->push(exchange);
    3110             : 
    3111           0 :     MOZ_TRY(resumeAfter(exchange));
    3112           0 :     return InliningStatus_Inlined;
    3113             : }
    3114             : 
    3115             : IonBuilder::InliningResult
    3116           0 : IonBuilder::inlineAtomicsLoad(CallInfo& callInfo)
    3117             : {
    3118           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    3119           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3120           0 :         return InliningStatus_NotInlined;
    3121             :     }
    3122             : 
    3123             :     Scalar::Type arrayType;
    3124           0 :     bool requiresCheck = false;
    3125           0 :     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
    3126           0 :         return InliningStatus_NotInlined;
    3127             : 
    3128           0 :     callInfo.setImplicitlyUsedUnchecked();
    3129             : 
    3130             :     MInstruction* elements;
    3131             :     MDefinition* index;
    3132           0 :     atomicsCheckBounds(callInfo, &elements, &index);
    3133             : 
    3134           0 :     if (requiresCheck)
    3135           0 :         addSharedTypedArrayGuard(callInfo.getArg(0));
    3136             : 
    3137             :     MLoadUnboxedScalar* load =
    3138           0 :         MLoadUnboxedScalar::New(alloc(), elements, index, arrayType,
    3139           0 :                                 DoesRequireMemoryBarrier);
    3140           0 :     load->setResultType(getInlineReturnType());
    3141           0 :     current->add(load);
    3142           0 :     current->push(load);
    3143             : 
    3144             :     // Loads are considered effectful (they execute a memory barrier).
    3145           0 :     MOZ_TRY(resumeAfter(load));
    3146           0 :     return InliningStatus_Inlined;
    3147             : }
    3148             : 
    3149             : IonBuilder::InliningResult
    3150           0 : IonBuilder::inlineAtomicsStore(CallInfo& callInfo)
    3151             : {
    3152           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    3153           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3154           0 :         return InliningStatus_NotInlined;
    3155             :     }
    3156             : 
    3157             :     // Atomics.store() is annoying because it returns the result of converting
    3158             :     // the value by ToInteger(), not the input value, nor the result of
    3159             :     // converting the value by ToInt32().  It is especially annoying because
    3160             :     // almost nobody uses the result value.
    3161             :     //
    3162             :     // As an expedient compromise, therefore, we inline only if the result is
    3163             :     // obviously unused or if the argument is already Int32 and thus requires no
    3164             :     // conversion.
    3165             : 
    3166           0 :     MDefinition* value = callInfo.getArg(2);
    3167           0 :     if (!BytecodeIsPopped(pc) && value->type() != MIRType::Int32) {
    3168           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadType);
    3169           0 :         return InliningStatus_NotInlined;
    3170             :     }
    3171             : 
    3172           0 :     if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol))
    3173           0 :         return InliningStatus_NotInlined;
    3174             : 
    3175             :     Scalar::Type arrayType;
    3176           0 :     bool requiresCheck = false;
    3177           0 :     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck, DontCheckAtomicResult))
    3178           0 :         return InliningStatus_NotInlined;
    3179             : 
    3180           0 :     callInfo.setImplicitlyUsedUnchecked();
    3181             : 
    3182             :     MInstruction* elements;
    3183             :     MDefinition* index;
    3184           0 :     atomicsCheckBounds(callInfo, &elements, &index);
    3185             : 
    3186           0 :     if (requiresCheck)
    3187           0 :         addSharedTypedArrayGuard(callInfo.getArg(0));
    3188             : 
    3189           0 :     MDefinition* toWrite = value;
    3190           0 :     if (toWrite->type() != MIRType::Int32) {
    3191           0 :         toWrite = MTruncateToInt32::New(alloc(), toWrite);
    3192           0 :         current->add(toWrite->toInstruction());
    3193             :     }
    3194             :     MStoreUnboxedScalar* store =
    3195           0 :         MStoreUnboxedScalar::New(alloc(), elements, index, toWrite, arrayType,
    3196           0 :                                  MStoreUnboxedScalar::TruncateInput, DoesRequireMemoryBarrier);
    3197           0 :     current->add(store);
    3198           0 :     current->push(value);       // Either Int32 or not used; in either case correct
    3199             : 
    3200           0 :     MOZ_TRY(resumeAfter(store));
    3201           0 :     return InliningStatus_Inlined;
    3202             : }
    3203             : 
    3204             : IonBuilder::InliningResult
    3205           0 : IonBuilder::inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target)
    3206             : {
    3207           0 :     if (callInfo.argc() != 3 || callInfo.constructing()) {
    3208           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3209           0 :         return InliningStatus_NotInlined;
    3210             :     }
    3211             : 
    3212           0 :     MDefinition* value = callInfo.getArg(2);
    3213           0 :     if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol))
    3214           0 :         return InliningStatus_NotInlined;
    3215             : 
    3216             :     Scalar::Type arrayType;
    3217           0 :     bool requiresCheck = false;
    3218           0 :     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
    3219           0 :         return InliningStatus_NotInlined;
    3220             : 
    3221           0 :     callInfo.setImplicitlyUsedUnchecked();
    3222             : 
    3223           0 :     if (requiresCheck)
    3224           0 :         addSharedTypedArrayGuard(callInfo.getArg(0));
    3225             : 
    3226             :     MInstruction* elements;
    3227             :     MDefinition* index;
    3228           0 :     atomicsCheckBounds(callInfo, &elements, &index);
    3229             : 
    3230           0 :     AtomicOp k = AtomicFetchAddOp;
    3231           0 :     switch (target) {
    3232             :       case InlinableNative::AtomicsAdd:
    3233           0 :         k = AtomicFetchAddOp;
    3234           0 :         break;
    3235             :       case InlinableNative::AtomicsSub:
    3236           0 :         k = AtomicFetchSubOp;
    3237           0 :         break;
    3238             :       case InlinableNative::AtomicsAnd:
    3239           0 :         k = AtomicFetchAndOp;
    3240           0 :         break;
    3241             :       case InlinableNative::AtomicsOr:
    3242           0 :         k = AtomicFetchOrOp;
    3243           0 :         break;
    3244             :       case InlinableNative::AtomicsXor:
    3245           0 :         k = AtomicFetchXorOp;
    3246           0 :         break;
    3247             :       default:
    3248           0 :         MOZ_CRASH("Bad atomic operation");
    3249             :     }
    3250             : 
    3251             :     MAtomicTypedArrayElementBinop* binop =
    3252           0 :         MAtomicTypedArrayElementBinop::New(alloc(), k, elements, index, arrayType, value);
    3253           0 :     binop->setResultType(getInlineReturnType());
    3254           0 :     current->add(binop);
    3255           0 :     current->push(binop);
    3256             : 
    3257           0 :     MOZ_TRY(resumeAfter(binop));
    3258           0 :     return InliningStatus_Inlined;
    3259             : }
    3260             : 
    3261             : IonBuilder::InliningResult
    3262           0 : IonBuilder::inlineAtomicsIsLockFree(CallInfo& callInfo)
    3263             : {
    3264           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    3265           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3266           0 :         return InliningStatus_NotInlined;
    3267             :     }
    3268             : 
    3269           0 :     callInfo.setImplicitlyUsedUnchecked();
    3270             : 
    3271             :     MAtomicIsLockFree* ilf =
    3272           0 :         MAtomicIsLockFree::New(alloc(), callInfo.getArg(0));
    3273           0 :     current->add(ilf);
    3274           0 :     current->push(ilf);
    3275             : 
    3276           0 :     return InliningStatus_Inlined;
    3277             : }
    3278             : 
    3279             : bool
    3280           0 : IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayType,
    3281             :                                       bool* requiresTagCheck, AtomicCheckResult checkResult)
    3282             : {
    3283           0 :     if (!JitSupportsAtomics())
    3284           0 :         return false;
    3285             : 
    3286           0 :     if (callInfo.getArg(0)->type() != MIRType::Object)
    3287           0 :         return false;
    3288             : 
    3289           0 :     if (callInfo.getArg(1)->type() != MIRType::Int32)
    3290           0 :         return false;
    3291             : 
    3292             :     // Ensure that the first argument is a TypedArray that maps shared
    3293             :     // memory.
    3294             :     //
    3295             :     // Then check both that the element type is something we can
    3296             :     // optimize and that the return type is suitable for that element
    3297             :     // type.
    3298             : 
    3299           0 :     TemporaryTypeSet* arg0Types = callInfo.getArg(0)->resultTypeSet();
    3300           0 :     if (!arg0Types)
    3301           0 :         return false;
    3302             : 
    3303             :     TemporaryTypeSet::TypedArraySharedness sharedness;
    3304           0 :     *arrayType = arg0Types->getTypedArrayType(constraints(), &sharedness);
    3305           0 :     *requiresTagCheck = sharedness != TemporaryTypeSet::KnownShared;
    3306           0 :     switch (*arrayType) {
    3307             :       case Scalar::Int8:
    3308             :       case Scalar::Uint8:
    3309             :       case Scalar::Int16:
    3310             :       case Scalar::Uint16:
    3311             :       case Scalar::Int32:
    3312           0 :         return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Int32;
    3313             :       case Scalar::Uint32:
    3314             :         // Bug 1077305: it would be attractive to allow inlining even
    3315             :         // if the inline return type is Int32, which it will frequently
    3316             :         // be.
    3317           0 :         return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double;
    3318             :       default:
    3319             :         // Excludes floating types and Uint8Clamped.
    3320           0 :         return false;
    3321             :     }
    3322             : }
    3323             : 
    3324             : void
    3325           0 : IonBuilder::atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index)
    3326             : {
    3327             :     // Perform bounds checking and extract the elements vector.
    3328           0 :     MDefinition* obj = callInfo.getArg(0);
    3329           0 :     MInstruction* length = nullptr;
    3330           0 :     *index = callInfo.getArg(1);
    3331           0 :     *elements = nullptr;
    3332           0 :     addTypedArrayLengthAndData(obj, DoBoundsCheck, index, &length, elements);
    3333           0 : }
    3334             : 
    3335             : IonBuilder::InliningResult
    3336           0 : IonBuilder::inlineIsConstructing(CallInfo& callInfo)
    3337             : {
    3338           0 :     MOZ_ASSERT(!callInfo.constructing());
    3339           0 :     MOZ_ASSERT(callInfo.argc() == 0);
    3340           0 :     MOZ_ASSERT(script()->functionNonDelazifying(),
    3341             :                "isConstructing() should only be called in function scripts");
    3342             : 
    3343           0 :     if (getInlineReturnType() != MIRType::Boolean)
    3344           0 :         return InliningStatus_NotInlined;
    3345             : 
    3346           0 :     callInfo.setImplicitlyUsedUnchecked();
    3347             : 
    3348           0 :     if (inliningDepth_ == 0) {
    3349           0 :         MInstruction* ins = MIsConstructing::New(alloc());
    3350           0 :         current->add(ins);
    3351           0 :         current->push(ins);
    3352           0 :         return InliningStatus_Inlined;
    3353             :     }
    3354             : 
    3355           0 :     bool constructing = inlineCallInfo_->constructing();
    3356           0 :     pushConstant(BooleanValue(constructing));
    3357           0 :     return InliningStatus_Inlined;
    3358             : }
    3359             : 
    3360             : IonBuilder::InliningResult
    3361           0 : IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr)
    3362             : {
    3363             :     // Only inline default constructors for now.
    3364           0 :     if (callInfo.argc() != 0) {
    3365           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3366           0 :         return InliningStatus_NotInlined;
    3367             :     }
    3368             : 
    3369           0 :     if (size_t(descr->size()) > InlineTypedObject::MaximumSize)
    3370           0 :         return InliningStatus_NotInlined;
    3371             : 
    3372           0 :     JSObject* obj = inspector->getTemplateObjectForClassHook(pc, descr->getClass());
    3373           0 :     if (!obj || !obj->is<InlineTypedObject>())
    3374           0 :         return InliningStatus_NotInlined;
    3375             : 
    3376           0 :     InlineTypedObject* templateObject = &obj->as<InlineTypedObject>();
    3377           0 :     if (&templateObject->typeDescr() != descr)
    3378           0 :         return InliningStatus_NotInlined;
    3379             : 
    3380           0 :     callInfo.setImplicitlyUsedUnchecked();
    3381             : 
    3382           0 :     MNewTypedObject* ins = MNewTypedObject::New(alloc(), constraints(), templateObject,
    3383           0 :                                                 templateObject->group()->initialHeap(constraints()));
    3384           0 :     current->add(ins);
    3385           0 :     current->push(ins);
    3386             : 
    3387           0 :     return InliningStatus_Inlined;
    3388             : }
    3389             : 
    3390             : // Main entry point for SIMD inlining.
    3391             : // When the controlling simdType is an integer type, sign indicates whether the lanes should
    3392             : // be treated as signed or unsigned integers.
    3393             : IonBuilder::InliningResult
    3394           0 : IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type)
    3395             : {
    3396           0 :     if (!JitSupportsSimd()) {
    3397           0 :         trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport);
    3398           0 :         return InliningStatus_NotInlined;
    3399             :     }
    3400             : 
    3401           0 :     JSNative native = target->native();
    3402           0 :     const JSJitInfo* jitInfo = target->jitInfo();
    3403           0 :     MOZ_ASSERT(jitInfo && jitInfo->type() == JSJitInfo::InlinableNative);
    3404           0 :     SimdOperation simdOp = SimdOperation(jitInfo->nativeOp);
    3405             : 
    3406           0 :     switch(simdOp) {
    3407             :       case SimdOperation::Constructor:
    3408             :         // SIMD constructor calls are handled via inlineNonFunctionCall(), so
    3409             :         // they won't show up here where target is required to be a JSFunction.
    3410             :         // See also inlineConstructSimdObject().
    3411           0 :         MOZ_CRASH("SIMD constructor call not expected.");
    3412             :       case SimdOperation::Fn_check:
    3413           0 :         return inlineSimdCheck(callInfo, native, type);
    3414             :       case SimdOperation::Fn_splat:
    3415           0 :         return inlineSimdSplat(callInfo, native, type);
    3416             :       case SimdOperation::Fn_extractLane:
    3417           0 :         return inlineSimdExtractLane(callInfo, native, type);
    3418             :       case SimdOperation::Fn_replaceLane:
    3419           0 :         return inlineSimdReplaceLane(callInfo, native, type);
    3420             :       case SimdOperation::Fn_select:
    3421           0 :         return inlineSimdSelect(callInfo, native, type);
    3422             :       case SimdOperation::Fn_swizzle:
    3423           0 :         return inlineSimdShuffle(callInfo, native, type, 1);
    3424             :       case SimdOperation::Fn_shuffle:
    3425           0 :         return inlineSimdShuffle(callInfo, native, type, 2);
    3426             : 
    3427             :         // Unary arithmetic.
    3428             :       case SimdOperation::Fn_abs:
    3429           0 :         return inlineSimdUnary(callInfo, native, MSimdUnaryArith::abs, type);
    3430             :       case SimdOperation::Fn_neg:
    3431           0 :         return inlineSimdUnary(callInfo, native, MSimdUnaryArith::neg, type);
    3432             :       case SimdOperation::Fn_not:
    3433           0 :         return inlineSimdUnary(callInfo, native, MSimdUnaryArith::not_, type);
    3434             :       case SimdOperation::Fn_reciprocalApproximation:
    3435             :         return inlineSimdUnary(callInfo, native, MSimdUnaryArith::reciprocalApproximation,
    3436           0 :                                type);
    3437             :       case SimdOperation::Fn_reciprocalSqrtApproximation:
    3438             :         return inlineSimdUnary(callInfo, native, MSimdUnaryArith::reciprocalSqrtApproximation,
    3439           0 :                                type);
    3440             :       case SimdOperation::Fn_sqrt:
    3441           0 :         return inlineSimdUnary(callInfo, native, MSimdUnaryArith::sqrt, type);
    3442             : 
    3443             :         // Binary arithmetic.
    3444             :       case SimdOperation::Fn_add:
    3445           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_add, type);
    3446             :       case SimdOperation::Fn_sub:
    3447           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_sub, type);
    3448             :       case SimdOperation::Fn_mul:
    3449           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_mul, type);
    3450             :       case SimdOperation::Fn_div:
    3451           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_div, type);
    3452             :       case SimdOperation::Fn_max:
    3453           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_max, type);
    3454             :       case SimdOperation::Fn_min:
    3455           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_min, type);
    3456             :       case SimdOperation::Fn_maxNum:
    3457           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_maxNum, type);
    3458             :       case SimdOperation::Fn_minNum:
    3459           0 :         return inlineSimdBinaryArith(callInfo, native, MSimdBinaryArith::Op_minNum, type);
    3460             : 
    3461             :         // Binary saturating.
    3462             :       case SimdOperation::Fn_addSaturate:
    3463           0 :         return inlineSimdBinarySaturating(callInfo, native, MSimdBinarySaturating::add, type);
    3464             :       case SimdOperation::Fn_subSaturate:
    3465           0 :         return inlineSimdBinarySaturating(callInfo, native, MSimdBinarySaturating::sub, type);
    3466             : 
    3467             :         // Binary bitwise.
    3468             :       case SimdOperation::Fn_and:
    3469           0 :         return inlineSimdBinaryBitwise(callInfo, native, MSimdBinaryBitwise::and_, type);
    3470             :       case SimdOperation::Fn_or:
    3471           0 :         return inlineSimdBinaryBitwise(callInfo, native, MSimdBinaryBitwise::or_, type);
    3472             :       case SimdOperation::Fn_xor:
    3473           0 :         return inlineSimdBinaryBitwise(callInfo, native, MSimdBinaryBitwise::xor_, type);
    3474             : 
    3475             :       // Shifts.
    3476             :       case SimdOperation::Fn_shiftLeftByScalar:
    3477           0 :         return inlineSimdShift(callInfo, native, MSimdShift::lsh, type);
    3478             :       case SimdOperation::Fn_shiftRightByScalar:
    3479           0 :         return inlineSimdShift(callInfo, native, MSimdShift::rshForSign(GetSimdSign(type)), type);
    3480             : 
    3481             :         // Boolean unary.
    3482             :       case SimdOperation::Fn_allTrue:
    3483           0 :         return inlineSimdAnyAllTrue(callInfo, /* IsAllTrue= */true, native, type);
    3484             :       case SimdOperation::Fn_anyTrue:
    3485           0 :         return inlineSimdAnyAllTrue(callInfo, /* IsAllTrue= */false, native, type);
    3486             : 
    3487             :         // Comparisons.
    3488             :       case SimdOperation::Fn_lessThan:
    3489           0 :         return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan, type);
    3490             :       case SimdOperation::Fn_lessThanOrEqual:
    3491           0 :         return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual, type);
    3492             :       case SimdOperation::Fn_equal:
    3493           0 :         return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal, type);
    3494             :       case SimdOperation::Fn_notEqual:
    3495           0 :         return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual, type);
    3496             :       case SimdOperation::Fn_greaterThan:
    3497           0 :         return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan, type);
    3498             :       case SimdOperation::Fn_greaterThanOrEqual:
    3499           0 :         return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual, type);
    3500             : 
    3501             :         // Int <-> Float conversions.
    3502             :       case SimdOperation::Fn_fromInt32x4:
    3503           0 :         return inlineSimdConvert(callInfo, native, false, SimdType::Int32x4, type);
    3504             :       case SimdOperation::Fn_fromUint32x4:
    3505           0 :         return inlineSimdConvert(callInfo, native, false, SimdType::Uint32x4, type);
    3506             :       case SimdOperation::Fn_fromFloat32x4:
    3507           0 :         return inlineSimdConvert(callInfo, native, false, SimdType::Float32x4, type);
    3508             : 
    3509             :         // Load/store.
    3510             :       case SimdOperation::Fn_load:
    3511           0 :         return inlineSimdLoad(callInfo, native, type, GetSimdLanes(type));
    3512             :       case SimdOperation::Fn_load1:
    3513           0 :         return inlineSimdLoad(callInfo, native, type, 1);
    3514             :       case SimdOperation::Fn_load2:
    3515           0 :         return inlineSimdLoad(callInfo, native, type, 2);
    3516             :       case SimdOperation::Fn_load3:
    3517           0 :         return inlineSimdLoad(callInfo, native, type, 3);
    3518             :       case SimdOperation::Fn_store:
    3519           0 :         return inlineSimdStore(callInfo, native, type, GetSimdLanes(type));
    3520             :       case SimdOperation::Fn_store1:
    3521           0 :         return inlineSimdStore(callInfo, native, type, 1);
    3522             :       case SimdOperation::Fn_store2:
    3523           0 :         return inlineSimdStore(callInfo, native, type, 2);
    3524             :       case SimdOperation::Fn_store3:
    3525           0 :         return inlineSimdStore(callInfo, native, type, 3);
    3526             : 
    3527             :         // Bitcasts. One for each type with a memory representation.
    3528             :       case SimdOperation::Fn_fromInt32x4Bits:
    3529           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Int32x4, type);
    3530             :       case SimdOperation::Fn_fromUint32x4Bits:
    3531           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Uint32x4, type);
    3532             :       case SimdOperation::Fn_fromInt16x8Bits:
    3533           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Int16x8, type);
    3534             :       case SimdOperation::Fn_fromUint16x8Bits:
    3535           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Uint16x8, type);
    3536             :       case SimdOperation::Fn_fromInt8x16Bits:
    3537           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Int8x16, type);
    3538             :       case SimdOperation::Fn_fromUint8x16Bits:
    3539           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Uint8x16, type);
    3540             :       case SimdOperation::Fn_fromFloat32x4Bits:
    3541           0 :         return inlineSimdConvert(callInfo, native, true, SimdType::Float32x4, type);
    3542             :       case SimdOperation::Fn_fromFloat64x2Bits:
    3543           0 :         return InliningStatus_NotInlined;
    3544             :     }
    3545             : 
    3546           0 :     MOZ_CRASH("Unexpected SIMD opcode");
    3547             : }
    3548             : 
    3549             : // The representation of boolean SIMD vectors is the same as the corresponding
    3550             : // integer SIMD vectors with -1 lanes meaning true and 0 lanes meaning false.
    3551             : //
    3552             : // Functions that set the value of a boolean vector lane work by applying
    3553             : // ToBoolean on the input argument, so they accept any argument type, just like
    3554             : // the MNot and MTest instructions.
    3555             : //
    3556             : // Convert any scalar value into an appropriate SIMD lane value: An Int32 value
    3557             : // that is either 0 for false or -1 for true.
    3558             : MDefinition*
    3559           0 : IonBuilder::convertToBooleanSimdLane(MDefinition* scalar)
    3560             : {
    3561             :     MSub* result;
    3562             : 
    3563           0 :     if (scalar->type() == MIRType::Boolean) {
    3564             :         // The input scalar is already a boolean with the int32 values 0 / 1.
    3565             :         // Compute result = 0 - scalar.
    3566           0 :         result = MSub::New(alloc(), constant(Int32Value(0)), scalar);
    3567             :     } else {
    3568             :         // For any other type, let MNot handle the conversion to boolean.
    3569             :         // Compute result = !scalar - 1.
    3570           0 :         MNot* inv = MNot::New(alloc(), scalar);
    3571           0 :         current->add(inv);
    3572           0 :         result = MSub::New(alloc(), inv, constant(Int32Value(1)));
    3573             :     }
    3574             : 
    3575           0 :     result->setInt32Specialization();
    3576           0 :     current->add(result);
    3577           0 :     return result;
    3578             : }
    3579             : 
    3580             : IonBuilder::InliningResult
    3581           0 : IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
    3582             : {
    3583           0 :     if (!JitSupportsSimd()) {
    3584           0 :         trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport);
    3585           0 :         return InliningStatus_NotInlined;
    3586             :     }
    3587             : 
    3588             :     // Generic constructor of SIMD valuesX4.
    3589             :     MIRType simdType;
    3590           0 :     if (!MaybeSimdTypeToMIRType(descr->type(), &simdType)) {
    3591           0 :         trackOptimizationOutcome(TrackedOutcome::SimdTypeNotOptimized);
    3592           0 :         return InliningStatus_NotInlined;
    3593             :     }
    3594             : 
    3595             :     // Take the templateObject out of Baseline ICs, such that we can box
    3596             :     // SIMD value type in the same kind of objects.
    3597           0 :     MOZ_ASSERT(size_t(descr->size(descr->type())) < InlineTypedObject::MaximumSize);
    3598           0 :     MOZ_ASSERT(descr->getClass() == &SimdTypeDescr::class_,
    3599             :                "getTemplateObjectForSimdCtor needs an update");
    3600             : 
    3601           0 :     JSObject* templateObject = inspector->getTemplateObjectForSimdCtor(pc, descr->type());
    3602           0 :     if (!templateObject)
    3603           0 :         return InliningStatus_NotInlined;
    3604             : 
    3605             :     // The previous assertion ensures this will never fail if we were able to
    3606             :     // allocate a templateObject in Baseline.
    3607           0 :     InlineTypedObject* inlineTypedObject = &templateObject->as<InlineTypedObject>();
    3608           0 :     MOZ_ASSERT(&inlineTypedObject->typeDescr() == descr);
    3609             : 
    3610             :     // When there are missing arguments, provide a default value
    3611             :     // containing the coercion of 'undefined' to the right type.
    3612           0 :     MConstant* defVal = nullptr;
    3613           0 :     MIRType laneType = SimdTypeToLaneType(simdType);
    3614           0 :     unsigned lanes = SimdTypeToLength(simdType);
    3615           0 :     if (lanes != 4 || callInfo.argc() < lanes) {
    3616           0 :         if (laneType == MIRType::Int32 || laneType == MIRType::Boolean) {
    3617             :             // The default lane for a boolean vector is |false|, but
    3618             :             // |MSimdSplat|, |MSimdValueX4|, and |MSimdInsertElement| all
    3619             :             // require an Int32 argument with the value 0 or 01 to initialize a
    3620             :             // boolean lane. See also convertToBooleanSimdLane() which is
    3621             :             // idempotent with a 0 argument after constant folding.
    3622           0 :             defVal = constant(Int32Value(0));
    3623           0 :         } else if (laneType == MIRType::Double) {
    3624           0 :             defVal = constant(DoubleNaNValue());
    3625             :         } else {
    3626           0 :             MOZ_ASSERT(laneType == MIRType::Float32);
    3627           0 :             defVal = MConstant::NewFloat32(alloc(), JS::GenericNaN());
    3628           0 :             current->add(defVal);
    3629             :         }
    3630             :     }
    3631             : 
    3632           0 :     MInstruction *values = nullptr;
    3633             : 
    3634             :     // Use the MSimdValueX4 constructor for X4 vectors.
    3635           0 :     if (lanes == 4) {
    3636             :         MDefinition* lane[4];
    3637           0 :         for (unsigned i = 0; i < 4; i++)
    3638           0 :             lane[i] = callInfo.getArgWithDefault(i, defVal);
    3639             : 
    3640             :         // Convert boolean lanes into Int32 0 / -1.
    3641           0 :         if (laneType == MIRType::Boolean) {
    3642           0 :             for (unsigned i = 0; i < 4; i++)
    3643           0 :                 lane[i] = convertToBooleanSimdLane(lane[i]);
    3644             :         }
    3645             : 
    3646           0 :         values = MSimdValueX4::New(alloc(), simdType, lane[0], lane[1], lane[2], lane[3]);
    3647           0 :         current->add(values);
    3648             :     } else {
    3649             :         // For general constructor calls, start from splat(defVal), insert one
    3650             :         // lane at a time.
    3651           0 :         values = MSimdSplat::New(alloc(), defVal, simdType);
    3652           0 :         current->add(values);
    3653             : 
    3654             :         // Stop early if constructor doesn't have enough arguments. These lanes
    3655             :         // then get the default value.
    3656           0 :         if (callInfo.argc() < lanes)
    3657           0 :             lanes = callInfo.argc();
    3658             : 
    3659           0 :         for (unsigned i = 0; i < lanes; i++) {
    3660           0 :             MDefinition* lane = callInfo.getArg(i);
    3661           0 :             if (laneType == MIRType::Boolean)
    3662           0 :                 lane = convertToBooleanSimdLane(lane);
    3663           0 :             values = MSimdInsertElement::New(alloc(), values, lane, i);
    3664           0 :             current->add(values);
    3665             :         }
    3666             :     }
    3667             : 
    3668           0 :     MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject, descr->type(),
    3669           0 :                                   inlineTypedObject->group()->initialHeap(constraints()));
    3670           0 :     current->add(obj);
    3671           0 :     current->push(obj);
    3672             : 
    3673           0 :     callInfo.setImplicitlyUsedUnchecked();
    3674           0 :     return InliningStatus_Inlined;
    3675             : }
    3676             : 
    3677             : bool
    3678           0 : IonBuilder::canInlineSimd(CallInfo& callInfo, JSNative native, unsigned numArgs,
    3679             :                           InlineTypedObject** templateObj)
    3680             : {
    3681           0 :     if (callInfo.argc() != numArgs)
    3682           0 :         return false;
    3683             : 
    3684           0 :     JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native);
    3685           0 :     if (!templateObject)
    3686           0 :         return false;
    3687             : 
    3688           0 :     *templateObj = &templateObject->as<InlineTypedObject>();
    3689           0 :     return true;
    3690             : }
    3691             : 
    3692             : IonBuilder::InliningResult
    3693           0 : IonBuilder::inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type)
    3694             : {
    3695           0 :     InlineTypedObject* templateObj = nullptr;
    3696           0 :     if (!canInlineSimd(callInfo, native, 1, &templateObj))
    3697           0 :         return InliningStatus_NotInlined;
    3698             : 
    3699             :     // Unboxing checks the SIMD object type and throws a TypeError if it doesn't
    3700             :     // match type.
    3701           0 :     MDefinition *arg = unboxSimd(callInfo.getArg(0), type);
    3702             : 
    3703             :     // Create an unbox/box pair, expecting the box to be optimized away if
    3704             :     // anyone use the return value from this check() call. This is what you want
    3705             :     // for code like this:
    3706             :     //
    3707             :     // function f(x) {
    3708             :     //   x = Int32x4.check(x)
    3709             :     //   for(...) {
    3710             :     //     y = Int32x4.add(x, ...)
    3711             :     //   }
    3712             :     //
    3713             :     // The unboxing of x happens as early as possible, and only once.
    3714           0 :     return boxSimd(callInfo, arg, templateObj);
    3715             : }
    3716             : 
    3717             : // Given a value or object, insert a dynamic check that this is a SIMD object of
    3718             : // the required SimdType, and unbox it into the corresponding SIMD MIRType.
    3719             : //
    3720             : // This represents the standard type checking that all the SIMD operations
    3721             : // perform on their arguments.
    3722             : MDefinition*
    3723           0 : IonBuilder::unboxSimd(MDefinition* ins, SimdType type)
    3724             : {
    3725             :     // Trivial optimization: If ins is a MSimdBox of the same SIMD type, there
    3726             :     // is no way the unboxing could fail, and we can skip it altogether.
    3727             :     // This is the same thing MSimdUnbox::foldsTo() does, but we can save the
    3728             :     // memory allocation here.
    3729           0 :     if (ins->isSimdBox()) {
    3730           0 :         MSimdBox* box = ins->toSimdBox();
    3731           0 :         if (box->simdType() == type) {
    3732           0 :             MDefinition* value = box->input();
    3733           0 :             MOZ_ASSERT(value->type() == SimdTypeToMIRType(type));
    3734           0 :             return value;
    3735             :         }
    3736             :     }
    3737             : 
    3738           0 :     MSimdUnbox* unbox = MSimdUnbox::New(alloc(), ins, type);
    3739           0 :     current->add(unbox);
    3740           0 :     return unbox;
    3741             : }
    3742             : 
    3743             : IonBuilder::InliningResult
    3744           0 : IonBuilder::boxSimd(CallInfo& callInfo, MDefinition* ins, InlineTypedObject* templateObj)
    3745             : {
    3746           0 :     SimdType simdType = templateObj->typeDescr().as<SimdTypeDescr>().type();
    3747           0 :     MSimdBox* obj = MSimdBox::New(alloc(), constraints(), ins, templateObj, simdType,
    3748           0 :                                   templateObj->group()->initialHeap(constraints()));
    3749             : 
    3750             :     // In some cases, ins has already been added to current.
    3751           0 :     if (!ins->block() && ins->isInstruction())
    3752           0 :         current->add(ins->toInstruction());
    3753           0 :     current->add(obj);
    3754           0 :     current->push(obj);
    3755             : 
    3756           0 :     callInfo.setImplicitlyUsedUnchecked();
    3757           0 :     return InliningStatus_Inlined;
    3758             : }
    3759             : 
    3760             : IonBuilder::InliningResult
    3761           0 : IonBuilder::inlineSimdBinaryArith(CallInfo& callInfo, JSNative native,
    3762             :                                   MSimdBinaryArith::Operation op, SimdType type)
    3763             : {
    3764           0 :     InlineTypedObject* templateObj = nullptr;
    3765           0 :     if (!canInlineSimd(callInfo, native, 2, &templateObj))
    3766           0 :         return InliningStatus_NotInlined;
    3767             : 
    3768           0 :     MDefinition* lhs = unboxSimd(callInfo.getArg(0), type);
    3769           0 :     MDefinition* rhs = unboxSimd(callInfo.getArg(1), type);
    3770             : 
    3771           0 :     auto* ins = MSimdBinaryArith::AddLegalized(alloc(), current, lhs, rhs, op);
    3772           0 :     return boxSimd(callInfo, ins, templateObj);
    3773             : }
    3774             : 
    3775             : IonBuilder::InliningResult
    3776           0 : IonBuilder::inlineSimdBinaryBitwise(CallInfo& callInfo, JSNative native,
    3777             :                                     MSimdBinaryBitwise::Operation op, SimdType type)
    3778             : {
    3779           0 :     InlineTypedObject* templateObj = nullptr;
    3780           0 :     if (!canInlineSimd(callInfo, native, 2, &templateObj))
    3781           0 :         return InliningStatus_NotInlined;
    3782             : 
    3783           0 :     MDefinition* lhs = unboxSimd(callInfo.getArg(0), type);
    3784           0 :     MDefinition* rhs = unboxSimd(callInfo.getArg(1), type);
    3785             : 
    3786           0 :     auto* ins = MSimdBinaryBitwise::New(alloc(), lhs, rhs, op);
    3787           0 :     return boxSimd(callInfo, ins, templateObj);
    3788             : }
    3789             : 
    3790             : // Inline a binary SIMD operation where both arguments are SIMD types.
    3791             : IonBuilder::InliningResult
    3792           0 : IonBuilder::inlineSimdBinarySaturating(CallInfo& callInfo, JSNative native,
    3793             :                                        MSimdBinarySaturating::Operation op, SimdType type)
    3794             : {
    3795           0 :     InlineTypedObject* templateObj = nullptr;
    3796           0 :     if (!canInlineSimd(callInfo, native, 2, &templateObj))
    3797           0 :         return InliningStatus_NotInlined;
    3798             : 
    3799           0 :     MDefinition* lhs = unboxSimd(callInfo.getArg(0), type);
    3800           0 :     MDefinition* rhs = unboxSimd(callInfo.getArg(1), type);
    3801             : 
    3802             :     MSimdBinarySaturating* ins =
    3803           0 :       MSimdBinarySaturating::New(alloc(), lhs, rhs, op, GetSimdSign(type));
    3804           0 :     return boxSimd(callInfo, ins, templateObj);
    3805             : }
    3806             : 
    3807             : // Inline a SIMD shiftByScalar operation.
    3808             : IonBuilder::InliningResult
    3809           0 : IonBuilder::inlineSimdShift(CallInfo& callInfo, JSNative native, MSimdShift::Operation op,
    3810             :                             SimdType type)
    3811             : {
    3812           0 :     InlineTypedObject* templateObj = nullptr;
    3813           0 :     if (!canInlineSimd(callInfo, native, 2, &templateObj))
    3814           0 :         return InliningStatus_NotInlined;
    3815             : 
    3816           0 :     MDefinition* vec = unboxSimd(callInfo.getArg(0), type);
    3817             : 
    3818           0 :     MInstruction* ins = MSimdShift::AddLegalized(alloc(), current, vec, callInfo.getArg(1), op);
    3819           0 :     return boxSimd(callInfo, ins, templateObj);
    3820             : }
    3821             : 
    3822             : IonBuilder::InliningResult
    3823           0 : IonBuilder::inlineSimdComp(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op,
    3824             :                            SimdType type)
    3825             : {
    3826           0 :     InlineTypedObject* templateObj = nullptr;
    3827           0 :     if (!canInlineSimd(callInfo, native, 2, &templateObj))
    3828           0 :         return InliningStatus_NotInlined;
    3829             : 
    3830           0 :     MDefinition* lhs = unboxSimd(callInfo.getArg(0), type);
    3831           0 :     MDefinition* rhs = unboxSimd(callInfo.getArg(1), type);
    3832             :     MInstruction* ins =
    3833           0 :       MSimdBinaryComp::AddLegalized(alloc(), current, lhs, rhs, op, GetSimdSign(type));
    3834           0 :     return boxSimd(callInfo, ins, templateObj);
    3835             : }
    3836             : 
    3837             : IonBuilder::InliningResult
    3838           0 : IonBuilder::inlineSimdUnary(CallInfo& callInfo, JSNative native, MSimdUnaryArith::Operation op,
    3839             :                             SimdType type)
    3840             : {
    3841           0 :     InlineTypedObject* templateObj = nullptr;
    3842           0 :     if (!canInlineSimd(callInfo, native, 1, &templateObj))
    3843           0 :         return InliningStatus_NotInlined;
    3844             : 
    3845           0 :     MDefinition* arg = unboxSimd(callInfo.getArg(0), type);
    3846             : 
    3847           0 :     MSimdUnaryArith* ins = MSimdUnaryArith::New(alloc(), arg, op);
    3848           0 :     return boxSimd(callInfo, ins, templateObj);
    3849             : }
    3850             : 
    3851             : IonBuilder::InliningResult
    3852           0 : IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdType type)
    3853             : {
    3854           0 :     InlineTypedObject* templateObj = nullptr;
    3855           0 :     if (!canInlineSimd(callInfo, native, 1, &templateObj))
    3856           0 :         return InliningStatus_NotInlined;
    3857             : 
    3858           0 :     MIRType mirType = SimdTypeToMIRType(type);
    3859           0 :     MDefinition* arg = callInfo.getArg(0);
    3860             : 
    3861             :     // Convert to 0 / -1 before splatting a boolean lane.
    3862           0 :     if (SimdTypeToLaneType(mirType) == MIRType::Boolean)
    3863           0 :         arg = convertToBooleanSimdLane(arg);
    3864             : 
    3865           0 :     MSimdSplat* ins = MSimdSplat::New(alloc(), arg, mirType);
    3866           0 :     return boxSimd(callInfo, ins, templateObj);
    3867             : }
    3868             : 
    3869             : IonBuilder::InliningResult
    3870           0 : IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdType type)
    3871             : {
    3872             :     // extractLane() returns a scalar, so don't use canInlineSimd() which looks
    3873             :     // for a template object.
    3874           0 :     if (callInfo.argc() != 2 || callInfo.constructing()) {
    3875           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    3876           0 :         return InliningStatus_NotInlined;
    3877             :     }
    3878             : 
    3879             :     // Lane index.
    3880           0 :     MDefinition* arg = callInfo.getArg(1);
    3881           0 :     if (!arg->isConstant() || arg->type() != MIRType::Int32)
    3882           0 :         return InliningStatus_NotInlined;
    3883           0 :     unsigned lane = arg->toConstant()->toInt32();
    3884           0 :     if (lane >= GetSimdLanes(type))
    3885           0 :         return InliningStatus_NotInlined;
    3886             : 
    3887             :     // Original vector.
    3888           0 :     MDefinition* orig = unboxSimd(callInfo.getArg(0), type);
    3889           0 :     MIRType vecType = orig->type();
    3890           0 :     MIRType laneType = SimdTypeToLaneType(vecType);
    3891           0 :     SimdSign sign = GetSimdSign(type);
    3892             : 
    3893             :     // An Uint32 lane can't be represented in MIRType::Int32. Get it as a double.
    3894           0 :     if (type == SimdType::Uint32x4)
    3895           0 :         laneType = MIRType::Double;
    3896             : 
    3897             :     MSimdExtractElement* ins =
    3898           0 :       MSimdExtractElement::New(alloc(), orig, laneType, lane, sign);
    3899           0 :     current->add(ins);
    3900           0 :     current->push(ins);
    3901           0 :     callInfo.setImplicitlyUsedUnchecked();
    3902           0 :     return InliningStatus_Inlined;
    3903             : }
    3904             : 
    3905             : IonBuilder::InliningResult
    3906           0 : IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType type)
    3907             : {
    3908           0 :     InlineTypedObject* templateObj = nullptr;
    3909           0 :     if (!canInlineSimd(callInfo, native, 3, &templateObj))
    3910           0 :         return InliningStatus_NotInlined;
    3911             : 
    3912             :     // Lane index.
    3913           0 :     MDefinition* arg = callInfo.getArg(1);
    3914           0 :     if (!arg->isConstant() || arg->type() != MIRType::Int32)
    3915           0 :         return InliningStatus_NotInlined;
    3916             : 
    3917           0 :     unsigned lane = arg->toConstant()->toInt32();
    3918           0 :     if (lane >= GetSimdLanes(type))
    3919           0 :         return InliningStatus_NotInlined;
    3920             : 
    3921             :     // Original vector.
    3922           0 :     MDefinition* orig = unboxSimd(callInfo.getArg(0), type);
    3923           0 :     MIRType vecType = orig->type();
    3924             : 
    3925             :     // Convert to 0 / -1 before inserting a boolean lane.
    3926           0 :     MDefinition* value = callInfo.getArg(2);
    3927           0 :     if (SimdTypeToLaneType(vecType) == MIRType::Boolean)
    3928           0 :         value = convertToBooleanSimdLane(value);
    3929             : 
    3930           0 :     MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), orig, value, lane);
    3931           0 :     return boxSimd(callInfo, ins, templateObj);
    3932             : }
    3933             : 
    3934             : // Inline a SIMD conversion or bitcast. When isCast==false, one of the types
    3935             : // must be floating point and the other integer. In this case, sign indicates if
    3936             : // the integer lanes should be treated as signed or unsigned integers.
    3937             : IonBuilder::InliningResult
    3938           0 : IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast, SimdType fromType,
    3939             :                               SimdType toType)
    3940             : {
    3941           0 :     InlineTypedObject* templateObj = nullptr;
    3942           0 :     if (!canInlineSimd(callInfo, native, 1, &templateObj))
    3943           0 :         return InliningStatus_NotInlined;
    3944             : 
    3945           0 :     MDefinition* arg = unboxSimd(callInfo.getArg(0), fromType);
    3946           0 :     MIRType mirType = SimdTypeToMIRType(toType);
    3947             : 
    3948             :     MInstruction* ins;
    3949           0 :     if (isCast) {
    3950             :         // Signed/Unsigned doesn't matter for bitcasts.
    3951           0 :         ins = MSimdReinterpretCast::New(alloc(), arg, mirType);
    3952             :     } else {
    3953             :         // Exactly one of fromType, toType must be an integer type.
    3954           0 :         SimdSign sign = GetSimdSign(fromType);
    3955           0 :         if (sign == SimdSign::NotApplicable)
    3956           0 :             sign = GetSimdSign(toType);
    3957             : 
    3958             :         // Possibly expand into multiple instructions.
    3959           0 :         ins = MSimdConvert::AddLegalized(alloc(), current, arg, mirType, sign);
    3960             :     }
    3961             : 
    3962           0 :     return boxSimd(callInfo, ins, templateObj);
    3963             : }
    3964             : 
    3965             : IonBuilder::InliningResult
    3966           0 : IonBuilder::inlineSimdSelect(CallInfo& callInfo, JSNative native, SimdType type)
    3967             : {
    3968           0 :     InlineTypedObject* templateObj = nullptr;
    3969           0 :     if (!canInlineSimd(callInfo, native, 3, &templateObj))
    3970           0 :         return InliningStatus_NotInlined;
    3971             : 
    3972           0 :     MDefinition* mask = unboxSimd(callInfo.getArg(0), GetBooleanSimdType(type));
    3973           0 :     MDefinition* tval = unboxSimd(callInfo.getArg(1), type);
    3974           0 :     MDefinition* fval = unboxSimd(callInfo.getArg(2), type);
    3975             : 
    3976           0 :     MSimdSelect* ins = MSimdSelect::New(alloc(), mask, tval, fval);
    3977           0 :     return boxSimd(callInfo, ins, templateObj);
    3978             : }
    3979             : 
    3980             : IonBuilder::InliningResult
    3981           0 : IonBuilder::inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdType type,
    3982             :                               unsigned numVectors)
    3983             : {
    3984           0 :     unsigned numLanes = GetSimdLanes(type);
    3985           0 :     InlineTypedObject* templateObj = nullptr;
    3986           0 :     if (!canInlineSimd(callInfo, native, numVectors + numLanes, &templateObj))
    3987           0 :         return InliningStatus_NotInlined;
    3988             : 
    3989           0 :     MIRType mirType = SimdTypeToMIRType(type);
    3990             : 
    3991           0 :     MSimdGeneralShuffle* ins = MSimdGeneralShuffle::New(alloc(), numVectors, numLanes, mirType);
    3992             : 
    3993           0 :     if (!ins->init(alloc()))
    3994           0 :         return abort(AbortReason::Alloc);
    3995             : 
    3996           0 :     for (unsigned i = 0; i < numVectors; i++)
    3997           0 :         ins->setVector(i, unboxSimd(callInfo.getArg(i), type));
    3998           0 :     for (size_t i = 0; i < numLanes; i++)
    3999           0 :         ins->setLane(i, callInfo.getArg(numVectors + i));
    4000             : 
    4001           0 :     return boxSimd(callInfo, ins, templateObj);
    4002             : }
    4003             : 
    4004             : IonBuilder::InliningResult
    4005           0 : IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native,
    4006             :                                  SimdType type)
    4007             : {
    4008             :     // anyTrue() / allTrue() return a scalar, so don't use canInlineSimd() which looks
    4009             :     // for a template object.
    4010           0 :     if (callInfo.argc() != 1 || callInfo.constructing()) {
    4011           0 :         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
    4012           0 :         return InliningStatus_NotInlined;
    4013             :     }
    4014             : 
    4015           0 :     MDefinition* arg = unboxSimd(callInfo.getArg(0), type);
    4016             : 
    4017             :     MUnaryInstruction* ins;
    4018           0 :     if (IsAllTrue)
    4019           0 :         ins = MSimdAllTrue::New(alloc(), arg, MIRType::Boolean);
    4020             :     else
    4021           0 :         ins = MSimdAnyTrue::New(alloc(), arg, MIRType::Boolean);
    4022             : 
    4023           0 :     current->add(ins);
    4024           0 :     current->push(ins);
    4025           0 :     callInfo.setImplicitlyUsedUnchecked();
    4026           0 :     return InliningStatus_Inlined;
    4027             : }
    4028             : 
    4029             : // Get the typed array element type corresponding to the lanes in a SIMD vector type.
    4030             : // This only applies to SIMD types that can be loaded and stored to a typed array.
    4031             : static Scalar::Type
    4032           0 : SimdTypeToArrayElementType(SimdType type)
    4033             : {
    4034           0 :     switch (type) {
    4035           0 :       case SimdType::Float32x4: return Scalar::Float32x4;
    4036             :       case SimdType::Int8x16:
    4037           0 :       case SimdType::Uint8x16:  return Scalar::Int8x16;
    4038             :       case SimdType::Int16x8:
    4039           0 :       case SimdType::Uint16x8:  return Scalar::Int16x8;
    4040             :       case SimdType::Int32x4:
    4041           0 :       case SimdType::Uint32x4:  return Scalar::Int32x4;
    4042           0 :       default:                MOZ_CRASH("unexpected simd type");
    4043             :     }
    4044             : }
    4045             : 
    4046             : bool
    4047           0 : IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
    4048             :                                     MDefinition** index, Scalar::Type* arrayType)
    4049             : {
    4050           0 :     MDefinition* array = callInfo.getArg(0);
    4051           0 :     *index = callInfo.getArg(1);
    4052             : 
    4053           0 :     if (!ElementAccessIsTypedArray(constraints(), array, *index, arrayType))
    4054           0 :         return false;
    4055             : 
    4056           0 :     MInstruction* indexAsInt32 = MToInt32::New(alloc(), *index);
    4057           0 :     current->add(indexAsInt32);
    4058           0 :     *index = indexAsInt32;
    4059             : 
    4060           0 :     MDefinition* indexForBoundsCheck = *index;
    4061             : 
    4062             :     // Artificially make sure the index is in bounds by adding the difference
    4063             :     // number of slots needed (e.g. reading from Float32Array we need to make
    4064             :     // sure to be in bounds for 4 slots, so add 3, etc.).
    4065           0 :     MOZ_ASSERT(Scalar::byteSize(simdType) % Scalar::byteSize(*arrayType) == 0);
    4066           0 :     int32_t suppSlotsNeeded = Scalar::byteSize(simdType) / Scalar::byteSize(*arrayType) - 1;
    4067           0 :     if (suppSlotsNeeded) {
    4068           0 :         MConstant* suppSlots = constant(Int32Value(suppSlotsNeeded));
    4069           0 :         MAdd* addedIndex = MAdd::New(alloc(), *index, suppSlots);
    4070             :         // We're fine even with the add overflows, as long as the generated code
    4071             :         // for the bounds check uses an unsigned comparison.
    4072           0 :         addedIndex->setInt32Specialization();
    4073           0 :         current->add(addedIndex);
    4074           0 :         indexForBoundsCheck = addedIndex;
    4075             :     }
    4076             : 
    4077             :     MInstruction* length;
    4078           0 :     addTypedArrayLengthAndData(array, SkipBoundsCheck, index, &length, elements);
    4079             : 
    4080             :     // It can be that the index is out of bounds, while the added index for the
    4081             :     // bounds check is in bounds, so we actually need two bounds checks here.
    4082           0 :     MInstruction* positiveCheck = MBoundsCheck::New(alloc(), *index, length);
    4083           0 :     current->add(positiveCheck);
    4084             : 
    4085           0 :     MInstruction* fullCheck = MBoundsCheck::New(alloc(), indexForBoundsCheck, length);
    4086           0 :     current->add(fullCheck);
    4087           0 :     return true;
    4088             : }
    4089             : 
    4090             : IonBuilder::InliningResult
    4091           0 : IonBuilder::inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type, unsigned numElems)
    4092             : {
    4093           0 :     InlineTypedObject* templateObj = nullptr;
    4094           0 :     if (!canInlineSimd(callInfo, native, 2, &templateObj))
    4095           0 :         return InliningStatus_NotInlined;
    4096             : 
    4097           0 :     Scalar::Type elemType = SimdTypeToArrayElementType(type);
    4098             : 
    4099           0 :     MDefinition* index = nullptr;
    4100           0 :     MInstruction* elements = nullptr;
    4101             :     Scalar::Type arrayType;
    4102           0 :     if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType))
    4103           0 :         return InliningStatus_NotInlined;
    4104             : 
    4105           0 :     MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType);
    4106           0 :     load->setResultType(SimdTypeToMIRType(type));
    4107           0 :     load->setSimdRead(elemType, numElems);
    4108             : 
    4109           0 :     return boxSimd(callInfo, load, templateObj);
    4110             : }
    4111             : 
    4112             : IonBuilder::InliningResult
    4113           0 : IonBuilder::inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type, unsigned numElems)
    4114             : {
    4115           0 :     InlineTypedObject* templateObj = nullptr;
    4116           0 :     if (!canInlineSimd(callInfo, native, 3, &templateObj))
    4117           0 :         return InliningStatus_NotInlined;
    4118             : 
    4119           0 :     Scalar::Type elemType = SimdTypeToArrayElementType(type);
    4120             : 
    4121           0 :     MDefinition* index = nullptr;
    4122           0 :     MInstruction* elements = nullptr;
    4123             :     Scalar::Type arrayType;
    4124           0 :     if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType))
    4125           0 :         return InliningStatus_NotInlined;
    4126             : 
    4127           0 :     MDefinition* valueToWrite = unboxSimd(callInfo.getArg(2), type);
    4128           0 :     MStoreUnboxedScalar* store = MStoreUnboxedScalar::New(alloc(), elements, index,
    4129             :                                                           valueToWrite, arrayType,
    4130           0 :                                                           MStoreUnboxedScalar::TruncateInput);
    4131           0 :     store->setSimdWrite(elemType, numElems);
    4132             : 
    4133           0 :     current->add(store);
    4134             :     // Produce the original boxed value as our return value.
    4135             :     // This is unlikely to be used, so don't bother reboxing valueToWrite.
    4136           0 :     current->push(callInfo.getArg(2));
    4137             : 
    4138           0 :     callInfo.setImplicitlyUsedUnchecked();
    4139             : 
    4140           0 :     MOZ_TRY(resumeAfter(store));
    4141           0 :     return InliningStatus_Inlined;
    4142             : }
    4143             : 
    4144             : // Note that SIMD.cpp provides its own JSJitInfo objects for SIMD.foo.* functions.
    4145             : // The Simd* objects defined here represent SIMD.foo() constructor calls.
    4146             : // They are encoded with .nativeOp = 0. That is the sub-opcode within the SIMD type.
    4147             : static_assert(uint16_t(SimdOperation::Constructor) == 0, "Constructor opcode must be 0");
    4148             : 
    4149             : #define ADD_NATIVE(native) const JSJitInfo JitInfo_##native { \
    4150             :     { nullptr }, { uint16_t(InlinableNative::native) }, { 0 }, JSJitInfo::InlinableNative };
    4151             :     INLINABLE_NATIVE_LIST(ADD_NATIVE)
    4152             : #undef ADD_NATIVE
    4153             : 
    4154             : } // namespace jit
    4155             : } // namespace js

Generated by: LCOV version 1.13