js/src/jit/MCallOptimize.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #include "jsmath.h"
     9 #include "builtin/TestingFunctions.h"
    10 #include "builtin/TypedObject.h"
    11 #include "jit/BaselineInspector.h"
    12 #include "jit/IonBuilder.h"
    13 #include "jit/Lowering.h"
    14 #include "jit/MIR.h"
    15 #include "jit/MIRGraph.h"
    16 #include "vm/ArgumentsObject.h"
    18 #include "jsscriptinlines.h"
    20 #include "vm/StringObject-inl.h"
    22 namespace js {
    23 namespace jit {
    25 IonBuilder::InliningStatus
    26 IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
    27 {
    28     JS_ASSERT(target->isNative());
    29     JSNative native = target->native();
    31     if (!optimizationInfo().inlineNative())
    32         return InliningStatus_NotInlined;
    34     // Array natives.
    35     if (native == js_Array)
    36         return inlineArray(callInfo);
    37     if (native == js::array_pop)
    38         return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
    39     if (native == js::array_shift)
    40         return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
    41     if (native == js::array_push)
    42         return inlineArrayPush(callInfo);
    43     if (native == js::array_concat)
    44         return inlineArrayConcat(callInfo);
    45     if (native == js::array_splice)
    46         return inlineArraySplice(callInfo);
    48     // Math natives.
    49     if (native == js_math_abs)
    50         return inlineMathAbs(callInfo);
    51     if (native == js::math_floor)
    52         return inlineMathFloor(callInfo);
    53     if (native == js::math_ceil)
    54         return inlineMathCeil(callInfo);
    55     if (native == js::math_round)
    56         return inlineMathRound(callInfo);
    57     if (native == js_math_sqrt)
    58         return inlineMathSqrt(callInfo);
    59     if (native == math_atan2)
    60         return inlineMathAtan2(callInfo);
    61     if (native == js::math_hypot)
    62         return inlineMathHypot(callInfo);
    63     if (native == js_math_max)
    64         return inlineMathMinMax(callInfo, true /* max */);
    65     if (native == js_math_min)
    66         return inlineMathMinMax(callInfo, false /* max */);
    67     if (native == js_math_pow)
    68         return inlineMathPow(callInfo);
    69     if (native == js_math_random)
    70         return inlineMathRandom(callInfo);
    71     if (native == js::math_imul)
    72         return inlineMathImul(callInfo);
    73     if (native == js::math_fround)
    74         return inlineMathFRound(callInfo);
    75     if (native == js::math_sin)
    76         return inlineMathFunction(callInfo, MMathFunction::Sin);
    77     if (native == js::math_cos)
    78         return inlineMathFunction(callInfo, MMathFunction::Cos);
    79     if (native == js::math_exp)
    80         return inlineMathFunction(callInfo, MMathFunction::Exp);
    81     if (native == js::math_tan)
    82         return inlineMathFunction(callInfo, MMathFunction::Tan);
    83     if (native == js::math_log)
    84         return inlineMathFunction(callInfo, MMathFunction::Log);
    85     if (native == js::math_atan)
    86         return inlineMathFunction(callInfo, MMathFunction::ATan);
    87     if (native == js::math_asin)
    88         return inlineMathFunction(callInfo, MMathFunction::ASin);
    89     if (native == js::math_acos)
    90         return inlineMathFunction(callInfo, MMathFunction::ACos);
    91     if (native == js::math_log10)
    92         return inlineMathFunction(callInfo, MMathFunction::Log10);
    93     if (native == js::math_log2)
    94         return inlineMathFunction(callInfo, MMathFunction::Log2);
    95     if (native == js::math_log1p)
    96         return inlineMathFunction(callInfo, MMathFunction::Log1P);
    97     if (native == js::math_expm1)
    98         return inlineMathFunction(callInfo, MMathFunction::ExpM1);
    99     if (native == js::math_cosh)
   100         return inlineMathFunction(callInfo, MMathFunction::CosH);
   101     if (native == js::math_sin)
   102         return inlineMathFunction(callInfo, MMathFunction::SinH);
   103     if (native == js::math_tan)
   104         return inlineMathFunction(callInfo, MMathFunction::TanH);
   105     if (native == js::math_acosh)
   106         return inlineMathFunction(callInfo, MMathFunction::ACosH);
   107     if (native == js::math_asin)
   108         return inlineMathFunction(callInfo, MMathFunction::ASinH);
   109     if (native == js::math_atan)
   110         return inlineMathFunction(callInfo, MMathFunction::ATanH);
   111     if (native == js::math_sign)
   112         return inlineMathFunction(callInfo, MMathFunction::Sign);
   113     if (native == js::math_trunc)
   114         return inlineMathFunction(callInfo, MMathFunction::Trunc);
   115     if (native == js::math_cbrt)
   116         return inlineMathFunction(callInfo, MMathFunction::Cbrt);
   118     // String natives.
   119     if (native == js_String)
   120         return inlineStringObject(callInfo);
   121     if (native == js::str_split)
   122         return inlineStringSplit(callInfo);
   123     if (native == js_str_charCodeAt)
   124         return inlineStrCharCodeAt(callInfo);
   125     if (native == js::str_fromCharCode)
   126         return inlineStrFromCharCode(callInfo);
   127     if (native == js_str_charAt)
   128         return inlineStrCharAt(callInfo);
   129     if (native == str_replace)
   130         return inlineStrReplace(callInfo);
   132     // RegExp natives.
   133     if (native == regexp_exec && CallResultEscapes(pc))
   134         return inlineRegExpExec(callInfo);
   135     if (native == regexp_exec && !CallResultEscapes(pc))
   136         return inlineRegExpTest(callInfo);
   137     if (native == regexp_test)
   138         return inlineRegExpTest(callInfo);
   140     // Array intrinsics.
   141     if (native == intrinsic_UnsafePutElements)
   142         return inlineUnsafePutElements(callInfo);
   143     if (native == intrinsic_NewDenseArray)
   144         return inlineNewDenseArray(callInfo);
   146     // Slot intrinsics.
   147     if (native == intrinsic_UnsafeSetReservedSlot)
   148         return inlineUnsafeSetReservedSlot(callInfo);
   149     if (native == intrinsic_UnsafeGetReservedSlot)
   150         return inlineUnsafeGetReservedSlot(callInfo);
   152     // Parallel intrinsics.
   153     if (native == intrinsic_ShouldForceSequential ||
   154         native == intrinsic_InParallelSection)
   155         return inlineForceSequentialOrInParallelSection(callInfo);
   156     if (native == intrinsic_ForkJoinGetSlice)
   157         return inlineForkJoinGetSlice(callInfo);
   159     // Utility intrinsics.
   160     if (native == intrinsic_IsCallable)
   161         return inlineIsCallable(callInfo);
   162     if (native == intrinsic_HaveSameClass)
   163         return inlineHaveSameClass(callInfo);
   164     if (native == intrinsic_ToObject)
   165         return inlineToObject(callInfo);
   167     // TypedObject intrinsics.
   168     if (native == intrinsic_ObjectIsTypedObject)
   169         return inlineHasClasses(callInfo,
   170                                 &TransparentTypedObject::class_, &OpaqueTypedObject::class_);
   171     if (native == intrinsic_ObjectIsTransparentTypedObject)
   172         return inlineHasClass(callInfo, &TransparentTypedObject::class_);
   173     if (native == intrinsic_ObjectIsOpaqueTypedObject)
   174         return inlineHasClass(callInfo, &OpaqueTypedObject::class_);
   175     if (native == intrinsic_ObjectIsTypeDescr)
   176         return inlineObjectIsTypeDescr(callInfo);
   177     if (native == intrinsic_TypeDescrIsSimpleType)
   178         return inlineHasClasses(callInfo,
   179                                 &ScalarTypeDescr::class_, &ReferenceTypeDescr::class_);
   180     if (native == intrinsic_TypeDescrIsArrayType)
   181         return inlineHasClasses(callInfo,
   182                                 &SizedArrayTypeDescr::class_, &UnsizedArrayTypeDescr::class_);
   183     if (native == intrinsic_TypeDescrIsSizedArrayType)
   184         return inlineHasClass(callInfo, &SizedArrayTypeDescr::class_);
   185     if (native == intrinsic_TypeDescrIsUnsizedArrayType)
   186         return inlineHasClass(callInfo, &UnsizedArrayTypeDescr::class_);
   187     if (native == intrinsic_SetTypedObjectOffset)
   188         return inlineSetTypedObjectOffset(callInfo);
   190     // Testing Functions
   191     if (native == testingFunc_inParallelSection)
   192         return inlineForceSequentialOrInParallelSection(callInfo);
   193     if (native == testingFunc_bailout)
   194         return inlineBailout(callInfo);
   195     if (native == testingFunc_assertFloat32)
   196         return inlineAssertFloat32(callInfo);
   198     // Bound function
   199     if (native == js::CallOrConstructBoundFunction)
   200         return inlineBoundFunction(callInfo, target);
   202     return InliningStatus_NotInlined;
   203 }
   205 types::TemporaryTypeSet *
   206 IonBuilder::getInlineReturnTypeSet()
   207 {
   208     return bytecodeTypes(pc);
   209 }
   211 MIRType
   212 IonBuilder::getInlineReturnType()
   213 {
   214     types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
   215     return returnTypes->getKnownMIRType();
   216 }
   218 IonBuilder::InliningStatus
   219 IonBuilder::inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function)
   220 {
   221     if (callInfo.constructing())
   222         return InliningStatus_NotInlined;
   224     if (callInfo.argc() != 1)
   225         return InliningStatus_NotInlined;
   227     if (getInlineReturnType() != MIRType_Double)
   228         return InliningStatus_NotInlined;
   229     if (!IsNumberType(callInfo.getArg(0)->type()))
   230         return InliningStatus_NotInlined;
   232     const MathCache *cache = compartment->runtime()->maybeGetMathCache();
   234     callInfo.fun()->setImplicitlyUsedUnchecked();
   235     callInfo.thisArg()->setImplicitlyUsedUnchecked();
   237     MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), function, cache);
   238     current->add(ins);
   239     current->push(ins);
   240     return InliningStatus_Inlined;
   241 }
   243 IonBuilder::InliningStatus
   244 IonBuilder::inlineArray(CallInfo &callInfo)
   245 {
   246     uint32_t initLength = 0;
   247     MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating;
   249     JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
   250     if (!templateObject)
   251         return InliningStatus_NotInlined;
   252     JS_ASSERT(templateObject->is<ArrayObject>());
   254     // Multiple arguments imply array initialization, not just construction.
   255     if (callInfo.argc() >= 2) {
   256         initLength = callInfo.argc();
   257         allocating = MNewArray::NewArray_Allocating;
   259         types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject);
   260         if (!type->unknownProperties()) {
   261             types::HeapTypeSetKey elemTypes = type->property(JSID_VOID);
   263             for (uint32_t i = 0; i < initLength; i++) {
   264                 MDefinition *value = callInfo.getArg(i);
   265                 if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
   266                     elemTypes.freeze(constraints());
   267                     return InliningStatus_NotInlined;
   268                 }
   269             }
   270         }
   271     }
   273     // A single integer argument denotes initial length.
   274     if (callInfo.argc() == 1) {
   275         if (callInfo.getArg(0)->type() != MIRType_Int32)
   276             return InliningStatus_NotInlined;
   277         MDefinition *arg = callInfo.getArg(0);
   278         if (!arg->isConstant())
   279             return InliningStatus_NotInlined;
   281         // Negative lengths generate a RangeError, unhandled by the inline path.
   282         initLength = arg->toConstant()->value().toInt32();
   283         if (initLength >= JSObject::NELEMENTS_LIMIT)
   284             return InliningStatus_NotInlined;
   286         // Make sure initLength matches the template object's length. This is
   287         // not guaranteed to be the case, for instance if we're inlining the
   288         // MConstant may come from an outer script.
   289         if (initLength != templateObject->as<ArrayObject>().length())
   290             return InliningStatus_NotInlined;
   292         if (initLength <= ArrayObject::EagerAllocationMaxLength)
   293             allocating = MNewArray::NewArray_Allocating;
   294     }
   296     callInfo.setImplicitlyUsedUnchecked();
   298     types::TemporaryTypeSet::DoubleConversion conversion =
   299         getInlineReturnTypeSet()->convertDoubleElements(constraints());
   300     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
   301         templateObject->setShouldConvertDoubleElements();
   302     else
   303         templateObject->clearShouldConvertDoubleElements();
   305     MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateObject,
   306                                     templateObject->type()->initialHeap(constraints()),
   307                                     allocating);
   308     current->add(ins);
   309     current->push(ins);
   311     if (callInfo.argc() >= 2) {
   312         // Get the elements vector.
   313         MElements *elements = MElements::New(alloc(), ins);
   314         current->add(elements);
   316         // Store all values, no need to initialize the length after each as
   317         // jsop_initelem_array is doing because we do not expect to bailout
   318         // because the memory is supposed to be allocated by now.
   319         MConstant *id = nullptr;
   320         for (uint32_t i = 0; i < initLength; i++) {
   321             id = MConstant::New(alloc(), Int32Value(i));
   322             current->add(id);
   324             MDefinition *value = callInfo.getArg(i);
   325             if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) {
   326                 MInstruction *valueDouble = MToDouble::New(alloc(), value);
   327                 current->add(valueDouble);
   328                 value = valueDouble;
   329             }
   331             // There is normally no need for a post barrier on these writes
   332             // because the new array will be in the nursery. However, this
   333             // assumption is volated if we specifically requested pre-tenuring.
   334             if (ins->initialHeap() == gc::TenuredHeap)
   335                 current->add(MPostWriteBarrier::New(alloc(), ins, value));
   337             MStoreElement *store = MStoreElement::New(alloc(), elements, id, value,
   338                                                       /* needsHoleCheck = */ false);
   339             current->add(store);
   340         }
   342         // Update the length.
   343         MSetInitializedLength *length = MSetInitializedLength::New(alloc(), elements, id);
   344         current->add(length);
   346         if (!resumeAfter(length))
   347             return InliningStatus_Error;
   348     }
   350     return InliningStatus_Inlined;
   351 }
   353 IonBuilder::InliningStatus
   354 IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
   355 {
   356     if (callInfo.constructing())
   357         return InliningStatus_NotInlined;
   359     MIRType returnType = getInlineReturnType();
   360     if (returnType == MIRType_Undefined || returnType == MIRType_Null)
   361         return InliningStatus_NotInlined;
   362     if (callInfo.thisArg()->type() != MIRType_Object)
   363         return InliningStatus_NotInlined;
   365     // Pop and shift are only handled for dense arrays that have never been
   366     // used in an iterator: popping elements does not account for suppressing
   367     // deleted properties in active iterators.
   368     types::TypeObjectFlags unhandledFlags =
   369         types::OBJECT_FLAG_SPARSE_INDEXES |
   370         types::OBJECT_FLAG_LENGTH_OVERFLOW |
   371         types::OBJECT_FLAG_ITERATED;
   373     types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
   374     if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
   375         return InliningStatus_NotInlined;
   376     if (thisTypes->hasObjectFlags(constraints(), unhandledFlags))
   377         return InliningStatus_NotInlined;
   379     if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
   380         return InliningStatus_NotInlined;
   382     callInfo.setImplicitlyUsedUnchecked();
   384     types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
   385     bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED);
   386     bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
   388     bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
   389                                                 callInfo.thisArg(), nullptr, returnTypes);
   390     if (barrier)
   391         returnType = MIRType_Value;
   393     MArrayPopShift *ins = MArrayPopShift::New(alloc(), callInfo.thisArg(), mode,
   394                                               needsHoleCheck, maybeUndefined);
   395     current->add(ins);
   396     current->push(ins);
   397     ins->setResultType(returnType);
   399     if (!resumeAfter(ins))
   400         return InliningStatus_Error;
   402     if (!pushTypeBarrier(ins, returnTypes, barrier))
   403         return InliningStatus_Error;
   405     return InliningStatus_Inlined;
   406 }
   408 IonBuilder::InliningStatus
   409 IonBuilder::inlineArraySplice(CallInfo &callInfo)
   410 {
   411     if (callInfo.argc() != 2 || callInfo.constructing())
   412         return InliningStatus_NotInlined;
   414     // Ensure |this|, argument and result are objects.
   415     if (getInlineReturnType() != MIRType_Object)
   416         return InliningStatus_NotInlined;
   417     if (callInfo.thisArg()->type() != MIRType_Object)
   418         return InliningStatus_NotInlined;
   419     if (callInfo.getArg(0)->type() != MIRType_Int32)
   420         return InliningStatus_NotInlined;
   421     if (callInfo.getArg(1)->type() != MIRType_Int32)
   422         return InliningStatus_NotInlined;
   424     callInfo.setImplicitlyUsedUnchecked();
   426     // Specialize arr.splice(start, deleteCount) with unused return value and
   427     // avoid creating the result array in this case.
   428     if (!BytecodeIsPopped(pc))
   429         return InliningStatus_NotInlined;
   431     MArraySplice *ins = MArraySplice::New(alloc(),
   432                                           callInfo.thisArg(),
   433                                           callInfo.getArg(0),
   434                                           callInfo.getArg(1));
   436     current->add(ins);
   437     pushConstant(UndefinedValue());
   439     if (!resumeAfter(ins))
   440         return InliningStatus_Error;
   441     return InliningStatus_Inlined;
   442 }
   444 IonBuilder::InliningStatus
   445 IonBuilder::inlineArrayPush(CallInfo &callInfo)
   446 {
   447     if (callInfo.argc() != 1 || callInfo.constructing())
   448         return InliningStatus_NotInlined;
   450     MDefinition *obj = callInfo.thisArg();
   451     MDefinition *value = callInfo.getArg(0);
   452     if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
   453                                       &obj, nullptr, &value, /* canModify = */ false))
   454     {
   455         return InliningStatus_NotInlined;
   456     }
   457     JS_ASSERT(obj == callInfo.thisArg() && value == callInfo.getArg(0));
   459     if (getInlineReturnType() != MIRType_Int32)
   460         return InliningStatus_NotInlined;
   461     if (callInfo.thisArg()->type() != MIRType_Object)
   462         return InliningStatus_NotInlined;
   464     types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
   465     if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
   466         return InliningStatus_NotInlined;
   467     if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
   468                                   types::OBJECT_FLAG_LENGTH_OVERFLOW))
   469     {
   470         return InliningStatus_NotInlined;
   471     }
   473     if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
   474         return InliningStatus_NotInlined;
   476     types::TemporaryTypeSet::DoubleConversion conversion =
   477         thisTypes->convertDoubleElements(constraints());
   478     if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion)
   479         return InliningStatus_NotInlined;
   481     callInfo.setImplicitlyUsedUnchecked();
   482     value = callInfo.getArg(0);
   484     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles ||
   485         conversion == types::TemporaryTypeSet::MaybeConvertToDoubles)
   486     {
   487         MInstruction *valueDouble = MToDouble::New(alloc(), value);
   488         current->add(valueDouble);
   489         value = valueDouble;
   490     }
   492     if (NeedsPostBarrier(info(), value))
   493         current->add(MPostWriteBarrier::New(alloc(), callInfo.thisArg(), value));
   495     MArrayPush *ins = MArrayPush::New(alloc(), callInfo.thisArg(), value);
   496     current->add(ins);
   497     current->push(ins);
   499     if (!resumeAfter(ins))
   500         return InliningStatus_Error;
   501     return InliningStatus_Inlined;
   502 }
   504 IonBuilder::InliningStatus
   505 IonBuilder::inlineArrayConcat(CallInfo &callInfo)
   506 {
   507     if (callInfo.argc() != 1 || callInfo.constructing())
   508         return InliningStatus_NotInlined;
   510     // Ensure |this|, argument and result are objects.
   511     if (getInlineReturnType() != MIRType_Object)
   512         return InliningStatus_NotInlined;
   513     if (callInfo.thisArg()->type() != MIRType_Object)
   514         return InliningStatus_NotInlined;
   515     if (callInfo.getArg(0)->type() != MIRType_Object)
   516         return InliningStatus_NotInlined;
   518     // |this| and the argument must be dense arrays.
   519     types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
   520     types::TemporaryTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
   521     if (!thisTypes || !argTypes)
   522         return InliningStatus_NotInlined;
   524     if (thisTypes->getKnownClass() != &ArrayObject::class_)
   525         return InliningStatus_NotInlined;
   526     if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
   527                                   types::OBJECT_FLAG_LENGTH_OVERFLOW))
   528     {
   529         return InliningStatus_NotInlined;
   530     }
   532     if (argTypes->getKnownClass() != &ArrayObject::class_)
   533         return InliningStatus_NotInlined;
   534     if (argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
   535                                  types::OBJECT_FLAG_LENGTH_OVERFLOW))
   536     {
   537         return InliningStatus_NotInlined;
   538     }
   540     // Watch out for indexed properties on the prototype.
   541     if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
   542         return InliningStatus_NotInlined;
   544     // Require the 'this' types to have a specific type matching the current
   545     // global, so we can create the result object inline.
   546     if (thisTypes->getObjectCount() != 1)
   547         return InliningStatus_NotInlined;
   549     types::TypeObject *baseThisType = thisTypes->getTypeObject(0);
   550     if (!baseThisType)
   551         return InliningStatus_NotInlined;
   552     types::TypeObjectKey *thisType = types::TypeObjectKey::get(baseThisType);
   553     if (thisType->unknownProperties())
   554         return InliningStatus_NotInlined;
   556     // Don't inline if 'this' is packed and the argument may not be packed
   557     // (the result array will reuse the 'this' type).
   558     if (!thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED) &&
   559         argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED))
   560     {
   561         return InliningStatus_NotInlined;
   562     }
   564     // Constraints modeling this concat have not been generated by inference,
   565     // so check that type information already reflects possible side effects of
   566     // this call.
   567     types::HeapTypeSetKey thisElemTypes = thisType->property(JSID_VOID);
   569     types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet();
   570     if (!resTypes->hasType(types::Type::ObjectType(thisType)))
   571         return InliningStatus_NotInlined;
   573     for (unsigned i = 0; i < argTypes->getObjectCount(); i++) {
   574         types::TypeObjectKey *argType = argTypes->getObject(i);
   575         if (!argType)
   576             continue;
   578         if (argType->unknownProperties())
   579             return InliningStatus_NotInlined;
   581         types::HeapTypeSetKey elemTypes = argType->property(JSID_VOID);
   582         if (!elemTypes.knownSubset(constraints(), thisElemTypes))
   583             return InliningStatus_NotInlined;
   584     }
   586     // Inline the call.
   587     JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
   588     if (!templateObj || templateObj->type() != baseThisType)
   589         return InliningStatus_NotInlined;
   590     JS_ASSERT(templateObj->is<ArrayObject>());
   592     callInfo.setImplicitlyUsedUnchecked();
   594     MArrayConcat *ins = MArrayConcat::New(alloc(), constraints(), callInfo.thisArg(), callInfo.getArg(0),
   595                                           templateObj, templateObj->type()->initialHeap(constraints()));
   596     current->add(ins);
   597     current->push(ins);
   599     if (!resumeAfter(ins))
   600         return InliningStatus_Error;
   601     return InliningStatus_Inlined;
   602 }
   604 IonBuilder::InliningStatus
   605 IonBuilder::inlineMathAbs(CallInfo &callInfo)
   606 {
   607     if (callInfo.constructing())
   608         return InliningStatus_NotInlined;
   610     if (callInfo.argc() != 1)
   611         return InliningStatus_NotInlined;
   613     MIRType returnType = getInlineReturnType();
   614     MIRType argType = callInfo.getArg(0)->type();
   615     if (!IsNumberType(argType))
   616         return InliningStatus_NotInlined;
   618     // Either argType == returnType, or
   619     //        argType == Double or Float32, returnType == Int, or
   620     //        argType == Float32, returnType == Double
   621     if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType_Int32)
   622         && !(argType == MIRType_Float32 && returnType == MIRType_Double))
   623     {
   624         return InliningStatus_NotInlined;
   625     }
   627     callInfo.setImplicitlyUsedUnchecked();
   629     // If the arg is a Float32, we specialize the op as double, it will be specialized
   630     // as float32 if necessary later.
   631     MIRType absType = (argType == MIRType_Float32) ? MIRType_Double : argType;
   632     MInstruction *ins = MAbs::New(alloc(), callInfo.getArg(0), absType);
   633     current->add(ins);
   635     current->push(ins);
   636     return InliningStatus_Inlined;
   637 }
   639 IonBuilder::InliningStatus
   640 IonBuilder::inlineMathFloor(CallInfo &callInfo)
   641 {
   642     if (callInfo.constructing())
   643         return InliningStatus_NotInlined;
   645     if (callInfo.argc() != 1)
   646         return InliningStatus_NotInlined;
   648     MIRType argType = callInfo.getArg(0)->type();
   649     MIRType returnType = getInlineReturnType();
   651     // Math.floor(int(x)) == int(x)
   652     if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
   653         callInfo.setImplicitlyUsedUnchecked();
   654         current->push(callInfo.getArg(0));
   655         return InliningStatus_Inlined;
   656     }
   658     if (IsFloatingPointType(argType) && returnType == MIRType_Int32) {
   659         callInfo.setImplicitlyUsedUnchecked();
   660         MFloor *ins = MFloor::New(alloc(), callInfo.getArg(0));
   661         current->add(ins);
   662         current->push(ins);
   663         return InliningStatus_Inlined;
   664     }
   666     if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
   667         callInfo.setImplicitlyUsedUnchecked();
   668         MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor, nullptr);
   669         current->add(ins);
   670         current->push(ins);
   671         return InliningStatus_Inlined;
   672     }
   674     return InliningStatus_NotInlined;
   675 }
   677 IonBuilder::InliningStatus
   678 IonBuilder::inlineMathCeil(CallInfo &callInfo)
   679 {
   680     if (callInfo.constructing())
   681         return InliningStatus_NotInlined;
   683     if (callInfo.argc() != 1)
   684         return InliningStatus_NotInlined;
   686     MIRType argType = callInfo.getArg(0)->type();
   687     MIRType returnType = getInlineReturnType();
   689     // Math.ceil(int(x)) == int(x)
   690     if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
   691         callInfo.setImplicitlyUsedUnchecked();
   692         current->push(callInfo.getArg(0));
   693         return InliningStatus_Inlined;
   694     }
   696     if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
   697         callInfo.setImplicitlyUsedUnchecked();
   698         MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil, nullptr);
   699         current->add(ins);
   700         current->push(ins);
   701         return InliningStatus_Inlined;
   702     }
   704     return InliningStatus_NotInlined;
   705 }
   707 IonBuilder::InliningStatus
   708 IonBuilder::inlineMathRound(CallInfo &callInfo)
   709 {
   710     if (callInfo.constructing())
   711         return InliningStatus_NotInlined;
   713     if (callInfo.argc() != 1)
   714         return InliningStatus_NotInlined;
   716     MIRType returnType = getInlineReturnType();
   717     MIRType argType = callInfo.getArg(0)->type();
   719     // Math.round(int(x)) == int(x)
   720     if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
   721         callInfo.setImplicitlyUsedUnchecked();
   722         current->push(callInfo.getArg(0));
   723         return InliningStatus_Inlined;
   724     }
   726     if (IsFloatingPointType(argType) && returnType == MIRType_Int32) {
   727         callInfo.setImplicitlyUsedUnchecked();
   728         MRound *ins = MRound::New(alloc(), callInfo.getArg(0));
   729         current->add(ins);
   730         current->push(ins);
   731         return InliningStatus_Inlined;
   732     }
   734     if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
   735         callInfo.setImplicitlyUsedUnchecked();
   736         MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round, nullptr);
   737         current->add(ins);
   738         current->push(ins);
   739         return InliningStatus_Inlined;
   740     }
   742     return InliningStatus_NotInlined;
   743 }
   745 IonBuilder::InliningStatus
   746 IonBuilder::inlineMathSqrt(CallInfo &callInfo)
   747 {
   748     if (callInfo.constructing())
   749         return InliningStatus_NotInlined;
   751     if (callInfo.argc() != 1)
   752         return InliningStatus_NotInlined;
   754     MIRType argType = callInfo.getArg(0)->type();
   755     if (getInlineReturnType() != MIRType_Double)
   756         return InliningStatus_NotInlined;
   757     if (!IsNumberType(argType))
   758         return InliningStatus_NotInlined;
   760     callInfo.setImplicitlyUsedUnchecked();
   762     MSqrt *sqrt = MSqrt::New(alloc(), callInfo.getArg(0));
   763     current->add(sqrt);
   764     current->push(sqrt);
   765     return InliningStatus_Inlined;
   766 }
   768 IonBuilder::InliningStatus
   769 IonBuilder::inlineMathAtan2(CallInfo &callInfo)
   770 {
   771     if (callInfo.constructing())
   772         return InliningStatus_NotInlined;
   774     if (callInfo.argc() != 2)
   775         return InliningStatus_NotInlined;
   777     if (getInlineReturnType() != MIRType_Double)
   778         return InliningStatus_NotInlined;
   780     MIRType argType0 = callInfo.getArg(0)->type();
   781     MIRType argType1 = callInfo.getArg(1)->type();
   783     if (!IsNumberType(argType0) || !IsNumberType(argType1))
   784         return InliningStatus_NotInlined;
   786     callInfo.setImplicitlyUsedUnchecked();
   788     MAtan2 *atan2 = MAtan2::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
   789     current->add(atan2);
   790     current->push(atan2);
   791     return InliningStatus_Inlined;
   792 }
   794 IonBuilder::InliningStatus
   795 IonBuilder::inlineMathHypot(CallInfo &callInfo)
   796 {
   797     if (callInfo.constructing())
   798         return InliningStatus_NotInlined;
   800     if (callInfo.argc() != 2)
   801         return InliningStatus_NotInlined;
   803     if (getInlineReturnType() != MIRType_Double)
   804         return InliningStatus_NotInlined;
   806     MIRType argType0 = callInfo.getArg(0)->type();
   807     MIRType argType1 = callInfo.getArg(1)->type();
   809     if (!IsNumberType(argType0) || !IsNumberType(argType1))
   810         return InliningStatus_NotInlined;
   812     callInfo.setImplicitlyUsedUnchecked();
   814     MHypot *hypot = MHypot::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
   815     current->add(hypot);
   816     current->push(hypot);
   817     return InliningStatus_Inlined;
   818 }
   820 IonBuilder::InliningStatus
   821 IonBuilder::inlineMathPow(CallInfo &callInfo)
   822 {
   823     if (callInfo.constructing())
   824         return InliningStatus_NotInlined;
   826     if (callInfo.argc() != 2)
   827         return InliningStatus_NotInlined;
   829     // Typechecking.
   830     MIRType baseType = callInfo.getArg(0)->type();
   831     MIRType powerType = callInfo.getArg(1)->type();
   832     MIRType outputType = getInlineReturnType();
   834     if (outputType != MIRType_Int32 && outputType != MIRType_Double)
   835         return InliningStatus_NotInlined;
   836     if (!IsNumberType(baseType))
   837         return InliningStatus_NotInlined;
   838     if (!IsNumberType(powerType))
   839         return InliningStatus_NotInlined;
   841     callInfo.setImplicitlyUsedUnchecked();
   843     MDefinition *base = callInfo.getArg(0);
   844     MDefinition *power = callInfo.getArg(1);
   845     MDefinition *output = nullptr;
   847     // Optimize some constant powers.
   848     if (callInfo.getArg(1)->isConstant() &&
   849         callInfo.getArg(1)->toConstant()->value().isNumber())
   850     {
   851         double pow = callInfo.getArg(1)->toConstant()->value().toNumber();
   853         // Math.pow(x, 0.5) is a sqrt with edge-case detection.
   854         if (pow == 0.5) {
   855             MPowHalf *half = MPowHalf::New(alloc(), base);
   856             current->add(half);
   857             output = half;
   858         }
   860         // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
   861         if (pow == -0.5) {
   862             MPowHalf *half = MPowHalf::New(alloc(), base);
   863             current->add(half);
   864             MConstant *one = MConstant::New(alloc(), DoubleValue(1.0));
   865             current->add(one);
   866             MDiv *div = MDiv::New(alloc(), one, half, MIRType_Double);
   867             current->add(div);
   868             output = div;
   869         }
   871         // Math.pow(x, 1) == x.
   872         if (pow == 1.0)
   873             output = base;
   875         // Math.pow(x, 2) == x*x.
   876         if (pow == 2.0) {
   877             MMul *mul = MMul::New(alloc(), base, base, outputType);
   878             current->add(mul);
   879             output = mul;
   880         }
   882         // Math.pow(x, 3) == x*x*x.
   883         if (pow == 3.0) {
   884             MMul *mul1 = MMul::New(alloc(), base, base, outputType);
   885             current->add(mul1);
   886             MMul *mul2 = MMul::New(alloc(), base, mul1, outputType);
   887             current->add(mul2);
   888             output = mul2;
   889         }
   891         // Math.pow(x, 4) == y*y, where y = x*x.
   892         if (pow == 4.0) {
   893             MMul *y = MMul::New(alloc(), base, base, outputType);
   894             current->add(y);
   895             MMul *mul = MMul::New(alloc(), y, y, outputType);
   896             current->add(mul);
   897             output = mul;
   898         }
   899     }
   901     // Use MPow for other powers
   902     if (!output) {
   903         if (powerType == MIRType_Float32)
   904             powerType = MIRType_Double;
   905         MPow *pow = MPow::New(alloc(), base, power, powerType);
   906         current->add(pow);
   907         output = pow;
   908     }
   910     // Cast to the right type
   911     if (outputType == MIRType_Int32 && output->type() != MIRType_Int32) {
   912         MToInt32 *toInt = MToInt32::New(alloc(), output);
   913         current->add(toInt);
   914         output = toInt;
   915     }
   916     if (outputType == MIRType_Double && output->type() != MIRType_Double) {
   917         MToDouble *toDouble = MToDouble::New(alloc(), output);
   918         current->add(toDouble);
   919         output = toDouble;
   920     }
   922     current->push(output);
   923     return InliningStatus_Inlined;
   924 }
   926 IonBuilder::InliningStatus
   927 IonBuilder::inlineMathRandom(CallInfo &callInfo)
   928 {
   929     if (callInfo.constructing())
   930         return InliningStatus_NotInlined;
   932     if (getInlineReturnType() != MIRType_Double)
   933         return InliningStatus_NotInlined;
   935     callInfo.setImplicitlyUsedUnchecked();
   937     MRandom *rand = MRandom::New(alloc());
   938     current->add(rand);
   939     current->push(rand);
   940     return InliningStatus_Inlined;
   941 }
   943 IonBuilder::InliningStatus
   944 IonBuilder::inlineMathImul(CallInfo &callInfo)
   945 {
   946     if (callInfo.argc() != 2 || callInfo.constructing())
   947         return InliningStatus_NotInlined;
   949     MIRType returnType = getInlineReturnType();
   950     if (returnType != MIRType_Int32)
   951         return InliningStatus_NotInlined;
   953     if (!IsNumberType(callInfo.getArg(0)->type()))
   954         return InliningStatus_NotInlined;
   955     if (!IsNumberType(callInfo.getArg(1)->type()))
   956         return InliningStatus_NotInlined;
   958     callInfo.setImplicitlyUsedUnchecked();
   960     MInstruction *first = MTruncateToInt32::New(alloc(), callInfo.getArg(0));
   961     current->add(first);
   963     MInstruction *second = MTruncateToInt32::New(alloc(), callInfo.getArg(1));
   964     current->add(second);
   966     MMul *ins = MMul::New(alloc(), first, second, MIRType_Int32, MMul::Integer);
   967     current->add(ins);
   968     current->push(ins);
   969     return InliningStatus_Inlined;
   970 }
   972 IonBuilder::InliningStatus
   973 IonBuilder::inlineMathFRound(CallInfo &callInfo)
   974 {
   975     if (!LIRGenerator::allowFloat32Optimizations())
   976         return InliningStatus_NotInlined;
   978     if (callInfo.argc() != 1 || callInfo.constructing())
   979         return InliningStatus_NotInlined;
   981     // MIRType can't be Float32, as this point, as getInlineReturnType uses JSVal types
   982     // to infer the returned MIR type.
   983     types::TemporaryTypeSet *returned = getInlineReturnTypeSet();
   984     if (returned->empty()) {
   985         // As there's only one possible returned type, just add it to the observed
   986         // returned typeset
   987         returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
   988     } else {
   989         MIRType returnType = getInlineReturnType();
   990         if (!IsNumberType(returnType))
   991             return InliningStatus_NotInlined;
   992     }
   994     MIRType arg = callInfo.getArg(0)->type();
   995     if (!IsNumberType(arg))
   996         return InliningStatus_NotInlined;
   998     callInfo.setImplicitlyUsedUnchecked();
  1000     MToFloat32 *ins = MToFloat32::New(alloc(), callInfo.getArg(0));
  1001     current->add(ins);
  1002     current->push(ins);
  1003     return InliningStatus_Inlined;
  1006 IonBuilder::InliningStatus
  1007 IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
  1009     if (callInfo.argc() < 2 || callInfo.constructing())
  1010         return InliningStatus_NotInlined;
  1012     MIRType returnType = getInlineReturnType();
  1013     if (!IsNumberType(returnType))
  1014         return InliningStatus_NotInlined;
  1016     for (unsigned i = 0; i < callInfo.argc(); i++) {
  1017         MIRType argType = callInfo.getArg(i)->type();
  1018         if (!IsNumberType(argType))
  1019             return InliningStatus_NotInlined;
  1021         // When one of the arguments is double, do a double MMinMax.
  1022         if (returnType == MIRType_Int32 && IsFloatingPointType(argType))
  1023             returnType = MIRType_Double;
  1026     callInfo.setImplicitlyUsedUnchecked();
  1028     // Chain N-1 MMinMax instructions to compute the MinMax.
  1029     MMinMax *last = MMinMax::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), returnType, max);
  1030     current->add(last);
  1032     for (unsigned i = 2; i < callInfo.argc(); i++) {
  1033         MMinMax *ins = MMinMax::New(alloc(), last, callInfo.getArg(i), returnType, max);
  1034         current->add(ins);
  1035         last = ins;
  1038     current->push(last);
  1039     return InliningStatus_Inlined;
  1042 IonBuilder::InliningStatus
  1043 IonBuilder::inlineStringObject(CallInfo &callInfo)
  1045     if (callInfo.argc() != 1 || !callInfo.constructing())
  1046         return InliningStatus_NotInlined;
  1048     // ConvertToString doesn't support objects.
  1049     if (callInfo.getArg(0)->mightBeType(MIRType_Object))
  1050         return InliningStatus_NotInlined;
  1052     JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js_String);
  1053     if (!templateObj)
  1054         return InliningStatus_NotInlined;
  1055     JS_ASSERT(templateObj->is<StringObject>());
  1057     callInfo.setImplicitlyUsedUnchecked();
  1059     MNewStringObject *ins = MNewStringObject::New(alloc(), callInfo.getArg(0), templateObj);
  1060     current->add(ins);
  1061     current->push(ins);
  1063     if (!resumeAfter(ins))
  1064         return InliningStatus_Error;
  1066     return InliningStatus_Inlined;
  1069 IonBuilder::InliningStatus
  1070 IonBuilder::inlineStringSplit(CallInfo &callInfo)
  1072     if (callInfo.argc() != 1 || callInfo.constructing())
  1073         return InliningStatus_NotInlined;
  1074     if (callInfo.thisArg()->type() != MIRType_String)
  1075         return InliningStatus_NotInlined;
  1076     if (callInfo.getArg(0)->type() != MIRType_String)
  1077         return InliningStatus_NotInlined;
  1079     JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js::str_split);
  1080     if (!templateObject)
  1081         return InliningStatus_NotInlined;
  1082     JS_ASSERT(templateObject->is<ArrayObject>());
  1084     types::TypeObjectKey *retType = types::TypeObjectKey::get(templateObject);
  1085     if (retType->unknownProperties())
  1086         return InliningStatus_NotInlined;
  1088     types::HeapTypeSetKey key = retType->property(JSID_VOID);
  1089     if (!key.maybeTypes())
  1090         return InliningStatus_NotInlined;
  1092     if (!key.maybeTypes()->hasType(types::Type::StringType())) {
  1093         key.freeze(constraints());
  1094         return InliningStatus_NotInlined;
  1097     callInfo.setImplicitlyUsedUnchecked();
  1099     MStringSplit *ins = MStringSplit::New(alloc(), constraints(), callInfo.thisArg(),
  1100                                           callInfo.getArg(0), templateObject);
  1101     current->add(ins);
  1102     current->push(ins);
  1104     return InliningStatus_Inlined;
  1107 IonBuilder::InliningStatus
  1108 IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
  1110     if (callInfo.argc() != 1 || callInfo.constructing())
  1111         return InliningStatus_NotInlined;
  1113     if (getInlineReturnType() != MIRType_Int32)
  1114         return InliningStatus_NotInlined;
  1115     if (callInfo.thisArg()->type() != MIRType_String && callInfo.thisArg()->type() != MIRType_Value)
  1116         return InliningStatus_NotInlined;
  1117     MIRType argType = callInfo.getArg(0)->type();
  1118     if (argType != MIRType_Int32 && argType != MIRType_Double)
  1119         return InliningStatus_NotInlined;
  1121     callInfo.setImplicitlyUsedUnchecked();
  1123     MInstruction *index = MToInt32::New(alloc(), callInfo.getArg(0));
  1124     current->add(index);
  1126     MStringLength *length = MStringLength::New(alloc(), callInfo.thisArg());
  1127     current->add(length);
  1129     index = addBoundsCheck(index, length);
  1131     MCharCodeAt *charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
  1132     current->add(charCode);
  1133     current->push(charCode);
  1134     return InliningStatus_Inlined;
  1137 IonBuilder::InliningStatus
  1138 IonBuilder::inlineStrFromCharCode(CallInfo &callInfo)
  1140     if (callInfo.argc() != 1 || callInfo.constructing())
  1141         return InliningStatus_NotInlined;
  1143     if (getInlineReturnType() != MIRType_String)
  1144         return InliningStatus_NotInlined;
  1145     if (callInfo.getArg(0)->type() != MIRType_Int32)
  1146         return InliningStatus_NotInlined;
  1148     callInfo.setImplicitlyUsedUnchecked();
  1150     MToInt32 *charCode = MToInt32::New(alloc(), callInfo.getArg(0));
  1151     current->add(charCode);
  1153     MFromCharCode *string = MFromCharCode::New(alloc(), charCode);
  1154     current->add(string);
  1155     current->push(string);
  1156     return InliningStatus_Inlined;
  1159 IonBuilder::InliningStatus
  1160 IonBuilder::inlineStrCharAt(CallInfo &callInfo)
  1162     if (callInfo.argc() != 1 || callInfo.constructing())
  1163         return InliningStatus_NotInlined;
  1165     if (getInlineReturnType() != MIRType_String)
  1166         return InliningStatus_NotInlined;
  1167     if (callInfo.thisArg()->type() != MIRType_String)
  1168         return InliningStatus_NotInlined;
  1169     MIRType argType = callInfo.getArg(0)->type();
  1170     if (argType != MIRType_Int32 && argType != MIRType_Double)
  1171         return InliningStatus_NotInlined;
  1173     callInfo.setImplicitlyUsedUnchecked();
  1175     MInstruction *index = MToInt32::New(alloc(), callInfo.getArg(0));
  1176     current->add(index);
  1178     MStringLength *length = MStringLength::New(alloc(), callInfo.thisArg());
  1179     current->add(length);
  1181     index = addBoundsCheck(index, length);
  1183     // String.charAt(x) = String.fromCharCode(String.charCodeAt(x))
  1184     MCharCodeAt *charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
  1185     current->add(charCode);
  1187     MFromCharCode *string = MFromCharCode::New(alloc(), charCode);
  1188     current->add(string);
  1189     current->push(string);
  1190     return InliningStatus_Inlined;
  1193 IonBuilder::InliningStatus
  1194 IonBuilder::inlineRegExpExec(CallInfo &callInfo)
  1196     if (callInfo.argc() != 1 || callInfo.constructing())
  1197         return InliningStatus_NotInlined;
  1199     if (callInfo.thisArg()->type() != MIRType_Object)
  1200         return InliningStatus_NotInlined;
  1202     types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
  1203     const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr;
  1204     if (clasp != &RegExpObject::class_)
  1205         return InliningStatus_NotInlined;
  1207     if (callInfo.getArg(0)->mightBeType(MIRType_Object))
  1208         return InliningStatus_NotInlined;
  1210     callInfo.setImplicitlyUsedUnchecked();
  1212     MInstruction *exec = MRegExpExec::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
  1213     current->add(exec);
  1214     current->push(exec);
  1216     if (!resumeAfter(exec))
  1217         return InliningStatus_Error;
  1219     if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), true))
  1220         return InliningStatus_Error;
  1222     return InliningStatus_Inlined;
  1225 IonBuilder::InliningStatus
  1226 IonBuilder::inlineRegExpTest(CallInfo &callInfo)
  1228     if (callInfo.argc() != 1 || callInfo.constructing())
  1229         return InliningStatus_NotInlined;
  1231     // TI can infer a nullptr return type of regexp_test with eager compilation.
  1232     if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean)
  1233         return InliningStatus_NotInlined;
  1235     if (callInfo.thisArg()->type() != MIRType_Object)
  1236         return InliningStatus_NotInlined;
  1237     types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
  1238     const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr;
  1239     if (clasp != &RegExpObject::class_)
  1240         return InliningStatus_NotInlined;
  1241     if (callInfo.getArg(0)->mightBeType(MIRType_Object))
  1242         return InliningStatus_NotInlined;
  1244     callInfo.setImplicitlyUsedUnchecked();
  1246     MInstruction *match = MRegExpTest::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
  1247     current->add(match);
  1248     current->push(match);
  1249     if (!resumeAfter(match))
  1250         return InliningStatus_Error;
  1252     return InliningStatus_Inlined;
  1255 IonBuilder::InliningStatus
  1256 IonBuilder::inlineStrReplace(CallInfo &callInfo)
  1258     if (callInfo.argc() != 2 || callInfo.constructing())
  1259         return InliningStatus_NotInlined;
  1261     // Return: String.
  1262     if (getInlineReturnType() != MIRType_String)
  1263         return InliningStatus_NotInlined;
  1265     // This: String.
  1266     if (callInfo.thisArg()->type() != MIRType_String)
  1267         return InliningStatus_NotInlined;
  1269     // Arg 0: RegExp.
  1270     types::TemporaryTypeSet *arg0Type = callInfo.getArg(0)->resultTypeSet();
  1271     const Class *clasp = arg0Type ? arg0Type->getKnownClass() : nullptr;
  1272     if (clasp != &RegExpObject::class_ && callInfo.getArg(0)->type() != MIRType_String)
  1273         return InliningStatus_NotInlined;
  1275     // Arg 1: String.
  1276     if (callInfo.getArg(1)->type() != MIRType_String)
  1277         return InliningStatus_NotInlined;
  1279     callInfo.setImplicitlyUsedUnchecked();
  1281     MInstruction *cte;
  1282     if (callInfo.getArg(0)->type() == MIRType_String) {
  1283         cte = MStringReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
  1284                                   callInfo.getArg(1));
  1285     } else {
  1286         cte = MRegExpReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
  1287                                   callInfo.getArg(1));
  1289     current->add(cte);
  1290     current->push(cte);
  1291     if (cte->isEffectful() && !resumeAfter(cte))
  1292         return InliningStatus_Error;
  1293     return InliningStatus_Inlined;
  1296 IonBuilder::InliningStatus
  1297 IonBuilder::inlineUnsafePutElements(CallInfo &callInfo)
  1299     uint32_t argc = callInfo.argc();
  1300     if (argc < 3 || (argc % 3) != 0 || callInfo.constructing())
  1301         return InliningStatus_NotInlined;
  1303     /* Important:
  1305      * Here we inline each of the stores resulting from a call to
  1306      * UnsafePutElements().  It is essential that these stores occur
  1307      * atomically and cannot be interrupted by a stack or recursion
  1308      * check.  If this is not true, race conditions can occur.
  1309      */
  1311     for (uint32_t base = 0; base < argc; base += 3) {
  1312         uint32_t arri = base + 0;
  1313         uint32_t idxi = base + 1;
  1314         uint32_t elemi = base + 2;
  1316         MDefinition *obj = callInfo.getArg(arri);
  1317         MDefinition *id = callInfo.getArg(idxi);
  1318         MDefinition *elem = callInfo.getArg(elemi);
  1320         bool isDenseNative = ElementAccessIsDenseNative(obj, id);
  1322         bool writeNeedsBarrier = false;
  1323         if (isDenseNative) {
  1324             writeNeedsBarrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
  1325                                                               &obj, nullptr, &elem,
  1326                                                               /* canModify = */ false);
  1329         // We can only inline setelem on dense arrays that do not need type
  1330         // barriers and on typed arrays and on typed object arrays.
  1331         ScalarTypeDescr::Type arrayType;
  1332         if ((!isDenseNative || writeNeedsBarrier) &&
  1333             !ElementAccessIsTypedArray(obj, id, &arrayType) &&
  1334             !elementAccessIsTypedObjectArrayOfScalarType(obj, id, &arrayType))
  1336             return InliningStatus_NotInlined;
  1340     callInfo.setImplicitlyUsedUnchecked();
  1342     // Push the result first so that the stack depth matches up for
  1343     // the potential bailouts that will occur in the stores below.
  1344     MConstant *udef = MConstant::New(alloc(), UndefinedValue());
  1345     current->add(udef);
  1346     current->push(udef);
  1348     for (uint32_t base = 0; base < argc; base += 3) {
  1349         uint32_t arri = base + 0;
  1350         uint32_t idxi = base + 1;
  1352         MDefinition *obj = callInfo.getArg(arri);
  1353         MDefinition *id = callInfo.getArg(idxi);
  1355         if (ElementAccessIsDenseNative(obj, id)) {
  1356             if (!inlineUnsafeSetDenseArrayElement(callInfo, base))
  1357                 return InliningStatus_Error;
  1358             continue;
  1361         ScalarTypeDescr::Type arrayType;
  1362         if (ElementAccessIsTypedArray(obj, id, &arrayType)) {
  1363             if (!inlineUnsafeSetTypedArrayElement(callInfo, base, arrayType))
  1364                 return InliningStatus_Error;
  1365             continue;
  1368         if (elementAccessIsTypedObjectArrayOfScalarType(obj, id, &arrayType)) {
  1369             if (!inlineUnsafeSetTypedObjectArrayElement(callInfo, base, arrayType))
  1370                 return InliningStatus_Error;
  1371             continue;
  1374         MOZ_ASSUME_UNREACHABLE("Element access not dense array nor typed array");
  1377     return InliningStatus_Inlined;
  1380 bool
  1381 IonBuilder::elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
  1382                                                         ScalarTypeDescr::Type *arrayType)
  1384     if (obj->type() != MIRType_Object) // lookupTypeDescrSet() tests for TypedObject
  1385         return false;
  1387     if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
  1388         return false;
  1390     TypeDescrSet objDescrs;
  1391     if (!lookupTypeDescrSet(obj, &objDescrs))
  1392         return false;
  1394     if (!objDescrs.allOfArrayKind())
  1395         return false;
  1397     TypeDescrSet elemDescrs;
  1398     if (!objDescrs.arrayElementType(*this, &elemDescrs))
  1399         return false;
  1401     if (elemDescrs.empty() || elemDescrs.kind() != TypeDescr::Scalar)
  1402         return false;
  1404     JS_ASSERT(TypeDescr::isSized(elemDescrs.kind()));
  1406     return elemDescrs.scalarType(arrayType);
  1409 bool
  1410 IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
  1412     // Note: we do not check the conditions that are asserted as true
  1413     // in intrinsic_UnsafePutElements():
  1414     // - arr is a dense array
  1415     // - idx < initialized length
  1416     // Furthermore, note that inlineUnsafePutElements ensures the type of the
  1417     // value is reflected in the JSID_VOID property of the array.
  1419     MDefinition *obj = callInfo.getArg(base + 0);
  1420     MDefinition *id = callInfo.getArg(base + 1);
  1421     MDefinition *elem = callInfo.getArg(base + 2);
  1423     types::TemporaryTypeSet::DoubleConversion conversion =
  1424         obj->resultTypeSet()->convertDoubleElements(constraints());
  1425     if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
  1426         return false;
  1427     return true;
  1430 bool
  1431 IonBuilder::inlineUnsafeSetTypedArrayElement(CallInfo &callInfo,
  1432                                              uint32_t base,
  1433                                              ScalarTypeDescr::Type arrayType)
  1435     // Note: we do not check the conditions that are asserted as true
  1436     // in intrinsic_UnsafePutElements():
  1437     // - arr is a typed array
  1438     // - idx < length
  1440     MDefinition *obj = callInfo.getArg(base + 0);
  1441     MDefinition *id = callInfo.getArg(base + 1);
  1442     MDefinition *elem = callInfo.getArg(base + 2);
  1444     if (!jsop_setelem_typed(arrayType, SetElem_Unsafe, obj, id, elem))
  1445         return false;
  1447     return true;
  1450 bool
  1451 IonBuilder::inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo,
  1452                                                    uint32_t base,
  1453                                                    ScalarTypeDescr::Type arrayType)
  1455     // Note: we do not check the conditions that are asserted as true
  1456     // in intrinsic_UnsafePutElements():
  1457     // - arr is a typed array
  1458     // - idx < length
  1460     MDefinition *obj = callInfo.getArg(base + 0);
  1461     MDefinition *id = callInfo.getArg(base + 1);
  1462     MDefinition *elem = callInfo.getArg(base + 2);
  1464     if (!jsop_setelem_typed_object(arrayType, SetElem_Unsafe, true, obj, id, elem))
  1465         return false;
  1467     return true;
  1470 IonBuilder::InliningStatus
  1471 IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo)
  1473     if (callInfo.constructing())
  1474         return InliningStatus_NotInlined;
  1476     ExecutionMode executionMode = info().executionMode();
  1477     switch (executionMode) {
  1478       case ParallelExecution: {
  1479         // During Parallel Exec, we always force sequential, so
  1480         // replace with true.  This permits UCE to eliminate the
  1481         // entire path as dead, which is important.
  1482         callInfo.setImplicitlyUsedUnchecked();
  1483         MConstant *ins = MConstant::New(alloc(), BooleanValue(true));
  1484         current->add(ins);
  1485         current->push(ins);
  1486         return InliningStatus_Inlined;
  1489       default:
  1490         // In sequential mode, leave as is, because we'd have to
  1491         // access the "in warmup" flag of the runtime.
  1492         return InliningStatus_NotInlined;
  1495     MOZ_ASSUME_UNREACHABLE("Invalid execution mode");
  1498 IonBuilder::InliningStatus
  1499 IonBuilder::inlineForkJoinGetSlice(CallInfo &callInfo)
  1501     if (info().executionMode() != ParallelExecution)
  1502         return InliningStatus_NotInlined;
  1504     // Assert the way the function is used instead of testing, as it is a
  1505     // self-hosted function which must be used in a particular fashion.
  1506     MOZ_ASSERT(callInfo.argc() == 1 && !callInfo.constructing());
  1507     MOZ_ASSERT(callInfo.getArg(0)->type() == MIRType_Int32);
  1509     // Test this, as we might have not executed the native despite knowing the
  1510     // target here.
  1511     if (getInlineReturnType() != MIRType_Int32)
  1512         return InliningStatus_NotInlined;
  1514     callInfo.setImplicitlyUsedUnchecked();
  1516     switch (info().executionMode()) {
  1517       case ParallelExecution:
  1518         if (LIRGenerator::allowInlineForkJoinGetSlice()) {
  1519             MForkJoinGetSlice *getSlice = MForkJoinGetSlice::New(alloc(),
  1520                                                                  graph().forkJoinContext());
  1521             current->add(getSlice);
  1522             current->push(getSlice);
  1523             return InliningStatus_Inlined;
  1525         return InliningStatus_NotInlined;
  1527       default:
  1528         // ForkJoinGetSlice acts as identity for sequential execution.
  1529         current->push(callInfo.getArg(0));
  1530         return InliningStatus_Inlined;
  1533     MOZ_ASSUME_UNREACHABLE("Invalid execution mode");
  1536 IonBuilder::InliningStatus
  1537 IonBuilder::inlineNewDenseArray(CallInfo &callInfo)
  1539     if (callInfo.constructing() || callInfo.argc() != 1)
  1540         return InliningStatus_NotInlined;
  1542     // For now, in seq. mode we just call the C function.  In
  1543     // par. mode we use inlined MIR.
  1544     ExecutionMode executionMode = info().executionMode();
  1545     switch (executionMode) {
  1546       case ParallelExecution:
  1547         return inlineNewDenseArrayForParallelExecution(callInfo);
  1548       default:
  1549         return inlineNewDenseArrayForSequentialExecution(callInfo);
  1552     MOZ_ASSUME_UNREACHABLE("unknown ExecutionMode");
  1555 IonBuilder::InliningStatus
  1556 IonBuilder::inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo)
  1558     // not yet implemented; in seq. mode the C function is not so bad
  1559     return InliningStatus_NotInlined;
  1562 IonBuilder::InliningStatus
  1563 IonBuilder::inlineNewDenseArrayForParallelExecution(CallInfo &callInfo)
  1565     // Create the new parallel array object.  Parallel arrays have specially
  1566     // constructed type objects, so we can only perform the inlining if we
  1567     // already have one of these type objects.
  1568     types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
  1569     if (returnTypes->getKnownMIRType() != MIRType_Object)
  1570         return InliningStatus_NotInlined;
  1571     if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
  1572         return InliningStatus_NotInlined;
  1573     if (callInfo.getArg(0)->type() != MIRType_Int32)
  1574         return InliningStatus_NotInlined;
  1575     types::TypeObject *typeObject = returnTypes->getTypeObject(0);
  1577     JSObject *templateObject = inspector->getTemplateObjectForNative(pc, intrinsic_NewDenseArray);
  1578     if (!templateObject || templateObject->type() != typeObject)
  1579         return InliningStatus_NotInlined;
  1581     callInfo.setImplicitlyUsedUnchecked();
  1583     MNewDenseArrayPar *newObject = MNewDenseArrayPar::New(alloc(),
  1584                                                           graph().forkJoinContext(),
  1585                                                           callInfo.getArg(0),
  1586                                                           templateObject);
  1587     current->add(newObject);
  1588     current->push(newObject);
  1590     return InliningStatus_Inlined;
  1593 IonBuilder::InliningStatus
  1594 IonBuilder::inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Class *clasp2)
  1596     // Thus far there has been no reason to complicate this beyond two classes,
  1597     // though it generalizes pretty well.
  1598     // clasp2 may be NULL.
  1599     if (callInfo.constructing() || callInfo.argc() != 1)
  1600         return InliningStatus_NotInlined;
  1602     if (callInfo.getArg(0)->type() != MIRType_Object)
  1603         return InliningStatus_NotInlined;
  1604     if (getInlineReturnType() != MIRType_Boolean)
  1605         return InliningStatus_NotInlined;
  1607     types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
  1608     const Class *knownClass = types ? types->getKnownClass() : nullptr;
  1609     if (knownClass) {
  1610         pushConstant(BooleanValue(knownClass == clasp1 || knownClass == clasp2));
  1611     } else {
  1612         MHasClass *hasClass1 = MHasClass::New(alloc(), callInfo.getArg(0), clasp1);
  1613         current->add(hasClass1);
  1614         if (clasp2 == nullptr) {
  1615             current->push(hasClass1);
  1616         } else {
  1617             // The following turns into branch-free, box-free code on x86, and should do so on ARM.
  1618             MHasClass *hasClass2 = MHasClass::New(alloc(), callInfo.getArg(0), clasp2);
  1619             current->add(hasClass2);
  1620             MBitOr *either = MBitOr::New(alloc(), hasClass1, hasClass2);
  1621             either->infer(inspector, pc);
  1622             current->add(either);
  1623             // Convert to bool with the '!!' idiom
  1624             MNot *resultInverted = MNot::New(alloc(), either);
  1625             resultInverted->infer();
  1626             current->add(resultInverted);
  1627             MNot *result = MNot::New(alloc(), resultInverted);
  1628             result->infer();
  1629             current->add(result);
  1630             current->push(result);
  1634     callInfo.setImplicitlyUsedUnchecked();
  1635     return InliningStatus_Inlined;
  1638 IonBuilder::InliningStatus
  1639 IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
  1641     if (callInfo.constructing() || callInfo.argc() != 1)
  1642         return InliningStatus_NotInlined;
  1644     if (callInfo.getArg(0)->type() != MIRType_Object)
  1645         return InliningStatus_NotInlined;
  1646     if (getInlineReturnType() != MIRType_Boolean)
  1647         return InliningStatus_NotInlined;
  1649     // The test is elaborate: in-line only if there is exact
  1650     // information.
  1652     types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
  1653     if (!types)
  1654         return InliningStatus_NotInlined;
  1656     bool result = false;
  1657     switch (types->forAllClasses(IsTypeDescrClass)) {
  1658     case types::TemporaryTypeSet::ForAllResult::ALL_FALSE:
  1659     case types::TemporaryTypeSet::ForAllResult::EMPTY:
  1660         result = false;
  1661         break;
  1662     case types::TemporaryTypeSet::ForAllResult::ALL_TRUE:
  1663         result = true;
  1664         break;
  1665     case types::TemporaryTypeSet::ForAllResult::MIXED:
  1666         return InliningStatus_NotInlined;
  1669     pushConstant(BooleanValue(result));
  1671     callInfo.setImplicitlyUsedUnchecked();
  1672     return InliningStatus_Inlined;
  1675 IonBuilder::InliningStatus
  1676 IonBuilder::inlineSetTypedObjectOffset(CallInfo &callInfo)
  1678     if (callInfo.argc() != 2 || callInfo.constructing())
  1679         return InliningStatus_NotInlined;
  1681     MDefinition *typedObj = callInfo.getArg(0);
  1682     MDefinition *offset = callInfo.getArg(1);
  1684     // Return type should be undefined or something wacky is going on.
  1685     if (getInlineReturnType() != MIRType_Undefined)
  1686         return InliningStatus_NotInlined;
  1688     // Check typedObj is a, well, typed object. Go ahead and use TI
  1689     // data. If this check should fail, that is almost certainly a bug
  1690     // in self-hosted code -- either because it's not being careful
  1691     // with TI or because of something else -- but we'll just let it
  1692     // fall through to the SetTypedObjectOffset intrinsic in such
  1693     // cases.
  1694     types::TemporaryTypeSet *types = typedObj->resultTypeSet();
  1695     if (typedObj->type() != MIRType_Object || !types)
  1696         return InliningStatus_NotInlined;
  1697     switch (types->forAllClasses(IsTypedObjectClass)) {
  1698       case types::TemporaryTypeSet::ForAllResult::ALL_FALSE:
  1699       case types::TemporaryTypeSet::ForAllResult::EMPTY:
  1700       case types::TemporaryTypeSet::ForAllResult::MIXED:
  1701         return InliningStatus_NotInlined;
  1702       case types::TemporaryTypeSet::ForAllResult::ALL_TRUE:
  1703         break;
  1706     // Check type of offset argument is an integer.
  1707     if (offset->type() != MIRType_Int32)
  1708         return InliningStatus_NotInlined;
  1710     callInfo.setImplicitlyUsedUnchecked();
  1711     MInstruction *ins = MSetTypedObjectOffset::New(alloc(), typedObj, offset);
  1712     current->add(ins);
  1713     current->push(ins);
  1714     return InliningStatus_Inlined;
  1717 IonBuilder::InliningStatus
  1718 IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
  1720     if (callInfo.argc() != 3 || callInfo.constructing())
  1721         return InliningStatus_NotInlined;
  1722     if (getInlineReturnType() != MIRType_Undefined)
  1723         return InliningStatus_NotInlined;
  1724     if (callInfo.getArg(0)->type() != MIRType_Object)
  1725         return InliningStatus_NotInlined;
  1726     if (callInfo.getArg(1)->type() != MIRType_Int32)
  1727         return InliningStatus_NotInlined;
  1729     // Don't inline if we don't have a constant slot.
  1730     MDefinition *arg = callInfo.getArg(1);
  1731     if (!arg->isConstant())
  1732         return InliningStatus_NotInlined;
  1733     uint32_t slot = arg->toConstant()->value().toPrivateUint32();
  1735     callInfo.setImplicitlyUsedUnchecked();
  1737     MStoreFixedSlot *store = MStoreFixedSlot::New(alloc(), callInfo.getArg(0), slot, callInfo.getArg(2));
  1738     current->add(store);
  1739     current->push(store);
  1741     if (NeedsPostBarrier(info(), callInfo.getArg(2)))
  1742         current->add(MPostWriteBarrier::New(alloc(), callInfo.thisArg(), callInfo.getArg(2)));
  1744     return InliningStatus_Inlined;
  1747 IonBuilder::InliningStatus
  1748 IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo)
  1750     if (callInfo.argc() != 2 || callInfo.constructing())
  1751         return InliningStatus_NotInlined;
  1752     if (callInfo.getArg(0)->type() != MIRType_Object)
  1753         return InliningStatus_NotInlined;
  1754     if (callInfo.getArg(1)->type() != MIRType_Int32)
  1755         return InliningStatus_NotInlined;
  1757     // Don't inline if we don't have a constant slot.
  1758     MDefinition *arg = callInfo.getArg(1);
  1759     if (!arg->isConstant())
  1760         return InliningStatus_NotInlined;
  1761     uint32_t slot = arg->toConstant()->value().toPrivateUint32();
  1763     callInfo.setImplicitlyUsedUnchecked();
  1765     MLoadFixedSlot *load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot);
  1766     current->add(load);
  1767     current->push(load);
  1769     // We don't track reserved slot types, so always emit a barrier.
  1770     if (!pushTypeBarrier(load, getInlineReturnTypeSet(), true))
  1771         return InliningStatus_Error;
  1773     return InliningStatus_Inlined;
  1776 IonBuilder::InliningStatus
  1777 IonBuilder::inlineHaveSameClass(CallInfo &callInfo)
  1779     if (callInfo.argc() != 2 || callInfo.constructing())
  1780         return InliningStatus_NotInlined;
  1781     if (callInfo.getArg(0)->type() != MIRType_Object)
  1782         return InliningStatus_NotInlined;
  1783     if (callInfo.getArg(1)->type() != MIRType_Object)
  1784         return InliningStatus_NotInlined;
  1786     types::TemporaryTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
  1787     types::TemporaryTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
  1788     const Class *arg1Clasp = arg1Types ? arg1Types->getKnownClass() : nullptr;
  1789     const Class *arg2Clasp = arg2Types ? arg2Types->getKnownClass() : nullptr;
  1790     if (arg1Clasp && arg2Clasp) {
  1791         MConstant *constant = MConstant::New(alloc(), BooleanValue(arg1Clasp == arg2Clasp));
  1792         current->add(constant);
  1793         current->push(constant);
  1794         return InliningStatus_Inlined;
  1797     callInfo.setImplicitlyUsedUnchecked();
  1799     MHaveSameClass *sameClass = MHaveSameClass::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
  1800     current->add(sameClass);
  1801     current->push(sameClass);
  1803     return InliningStatus_Inlined;
  1806 IonBuilder::InliningStatus
  1807 IonBuilder::inlineIsCallable(CallInfo &callInfo)
  1809     if (callInfo.argc() != 1 || callInfo.constructing())
  1810         return InliningStatus_NotInlined;
  1812     if (getInlineReturnType() != MIRType_Boolean)
  1813         return InliningStatus_NotInlined;
  1814     if (callInfo.getArg(0)->type() != MIRType_Object)
  1815         return InliningStatus_NotInlined;
  1817     // Try inlining with constant true/false: only objects may be callable at
  1818     // all, and if we know the class check if it is callable.
  1819     bool isCallableKnown = false;
  1820     bool isCallableConstant;
  1821     if (callInfo.getArg(0)->type() != MIRType_Object) {
  1822         isCallableKnown = true;
  1823         isCallableConstant = false;
  1824     } else {
  1825         types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
  1826         const Class *clasp = types ? types->getKnownClass() : nullptr;
  1827         if (clasp) {
  1828             isCallableKnown = true;
  1829             isCallableConstant = clasp->isCallable();
  1833     callInfo.setImplicitlyUsedUnchecked();
  1835     if (isCallableKnown) {
  1836         MConstant *constant = MConstant::New(alloc(), BooleanValue(isCallableConstant));
  1837         current->add(constant);
  1838         current->push(constant);
  1839         return InliningStatus_Inlined;
  1842     MIsCallable *isCallable = MIsCallable::New(alloc(), callInfo.getArg(0));
  1843     current->add(isCallable);
  1844     current->push(isCallable);
  1846     return InliningStatus_Inlined;
  1849 IonBuilder::InliningStatus
  1850 IonBuilder::inlineToObject(CallInfo &callInfo)
  1852     if (callInfo.argc() != 1 || callInfo.constructing())
  1853         return InliningStatus_NotInlined;
  1855     // If we know the input type is an object, nop ToObject.
  1856     if (getInlineReturnType() != MIRType_Object)
  1857         return InliningStatus_NotInlined;
  1858     if (callInfo.getArg(0)->type() != MIRType_Object)
  1859         return InliningStatus_NotInlined;
  1861     callInfo.setImplicitlyUsedUnchecked();
  1862     MDefinition *object = callInfo.getArg(0);
  1864     current->push(object);
  1865     return InliningStatus_Inlined;
  1868 IonBuilder::InliningStatus
  1869 IonBuilder::inlineBailout(CallInfo &callInfo)
  1871     callInfo.setImplicitlyUsedUnchecked();
  1873     current->add(MBail::New(alloc()));
  1875     MConstant *undefined = MConstant::New(alloc(), UndefinedValue());
  1876     current->add(undefined);
  1877     current->push(undefined);
  1878     return InliningStatus_Inlined;
  1881 IonBuilder::InliningStatus
  1882 IonBuilder::inlineAssertFloat32(CallInfo &callInfo)
  1884     callInfo.setImplicitlyUsedUnchecked();
  1886     MDefinition *secondArg = callInfo.getArg(1);
  1888     JS_ASSERT(secondArg->type() == MIRType_Boolean);
  1889     JS_ASSERT(secondArg->isConstant());
  1891     bool mustBeFloat32 = JSVAL_TO_BOOLEAN(secondArg->toConstant()->value());
  1892     current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32));
  1894     MConstant *undefined = MConstant::New(alloc(), UndefinedValue());
  1895     current->add(undefined);
  1896     current->push(undefined);
  1897     return InliningStatus_Inlined;
  1900 IonBuilder::InliningStatus
  1901 IonBuilder::inlineBoundFunction(CallInfo &nativeCallInfo, JSFunction *target)
  1903      if (!target->getBoundFunctionTarget()->is<JSFunction>())
  1904          return InliningStatus_NotInlined;
  1906     JSFunction *scriptedTarget = &(target->getBoundFunctionTarget()->as<JSFunction>());
  1907     JSRuntime *runtime = scriptedTarget->runtimeFromMainThread();
  1909     // Don't optimize if we're constructing and the callee is not a
  1910     // constructor, so that CallKnown does not have to handle this case
  1911     // (it should always throw).
  1912     if (nativeCallInfo.constructing() && !scriptedTarget->isInterpretedConstructor() &&
  1913         !scriptedTarget->isNativeConstructor())
  1915         return InliningStatus_NotInlined;
  1918     if (gc::IsInsideNursery(runtime, scriptedTarget))
  1919         return InliningStatus_NotInlined;
  1921     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
  1922         const Value val = target->getBoundFunctionArgument(i);
  1923         if (val.isObject() && gc::IsInsideNursery(runtime, &val.toObject()))
  1924             return InliningStatus_NotInlined;
  1927     const Value thisVal = target->getBoundFunctionThis();
  1928     if (thisVal.isObject() && gc::IsInsideNursery(runtime, &thisVal.toObject()))
  1929         return InliningStatus_NotInlined;
  1931     size_t argc = target->getBoundFunctionArgumentCount() + nativeCallInfo.argc();
  1932     if (argc > ARGS_LENGTH_MAX)
  1933         return InliningStatus_NotInlined;
  1935     nativeCallInfo.thisArg()->setImplicitlyUsedUnchecked();
  1937     CallInfo callInfo(alloc(), nativeCallInfo.constructing());
  1938     callInfo.setFun(constant(ObjectValue(*scriptedTarget)));
  1939     callInfo.setThis(constant(target->getBoundFunctionThis()));
  1941     if (!callInfo.argv().reserve(argc))
  1942         return InliningStatus_Error;
  1944     for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++)
  1945         callInfo.argv().infallibleAppend(constant(target->getBoundFunctionArgument(i)));
  1946     for (size_t i = 0; i < nativeCallInfo.argc(); i++)
  1947         callInfo.argv().infallibleAppend(nativeCallInfo.getArg(i));
  1949     if (!makeCall(scriptedTarget, callInfo, false))
  1950         return InliningStatus_Error;
  1952     return InliningStatus_Inlined;
  1955 } // namespace jit
  1956 } // namespace js

mercurial