js/src/jit/MCallOptimize.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/MCallOptimize.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1956 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jsmath.h"
    1.11 +
    1.12 +#include "builtin/TestingFunctions.h"
    1.13 +#include "builtin/TypedObject.h"
    1.14 +#include "jit/BaselineInspector.h"
    1.15 +#include "jit/IonBuilder.h"
    1.16 +#include "jit/Lowering.h"
    1.17 +#include "jit/MIR.h"
    1.18 +#include "jit/MIRGraph.h"
    1.19 +#include "vm/ArgumentsObject.h"
    1.20 +
    1.21 +#include "jsscriptinlines.h"
    1.22 +
    1.23 +#include "vm/StringObject-inl.h"
    1.24 +
    1.25 +namespace js {
    1.26 +namespace jit {
    1.27 +
    1.28 +IonBuilder::InliningStatus
    1.29 +IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
    1.30 +{
    1.31 +    JS_ASSERT(target->isNative());
    1.32 +    JSNative native = target->native();
    1.33 +
    1.34 +    if (!optimizationInfo().inlineNative())
    1.35 +        return InliningStatus_NotInlined;
    1.36 +
    1.37 +    // Array natives.
    1.38 +    if (native == js_Array)
    1.39 +        return inlineArray(callInfo);
    1.40 +    if (native == js::array_pop)
    1.41 +        return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
    1.42 +    if (native == js::array_shift)
    1.43 +        return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
    1.44 +    if (native == js::array_push)
    1.45 +        return inlineArrayPush(callInfo);
    1.46 +    if (native == js::array_concat)
    1.47 +        return inlineArrayConcat(callInfo);
    1.48 +    if (native == js::array_splice)
    1.49 +        return inlineArraySplice(callInfo);
    1.50 +
    1.51 +    // Math natives.
    1.52 +    if (native == js_math_abs)
    1.53 +        return inlineMathAbs(callInfo);
    1.54 +    if (native == js::math_floor)
    1.55 +        return inlineMathFloor(callInfo);
    1.56 +    if (native == js::math_ceil)
    1.57 +        return inlineMathCeil(callInfo);
    1.58 +    if (native == js::math_round)
    1.59 +        return inlineMathRound(callInfo);
    1.60 +    if (native == js_math_sqrt)
    1.61 +        return inlineMathSqrt(callInfo);
    1.62 +    if (native == math_atan2)
    1.63 +        return inlineMathAtan2(callInfo);
    1.64 +    if (native == js::math_hypot)
    1.65 +        return inlineMathHypot(callInfo);
    1.66 +    if (native == js_math_max)
    1.67 +        return inlineMathMinMax(callInfo, true /* max */);
    1.68 +    if (native == js_math_min)
    1.69 +        return inlineMathMinMax(callInfo, false /* max */);
    1.70 +    if (native == js_math_pow)
    1.71 +        return inlineMathPow(callInfo);
    1.72 +    if (native == js_math_random)
    1.73 +        return inlineMathRandom(callInfo);
    1.74 +    if (native == js::math_imul)
    1.75 +        return inlineMathImul(callInfo);
    1.76 +    if (native == js::math_fround)
    1.77 +        return inlineMathFRound(callInfo);
    1.78 +    if (native == js::math_sin)
    1.79 +        return inlineMathFunction(callInfo, MMathFunction::Sin);
    1.80 +    if (native == js::math_cos)
    1.81 +        return inlineMathFunction(callInfo, MMathFunction::Cos);
    1.82 +    if (native == js::math_exp)
    1.83 +        return inlineMathFunction(callInfo, MMathFunction::Exp);
    1.84 +    if (native == js::math_tan)
    1.85 +        return inlineMathFunction(callInfo, MMathFunction::Tan);
    1.86 +    if (native == js::math_log)
    1.87 +        return inlineMathFunction(callInfo, MMathFunction::Log);
    1.88 +    if (native == js::math_atan)
    1.89 +        return inlineMathFunction(callInfo, MMathFunction::ATan);
    1.90 +    if (native == js::math_asin)
    1.91 +        return inlineMathFunction(callInfo, MMathFunction::ASin);
    1.92 +    if (native == js::math_acos)
    1.93 +        return inlineMathFunction(callInfo, MMathFunction::ACos);
    1.94 +    if (native == js::math_log10)
    1.95 +        return inlineMathFunction(callInfo, MMathFunction::Log10);
    1.96 +    if (native == js::math_log2)
    1.97 +        return inlineMathFunction(callInfo, MMathFunction::Log2);
    1.98 +    if (native == js::math_log1p)
    1.99 +        return inlineMathFunction(callInfo, MMathFunction::Log1P);
   1.100 +    if (native == js::math_expm1)
   1.101 +        return inlineMathFunction(callInfo, MMathFunction::ExpM1);
   1.102 +    if (native == js::math_cosh)
   1.103 +        return inlineMathFunction(callInfo, MMathFunction::CosH);
   1.104 +    if (native == js::math_sin)
   1.105 +        return inlineMathFunction(callInfo, MMathFunction::SinH);
   1.106 +    if (native == js::math_tan)
   1.107 +        return inlineMathFunction(callInfo, MMathFunction::TanH);
   1.108 +    if (native == js::math_acosh)
   1.109 +        return inlineMathFunction(callInfo, MMathFunction::ACosH);
   1.110 +    if (native == js::math_asin)
   1.111 +        return inlineMathFunction(callInfo, MMathFunction::ASinH);
   1.112 +    if (native == js::math_atan)
   1.113 +        return inlineMathFunction(callInfo, MMathFunction::ATanH);
   1.114 +    if (native == js::math_sign)
   1.115 +        return inlineMathFunction(callInfo, MMathFunction::Sign);
   1.116 +    if (native == js::math_trunc)
   1.117 +        return inlineMathFunction(callInfo, MMathFunction::Trunc);
   1.118 +    if (native == js::math_cbrt)
   1.119 +        return inlineMathFunction(callInfo, MMathFunction::Cbrt);
   1.120 +
   1.121 +    // String natives.
   1.122 +    if (native == js_String)
   1.123 +        return inlineStringObject(callInfo);
   1.124 +    if (native == js::str_split)
   1.125 +        return inlineStringSplit(callInfo);
   1.126 +    if (native == js_str_charCodeAt)
   1.127 +        return inlineStrCharCodeAt(callInfo);
   1.128 +    if (native == js::str_fromCharCode)
   1.129 +        return inlineStrFromCharCode(callInfo);
   1.130 +    if (native == js_str_charAt)
   1.131 +        return inlineStrCharAt(callInfo);
   1.132 +    if (native == str_replace)
   1.133 +        return inlineStrReplace(callInfo);
   1.134 +
   1.135 +    // RegExp natives.
   1.136 +    if (native == regexp_exec && CallResultEscapes(pc))
   1.137 +        return inlineRegExpExec(callInfo);
   1.138 +    if (native == regexp_exec && !CallResultEscapes(pc))
   1.139 +        return inlineRegExpTest(callInfo);
   1.140 +    if (native == regexp_test)
   1.141 +        return inlineRegExpTest(callInfo);
   1.142 +
   1.143 +    // Array intrinsics.
   1.144 +    if (native == intrinsic_UnsafePutElements)
   1.145 +        return inlineUnsafePutElements(callInfo);
   1.146 +    if (native == intrinsic_NewDenseArray)
   1.147 +        return inlineNewDenseArray(callInfo);
   1.148 +
   1.149 +    // Slot intrinsics.
   1.150 +    if (native == intrinsic_UnsafeSetReservedSlot)
   1.151 +        return inlineUnsafeSetReservedSlot(callInfo);
   1.152 +    if (native == intrinsic_UnsafeGetReservedSlot)
   1.153 +        return inlineUnsafeGetReservedSlot(callInfo);
   1.154 +
   1.155 +    // Parallel intrinsics.
   1.156 +    if (native == intrinsic_ShouldForceSequential ||
   1.157 +        native == intrinsic_InParallelSection)
   1.158 +        return inlineForceSequentialOrInParallelSection(callInfo);
   1.159 +    if (native == intrinsic_ForkJoinGetSlice)
   1.160 +        return inlineForkJoinGetSlice(callInfo);
   1.161 +
   1.162 +    // Utility intrinsics.
   1.163 +    if (native == intrinsic_IsCallable)
   1.164 +        return inlineIsCallable(callInfo);
   1.165 +    if (native == intrinsic_HaveSameClass)
   1.166 +        return inlineHaveSameClass(callInfo);
   1.167 +    if (native == intrinsic_ToObject)
   1.168 +        return inlineToObject(callInfo);
   1.169 +
   1.170 +    // TypedObject intrinsics.
   1.171 +    if (native == intrinsic_ObjectIsTypedObject)
   1.172 +        return inlineHasClasses(callInfo,
   1.173 +                                &TransparentTypedObject::class_, &OpaqueTypedObject::class_);
   1.174 +    if (native == intrinsic_ObjectIsTransparentTypedObject)
   1.175 +        return inlineHasClass(callInfo, &TransparentTypedObject::class_);
   1.176 +    if (native == intrinsic_ObjectIsOpaqueTypedObject)
   1.177 +        return inlineHasClass(callInfo, &OpaqueTypedObject::class_);
   1.178 +    if (native == intrinsic_ObjectIsTypeDescr)
   1.179 +        return inlineObjectIsTypeDescr(callInfo);
   1.180 +    if (native == intrinsic_TypeDescrIsSimpleType)
   1.181 +        return inlineHasClasses(callInfo,
   1.182 +                                &ScalarTypeDescr::class_, &ReferenceTypeDescr::class_);
   1.183 +    if (native == intrinsic_TypeDescrIsArrayType)
   1.184 +        return inlineHasClasses(callInfo,
   1.185 +                                &SizedArrayTypeDescr::class_, &UnsizedArrayTypeDescr::class_);
   1.186 +    if (native == intrinsic_TypeDescrIsSizedArrayType)
   1.187 +        return inlineHasClass(callInfo, &SizedArrayTypeDescr::class_);
   1.188 +    if (native == intrinsic_TypeDescrIsUnsizedArrayType)
   1.189 +        return inlineHasClass(callInfo, &UnsizedArrayTypeDescr::class_);
   1.190 +    if (native == intrinsic_SetTypedObjectOffset)
   1.191 +        return inlineSetTypedObjectOffset(callInfo);
   1.192 +
   1.193 +    // Testing Functions
   1.194 +    if (native == testingFunc_inParallelSection)
   1.195 +        return inlineForceSequentialOrInParallelSection(callInfo);
   1.196 +    if (native == testingFunc_bailout)
   1.197 +        return inlineBailout(callInfo);
   1.198 +    if (native == testingFunc_assertFloat32)
   1.199 +        return inlineAssertFloat32(callInfo);
   1.200 +
   1.201 +    // Bound function
   1.202 +    if (native == js::CallOrConstructBoundFunction)
   1.203 +        return inlineBoundFunction(callInfo, target);
   1.204 +
   1.205 +    return InliningStatus_NotInlined;
   1.206 +}
   1.207 +
   1.208 +types::TemporaryTypeSet *
   1.209 +IonBuilder::getInlineReturnTypeSet()
   1.210 +{
   1.211 +    return bytecodeTypes(pc);
   1.212 +}
   1.213 +
   1.214 +MIRType
   1.215 +IonBuilder::getInlineReturnType()
   1.216 +{
   1.217 +    types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
   1.218 +    return returnTypes->getKnownMIRType();
   1.219 +}
   1.220 +
   1.221 +IonBuilder::InliningStatus
   1.222 +IonBuilder::inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function)
   1.223 +{
   1.224 +    if (callInfo.constructing())
   1.225 +        return InliningStatus_NotInlined;
   1.226 +
   1.227 +    if (callInfo.argc() != 1)
   1.228 +        return InliningStatus_NotInlined;
   1.229 +
   1.230 +    if (getInlineReturnType() != MIRType_Double)
   1.231 +        return InliningStatus_NotInlined;
   1.232 +    if (!IsNumberType(callInfo.getArg(0)->type()))
   1.233 +        return InliningStatus_NotInlined;
   1.234 +
   1.235 +    const MathCache *cache = compartment->runtime()->maybeGetMathCache();
   1.236 +
   1.237 +    callInfo.fun()->setImplicitlyUsedUnchecked();
   1.238 +    callInfo.thisArg()->setImplicitlyUsedUnchecked();
   1.239 +
   1.240 +    MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), function, cache);
   1.241 +    current->add(ins);
   1.242 +    current->push(ins);
   1.243 +    return InliningStatus_Inlined;
   1.244 +}
   1.245 +
   1.246 +IonBuilder::InliningStatus
   1.247 +IonBuilder::inlineArray(CallInfo &callInfo)
   1.248 +{
   1.249 +    uint32_t initLength = 0;
   1.250 +    MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating;
   1.251 +
   1.252 +    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
   1.253 +    if (!templateObject)
   1.254 +        return InliningStatus_NotInlined;
   1.255 +    JS_ASSERT(templateObject->is<ArrayObject>());
   1.256 +
   1.257 +    // Multiple arguments imply array initialization, not just construction.
   1.258 +    if (callInfo.argc() >= 2) {
   1.259 +        initLength = callInfo.argc();
   1.260 +        allocating = MNewArray::NewArray_Allocating;
   1.261 +
   1.262 +        types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject);
   1.263 +        if (!type->unknownProperties()) {
   1.264 +            types::HeapTypeSetKey elemTypes = type->property(JSID_VOID);
   1.265 +
   1.266 +            for (uint32_t i = 0; i < initLength; i++) {
   1.267 +                MDefinition *value = callInfo.getArg(i);
   1.268 +                if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
   1.269 +                    elemTypes.freeze(constraints());
   1.270 +                    return InliningStatus_NotInlined;
   1.271 +                }
   1.272 +            }
   1.273 +        }
   1.274 +    }
   1.275 +
   1.276 +    // A single integer argument denotes initial length.
   1.277 +    if (callInfo.argc() == 1) {
   1.278 +        if (callInfo.getArg(0)->type() != MIRType_Int32)
   1.279 +            return InliningStatus_NotInlined;
   1.280 +        MDefinition *arg = callInfo.getArg(0);
   1.281 +        if (!arg->isConstant())
   1.282 +            return InliningStatus_NotInlined;
   1.283 +
   1.284 +        // Negative lengths generate a RangeError, unhandled by the inline path.
   1.285 +        initLength = arg->toConstant()->value().toInt32();
   1.286 +        if (initLength >= JSObject::NELEMENTS_LIMIT)
   1.287 +            return InliningStatus_NotInlined;
   1.288 +
   1.289 +        // Make sure initLength matches the template object's length. This is
   1.290 +        // not guaranteed to be the case, for instance if we're inlining the
   1.291 +        // MConstant may come from an outer script.
   1.292 +        if (initLength != templateObject->as<ArrayObject>().length())
   1.293 +            return InliningStatus_NotInlined;
   1.294 +
   1.295 +        if (initLength <= ArrayObject::EagerAllocationMaxLength)
   1.296 +            allocating = MNewArray::NewArray_Allocating;
   1.297 +    }
   1.298 +
   1.299 +    callInfo.setImplicitlyUsedUnchecked();
   1.300 +
   1.301 +    types::TemporaryTypeSet::DoubleConversion conversion =
   1.302 +        getInlineReturnTypeSet()->convertDoubleElements(constraints());
   1.303 +    if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
   1.304 +        templateObject->setShouldConvertDoubleElements();
   1.305 +    else
   1.306 +        templateObject->clearShouldConvertDoubleElements();
   1.307 +
   1.308 +    MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateObject,
   1.309 +                                    templateObject->type()->initialHeap(constraints()),
   1.310 +                                    allocating);
   1.311 +    current->add(ins);
   1.312 +    current->push(ins);
   1.313 +
   1.314 +    if (callInfo.argc() >= 2) {
   1.315 +        // Get the elements vector.
   1.316 +        MElements *elements = MElements::New(alloc(), ins);
   1.317 +        current->add(elements);
   1.318 +
   1.319 +        // Store all values, no need to initialize the length after each as
   1.320 +        // jsop_initelem_array is doing because we do not expect to bailout
   1.321 +        // because the memory is supposed to be allocated by now.
   1.322 +        MConstant *id = nullptr;
   1.323 +        for (uint32_t i = 0; i < initLength; i++) {
   1.324 +            id = MConstant::New(alloc(), Int32Value(i));
   1.325 +            current->add(id);
   1.326 +
   1.327 +            MDefinition *value = callInfo.getArg(i);
   1.328 +            if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) {
   1.329 +                MInstruction *valueDouble = MToDouble::New(alloc(), value);
   1.330 +                current->add(valueDouble);
   1.331 +                value = valueDouble;
   1.332 +            }
   1.333 +
   1.334 +            // There is normally no need for a post barrier on these writes
   1.335 +            // because the new array will be in the nursery. However, this
   1.336 +            // assumption is volated if we specifically requested pre-tenuring.
   1.337 +            if (ins->initialHeap() == gc::TenuredHeap)
   1.338 +                current->add(MPostWriteBarrier::New(alloc(), ins, value));
   1.339 +
   1.340 +            MStoreElement *store = MStoreElement::New(alloc(), elements, id, value,
   1.341 +                                                      /* needsHoleCheck = */ false);
   1.342 +            current->add(store);
   1.343 +        }
   1.344 +
   1.345 +        // Update the length.
   1.346 +        MSetInitializedLength *length = MSetInitializedLength::New(alloc(), elements, id);
   1.347 +        current->add(length);
   1.348 +
   1.349 +        if (!resumeAfter(length))
   1.350 +            return InliningStatus_Error;
   1.351 +    }
   1.352 +
   1.353 +    return InliningStatus_Inlined;
   1.354 +}
   1.355 +
   1.356 +IonBuilder::InliningStatus
   1.357 +IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
   1.358 +{
   1.359 +    if (callInfo.constructing())
   1.360 +        return InliningStatus_NotInlined;
   1.361 +
   1.362 +    MIRType returnType = getInlineReturnType();
   1.363 +    if (returnType == MIRType_Undefined || returnType == MIRType_Null)
   1.364 +        return InliningStatus_NotInlined;
   1.365 +    if (callInfo.thisArg()->type() != MIRType_Object)
   1.366 +        return InliningStatus_NotInlined;
   1.367 +
   1.368 +    // Pop and shift are only handled for dense arrays that have never been
   1.369 +    // used in an iterator: popping elements does not account for suppressing
   1.370 +    // deleted properties in active iterators.
   1.371 +    types::TypeObjectFlags unhandledFlags =
   1.372 +        types::OBJECT_FLAG_SPARSE_INDEXES |
   1.373 +        types::OBJECT_FLAG_LENGTH_OVERFLOW |
   1.374 +        types::OBJECT_FLAG_ITERATED;
   1.375 +
   1.376 +    types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
   1.377 +    if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
   1.378 +        return InliningStatus_NotInlined;
   1.379 +    if (thisTypes->hasObjectFlags(constraints(), unhandledFlags))
   1.380 +        return InliningStatus_NotInlined;
   1.381 +
   1.382 +    if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
   1.383 +        return InliningStatus_NotInlined;
   1.384 +
   1.385 +    callInfo.setImplicitlyUsedUnchecked();
   1.386 +
   1.387 +    types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
   1.388 +    bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED);
   1.389 +    bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
   1.390 +
   1.391 +    bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
   1.392 +                                                callInfo.thisArg(), nullptr, returnTypes);
   1.393 +    if (barrier)
   1.394 +        returnType = MIRType_Value;
   1.395 +
   1.396 +    MArrayPopShift *ins = MArrayPopShift::New(alloc(), callInfo.thisArg(), mode,
   1.397 +                                              needsHoleCheck, maybeUndefined);
   1.398 +    current->add(ins);
   1.399 +    current->push(ins);
   1.400 +    ins->setResultType(returnType);
   1.401 +
   1.402 +    if (!resumeAfter(ins))
   1.403 +        return InliningStatus_Error;
   1.404 +
   1.405 +    if (!pushTypeBarrier(ins, returnTypes, barrier))
   1.406 +        return InliningStatus_Error;
   1.407 +
   1.408 +    return InliningStatus_Inlined;
   1.409 +}
   1.410 +
   1.411 +IonBuilder::InliningStatus
   1.412 +IonBuilder::inlineArraySplice(CallInfo &callInfo)
   1.413 +{
   1.414 +    if (callInfo.argc() != 2 || callInfo.constructing())
   1.415 +        return InliningStatus_NotInlined;
   1.416 +
   1.417 +    // Ensure |this|, argument and result are objects.
   1.418 +    if (getInlineReturnType() != MIRType_Object)
   1.419 +        return InliningStatus_NotInlined;
   1.420 +    if (callInfo.thisArg()->type() != MIRType_Object)
   1.421 +        return InliningStatus_NotInlined;
   1.422 +    if (callInfo.getArg(0)->type() != MIRType_Int32)
   1.423 +        return InliningStatus_NotInlined;
   1.424 +    if (callInfo.getArg(1)->type() != MIRType_Int32)
   1.425 +        return InliningStatus_NotInlined;
   1.426 +
   1.427 +    callInfo.setImplicitlyUsedUnchecked();
   1.428 +
   1.429 +    // Specialize arr.splice(start, deleteCount) with unused return value and
   1.430 +    // avoid creating the result array in this case.
   1.431 +    if (!BytecodeIsPopped(pc))
   1.432 +        return InliningStatus_NotInlined;
   1.433 +
   1.434 +    MArraySplice *ins = MArraySplice::New(alloc(),
   1.435 +                                          callInfo.thisArg(),
   1.436 +                                          callInfo.getArg(0),
   1.437 +                                          callInfo.getArg(1));
   1.438 +
   1.439 +    current->add(ins);
   1.440 +    pushConstant(UndefinedValue());
   1.441 +
   1.442 +    if (!resumeAfter(ins))
   1.443 +        return InliningStatus_Error;
   1.444 +    return InliningStatus_Inlined;
   1.445 +}
   1.446 +
   1.447 +IonBuilder::InliningStatus
   1.448 +IonBuilder::inlineArrayPush(CallInfo &callInfo)
   1.449 +{
   1.450 +    if (callInfo.argc() != 1 || callInfo.constructing())
   1.451 +        return InliningStatus_NotInlined;
   1.452 +
   1.453 +    MDefinition *obj = callInfo.thisArg();
   1.454 +    MDefinition *value = callInfo.getArg(0);
   1.455 +    if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
   1.456 +                                      &obj, nullptr, &value, /* canModify = */ false))
   1.457 +    {
   1.458 +        return InliningStatus_NotInlined;
   1.459 +    }
   1.460 +    JS_ASSERT(obj == callInfo.thisArg() && value == callInfo.getArg(0));
   1.461 +
   1.462 +    if (getInlineReturnType() != MIRType_Int32)
   1.463 +        return InliningStatus_NotInlined;
   1.464 +    if (callInfo.thisArg()->type() != MIRType_Object)
   1.465 +        return InliningStatus_NotInlined;
   1.466 +
   1.467 +    types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
   1.468 +    if (!thisTypes || thisTypes->getKnownClass() != &ArrayObject::class_)
   1.469 +        return InliningStatus_NotInlined;
   1.470 +    if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
   1.471 +                                  types::OBJECT_FLAG_LENGTH_OVERFLOW))
   1.472 +    {
   1.473 +        return InliningStatus_NotInlined;
   1.474 +    }
   1.475 +
   1.476 +    if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
   1.477 +        return InliningStatus_NotInlined;
   1.478 +
   1.479 +    types::TemporaryTypeSet::DoubleConversion conversion =
   1.480 +        thisTypes->convertDoubleElements(constraints());
   1.481 +    if (conversion == types::TemporaryTypeSet::AmbiguousDoubleConversion)
   1.482 +        return InliningStatus_NotInlined;
   1.483 +
   1.484 +    callInfo.setImplicitlyUsedUnchecked();
   1.485 +    value = callInfo.getArg(0);
   1.486 +
   1.487 +    if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles ||
   1.488 +        conversion == types::TemporaryTypeSet::MaybeConvertToDoubles)
   1.489 +    {
   1.490 +        MInstruction *valueDouble = MToDouble::New(alloc(), value);
   1.491 +        current->add(valueDouble);
   1.492 +        value = valueDouble;
   1.493 +    }
   1.494 +
   1.495 +    if (NeedsPostBarrier(info(), value))
   1.496 +        current->add(MPostWriteBarrier::New(alloc(), callInfo.thisArg(), value));
   1.497 +
   1.498 +    MArrayPush *ins = MArrayPush::New(alloc(), callInfo.thisArg(), value);
   1.499 +    current->add(ins);
   1.500 +    current->push(ins);
   1.501 +
   1.502 +    if (!resumeAfter(ins))
   1.503 +        return InliningStatus_Error;
   1.504 +    return InliningStatus_Inlined;
   1.505 +}
   1.506 +
   1.507 +IonBuilder::InliningStatus
   1.508 +IonBuilder::inlineArrayConcat(CallInfo &callInfo)
   1.509 +{
   1.510 +    if (callInfo.argc() != 1 || callInfo.constructing())
   1.511 +        return InliningStatus_NotInlined;
   1.512 +
   1.513 +    // Ensure |this|, argument and result are objects.
   1.514 +    if (getInlineReturnType() != MIRType_Object)
   1.515 +        return InliningStatus_NotInlined;
   1.516 +    if (callInfo.thisArg()->type() != MIRType_Object)
   1.517 +        return InliningStatus_NotInlined;
   1.518 +    if (callInfo.getArg(0)->type() != MIRType_Object)
   1.519 +        return InliningStatus_NotInlined;
   1.520 +
   1.521 +    // |this| and the argument must be dense arrays.
   1.522 +    types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
   1.523 +    types::TemporaryTypeSet *argTypes = callInfo.getArg(0)->resultTypeSet();
   1.524 +    if (!thisTypes || !argTypes)
   1.525 +        return InliningStatus_NotInlined;
   1.526 +
   1.527 +    if (thisTypes->getKnownClass() != &ArrayObject::class_)
   1.528 +        return InliningStatus_NotInlined;
   1.529 +    if (thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
   1.530 +                                  types::OBJECT_FLAG_LENGTH_OVERFLOW))
   1.531 +    {
   1.532 +        return InliningStatus_NotInlined;
   1.533 +    }
   1.534 +
   1.535 +    if (argTypes->getKnownClass() != &ArrayObject::class_)
   1.536 +        return InliningStatus_NotInlined;
   1.537 +    if (argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_SPARSE_INDEXES |
   1.538 +                                 types::OBJECT_FLAG_LENGTH_OVERFLOW))
   1.539 +    {
   1.540 +        return InliningStatus_NotInlined;
   1.541 +    }
   1.542 +
   1.543 +    // Watch out for indexed properties on the prototype.
   1.544 +    if (types::ArrayPrototypeHasIndexedProperty(constraints(), script()))
   1.545 +        return InliningStatus_NotInlined;
   1.546 +
   1.547 +    // Require the 'this' types to have a specific type matching the current
   1.548 +    // global, so we can create the result object inline.
   1.549 +    if (thisTypes->getObjectCount() != 1)
   1.550 +        return InliningStatus_NotInlined;
   1.551 +
   1.552 +    types::TypeObject *baseThisType = thisTypes->getTypeObject(0);
   1.553 +    if (!baseThisType)
   1.554 +        return InliningStatus_NotInlined;
   1.555 +    types::TypeObjectKey *thisType = types::TypeObjectKey::get(baseThisType);
   1.556 +    if (thisType->unknownProperties())
   1.557 +        return InliningStatus_NotInlined;
   1.558 +
   1.559 +    // Don't inline if 'this' is packed and the argument may not be packed
   1.560 +    // (the result array will reuse the 'this' type).
   1.561 +    if (!thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED) &&
   1.562 +        argTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED))
   1.563 +    {
   1.564 +        return InliningStatus_NotInlined;
   1.565 +    }
   1.566 +
   1.567 +    // Constraints modeling this concat have not been generated by inference,
   1.568 +    // so check that type information already reflects possible side effects of
   1.569 +    // this call.
   1.570 +    types::HeapTypeSetKey thisElemTypes = thisType->property(JSID_VOID);
   1.571 +
   1.572 +    types::TemporaryTypeSet *resTypes = getInlineReturnTypeSet();
   1.573 +    if (!resTypes->hasType(types::Type::ObjectType(thisType)))
   1.574 +        return InliningStatus_NotInlined;
   1.575 +
   1.576 +    for (unsigned i = 0; i < argTypes->getObjectCount(); i++) {
   1.577 +        types::TypeObjectKey *argType = argTypes->getObject(i);
   1.578 +        if (!argType)
   1.579 +            continue;
   1.580 +
   1.581 +        if (argType->unknownProperties())
   1.582 +            return InliningStatus_NotInlined;
   1.583 +
   1.584 +        types::HeapTypeSetKey elemTypes = argType->property(JSID_VOID);
   1.585 +        if (!elemTypes.knownSubset(constraints(), thisElemTypes))
   1.586 +            return InliningStatus_NotInlined;
   1.587 +    }
   1.588 +
   1.589 +    // Inline the call.
   1.590 +    JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
   1.591 +    if (!templateObj || templateObj->type() != baseThisType)
   1.592 +        return InliningStatus_NotInlined;
   1.593 +    JS_ASSERT(templateObj->is<ArrayObject>());
   1.594 +
   1.595 +    callInfo.setImplicitlyUsedUnchecked();
   1.596 +
   1.597 +    MArrayConcat *ins = MArrayConcat::New(alloc(), constraints(), callInfo.thisArg(), callInfo.getArg(0),
   1.598 +                                          templateObj, templateObj->type()->initialHeap(constraints()));
   1.599 +    current->add(ins);
   1.600 +    current->push(ins);
   1.601 +
   1.602 +    if (!resumeAfter(ins))
   1.603 +        return InliningStatus_Error;
   1.604 +    return InliningStatus_Inlined;
   1.605 +}
   1.606 +
   1.607 +IonBuilder::InliningStatus
   1.608 +IonBuilder::inlineMathAbs(CallInfo &callInfo)
   1.609 +{
   1.610 +    if (callInfo.constructing())
   1.611 +        return InliningStatus_NotInlined;
   1.612 +
   1.613 +    if (callInfo.argc() != 1)
   1.614 +        return InliningStatus_NotInlined;
   1.615 +
   1.616 +    MIRType returnType = getInlineReturnType();
   1.617 +    MIRType argType = callInfo.getArg(0)->type();
   1.618 +    if (!IsNumberType(argType))
   1.619 +        return InliningStatus_NotInlined;
   1.620 +
   1.621 +    // Either argType == returnType, or
   1.622 +    //        argType == Double or Float32, returnType == Int, or
   1.623 +    //        argType == Float32, returnType == Double
   1.624 +    if (argType != returnType && !(IsFloatingPointType(argType) && returnType == MIRType_Int32)
   1.625 +        && !(argType == MIRType_Float32 && returnType == MIRType_Double))
   1.626 +    {
   1.627 +        return InliningStatus_NotInlined;
   1.628 +    }
   1.629 +
   1.630 +    callInfo.setImplicitlyUsedUnchecked();
   1.631 +
   1.632 +    // If the arg is a Float32, we specialize the op as double, it will be specialized
   1.633 +    // as float32 if necessary later.
   1.634 +    MIRType absType = (argType == MIRType_Float32) ? MIRType_Double : argType;
   1.635 +    MInstruction *ins = MAbs::New(alloc(), callInfo.getArg(0), absType);
   1.636 +    current->add(ins);
   1.637 +
   1.638 +    current->push(ins);
   1.639 +    return InliningStatus_Inlined;
   1.640 +}
   1.641 +
   1.642 +IonBuilder::InliningStatus
   1.643 +IonBuilder::inlineMathFloor(CallInfo &callInfo)
   1.644 +{
   1.645 +    if (callInfo.constructing())
   1.646 +        return InliningStatus_NotInlined;
   1.647 +
   1.648 +    if (callInfo.argc() != 1)
   1.649 +        return InliningStatus_NotInlined;
   1.650 +
   1.651 +    MIRType argType = callInfo.getArg(0)->type();
   1.652 +    MIRType returnType = getInlineReturnType();
   1.653 +
   1.654 +    // Math.floor(int(x)) == int(x)
   1.655 +    if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
   1.656 +        callInfo.setImplicitlyUsedUnchecked();
   1.657 +        current->push(callInfo.getArg(0));
   1.658 +        return InliningStatus_Inlined;
   1.659 +    }
   1.660 +
   1.661 +    if (IsFloatingPointType(argType) && returnType == MIRType_Int32) {
   1.662 +        callInfo.setImplicitlyUsedUnchecked();
   1.663 +        MFloor *ins = MFloor::New(alloc(), callInfo.getArg(0));
   1.664 +        current->add(ins);
   1.665 +        current->push(ins);
   1.666 +        return InliningStatus_Inlined;
   1.667 +    }
   1.668 +
   1.669 +    if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
   1.670 +        callInfo.setImplicitlyUsedUnchecked();
   1.671 +        MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor, nullptr);
   1.672 +        current->add(ins);
   1.673 +        current->push(ins);
   1.674 +        return InliningStatus_Inlined;
   1.675 +    }
   1.676 +
   1.677 +    return InliningStatus_NotInlined;
   1.678 +}
   1.679 +
   1.680 +IonBuilder::InliningStatus
   1.681 +IonBuilder::inlineMathCeil(CallInfo &callInfo)
   1.682 +{
   1.683 +    if (callInfo.constructing())
   1.684 +        return InliningStatus_NotInlined;
   1.685 +
   1.686 +    if (callInfo.argc() != 1)
   1.687 +        return InliningStatus_NotInlined;
   1.688 +
   1.689 +    MIRType argType = callInfo.getArg(0)->type();
   1.690 +    MIRType returnType = getInlineReturnType();
   1.691 +
   1.692 +    // Math.ceil(int(x)) == int(x)
   1.693 +    if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
   1.694 +        callInfo.setImplicitlyUsedUnchecked();
   1.695 +        current->push(callInfo.getArg(0));
   1.696 +        return InliningStatus_Inlined;
   1.697 +    }
   1.698 +
   1.699 +    if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
   1.700 +        callInfo.setImplicitlyUsedUnchecked();
   1.701 +        MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil, nullptr);
   1.702 +        current->add(ins);
   1.703 +        current->push(ins);
   1.704 +        return InliningStatus_Inlined;
   1.705 +    }
   1.706 +
   1.707 +    return InliningStatus_NotInlined;
   1.708 +}
   1.709 +
   1.710 +IonBuilder::InliningStatus
   1.711 +IonBuilder::inlineMathRound(CallInfo &callInfo)
   1.712 +{
   1.713 +    if (callInfo.constructing())
   1.714 +        return InliningStatus_NotInlined;
   1.715 +
   1.716 +    if (callInfo.argc() != 1)
   1.717 +        return InliningStatus_NotInlined;
   1.718 +
   1.719 +    MIRType returnType = getInlineReturnType();
   1.720 +    MIRType argType = callInfo.getArg(0)->type();
   1.721 +
   1.722 +    // Math.round(int(x)) == int(x)
   1.723 +    if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
   1.724 +        callInfo.setImplicitlyUsedUnchecked();
   1.725 +        current->push(callInfo.getArg(0));
   1.726 +        return InliningStatus_Inlined;
   1.727 +    }
   1.728 +
   1.729 +    if (IsFloatingPointType(argType) && returnType == MIRType_Int32) {
   1.730 +        callInfo.setImplicitlyUsedUnchecked();
   1.731 +        MRound *ins = MRound::New(alloc(), callInfo.getArg(0));
   1.732 +        current->add(ins);
   1.733 +        current->push(ins);
   1.734 +        return InliningStatus_Inlined;
   1.735 +    }
   1.736 +
   1.737 +    if (IsFloatingPointType(argType) && returnType == MIRType_Double) {
   1.738 +        callInfo.setImplicitlyUsedUnchecked();
   1.739 +        MMathFunction *ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round, nullptr);
   1.740 +        current->add(ins);
   1.741 +        current->push(ins);
   1.742 +        return InliningStatus_Inlined;
   1.743 +    }
   1.744 +
   1.745 +    return InliningStatus_NotInlined;
   1.746 +}
   1.747 +
   1.748 +IonBuilder::InliningStatus
   1.749 +IonBuilder::inlineMathSqrt(CallInfo &callInfo)
   1.750 +{
   1.751 +    if (callInfo.constructing())
   1.752 +        return InliningStatus_NotInlined;
   1.753 +
   1.754 +    if (callInfo.argc() != 1)
   1.755 +        return InliningStatus_NotInlined;
   1.756 +
   1.757 +    MIRType argType = callInfo.getArg(0)->type();
   1.758 +    if (getInlineReturnType() != MIRType_Double)
   1.759 +        return InliningStatus_NotInlined;
   1.760 +    if (!IsNumberType(argType))
   1.761 +        return InliningStatus_NotInlined;
   1.762 +
   1.763 +    callInfo.setImplicitlyUsedUnchecked();
   1.764 +
   1.765 +    MSqrt *sqrt = MSqrt::New(alloc(), callInfo.getArg(0));
   1.766 +    current->add(sqrt);
   1.767 +    current->push(sqrt);
   1.768 +    return InliningStatus_Inlined;
   1.769 +}
   1.770 +
   1.771 +IonBuilder::InliningStatus
   1.772 +IonBuilder::inlineMathAtan2(CallInfo &callInfo)
   1.773 +{
   1.774 +    if (callInfo.constructing())
   1.775 +        return InliningStatus_NotInlined;
   1.776 +
   1.777 +    if (callInfo.argc() != 2)
   1.778 +        return InliningStatus_NotInlined;
   1.779 +
   1.780 +    if (getInlineReturnType() != MIRType_Double)
   1.781 +        return InliningStatus_NotInlined;
   1.782 +
   1.783 +    MIRType argType0 = callInfo.getArg(0)->type();
   1.784 +    MIRType argType1 = callInfo.getArg(1)->type();
   1.785 +
   1.786 +    if (!IsNumberType(argType0) || !IsNumberType(argType1))
   1.787 +        return InliningStatus_NotInlined;
   1.788 +
   1.789 +    callInfo.setImplicitlyUsedUnchecked();
   1.790 +
   1.791 +    MAtan2 *atan2 = MAtan2::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
   1.792 +    current->add(atan2);
   1.793 +    current->push(atan2);
   1.794 +    return InliningStatus_Inlined;
   1.795 +}
   1.796 +
   1.797 +IonBuilder::InliningStatus
   1.798 +IonBuilder::inlineMathHypot(CallInfo &callInfo)
   1.799 +{
   1.800 +    if (callInfo.constructing())
   1.801 +        return InliningStatus_NotInlined;
   1.802 +
   1.803 +    if (callInfo.argc() != 2)
   1.804 +        return InliningStatus_NotInlined;
   1.805 +
   1.806 +    if (getInlineReturnType() != MIRType_Double)
   1.807 +        return InliningStatus_NotInlined;
   1.808 +
   1.809 +    MIRType argType0 = callInfo.getArg(0)->type();
   1.810 +    MIRType argType1 = callInfo.getArg(1)->type();
   1.811 +
   1.812 +    if (!IsNumberType(argType0) || !IsNumberType(argType1))
   1.813 +        return InliningStatus_NotInlined;
   1.814 +
   1.815 +    callInfo.setImplicitlyUsedUnchecked();
   1.816 +
   1.817 +    MHypot *hypot = MHypot::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
   1.818 +    current->add(hypot);
   1.819 +    current->push(hypot);
   1.820 +    return InliningStatus_Inlined;
   1.821 +}
   1.822 +
   1.823 +IonBuilder::InliningStatus
   1.824 +IonBuilder::inlineMathPow(CallInfo &callInfo)
   1.825 +{
   1.826 +    if (callInfo.constructing())
   1.827 +        return InliningStatus_NotInlined;
   1.828 +
   1.829 +    if (callInfo.argc() != 2)
   1.830 +        return InliningStatus_NotInlined;
   1.831 +
   1.832 +    // Typechecking.
   1.833 +    MIRType baseType = callInfo.getArg(0)->type();
   1.834 +    MIRType powerType = callInfo.getArg(1)->type();
   1.835 +    MIRType outputType = getInlineReturnType();
   1.836 +
   1.837 +    if (outputType != MIRType_Int32 && outputType != MIRType_Double)
   1.838 +        return InliningStatus_NotInlined;
   1.839 +    if (!IsNumberType(baseType))
   1.840 +        return InliningStatus_NotInlined;
   1.841 +    if (!IsNumberType(powerType))
   1.842 +        return InliningStatus_NotInlined;
   1.843 +
   1.844 +    callInfo.setImplicitlyUsedUnchecked();
   1.845 +
   1.846 +    MDefinition *base = callInfo.getArg(0);
   1.847 +    MDefinition *power = callInfo.getArg(1);
   1.848 +    MDefinition *output = nullptr;
   1.849 +
   1.850 +    // Optimize some constant powers.
   1.851 +    if (callInfo.getArg(1)->isConstant() &&
   1.852 +        callInfo.getArg(1)->toConstant()->value().isNumber())
   1.853 +    {
   1.854 +        double pow = callInfo.getArg(1)->toConstant()->value().toNumber();
   1.855 +
   1.856 +        // Math.pow(x, 0.5) is a sqrt with edge-case detection.
   1.857 +        if (pow == 0.5) {
   1.858 +            MPowHalf *half = MPowHalf::New(alloc(), base);
   1.859 +            current->add(half);
   1.860 +            output = half;
   1.861 +        }
   1.862 +
   1.863 +        // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
   1.864 +        if (pow == -0.5) {
   1.865 +            MPowHalf *half = MPowHalf::New(alloc(), base);
   1.866 +            current->add(half);
   1.867 +            MConstant *one = MConstant::New(alloc(), DoubleValue(1.0));
   1.868 +            current->add(one);
   1.869 +            MDiv *div = MDiv::New(alloc(), one, half, MIRType_Double);
   1.870 +            current->add(div);
   1.871 +            output = div;
   1.872 +        }
   1.873 +
   1.874 +        // Math.pow(x, 1) == x.
   1.875 +        if (pow == 1.0)
   1.876 +            output = base;
   1.877 +
   1.878 +        // Math.pow(x, 2) == x*x.
   1.879 +        if (pow == 2.0) {
   1.880 +            MMul *mul = MMul::New(alloc(), base, base, outputType);
   1.881 +            current->add(mul);
   1.882 +            output = mul;
   1.883 +        }
   1.884 +
   1.885 +        // Math.pow(x, 3) == x*x*x.
   1.886 +        if (pow == 3.0) {
   1.887 +            MMul *mul1 = MMul::New(alloc(), base, base, outputType);
   1.888 +            current->add(mul1);
   1.889 +            MMul *mul2 = MMul::New(alloc(), base, mul1, outputType);
   1.890 +            current->add(mul2);
   1.891 +            output = mul2;
   1.892 +        }
   1.893 +
   1.894 +        // Math.pow(x, 4) == y*y, where y = x*x.
   1.895 +        if (pow == 4.0) {
   1.896 +            MMul *y = MMul::New(alloc(), base, base, outputType);
   1.897 +            current->add(y);
   1.898 +            MMul *mul = MMul::New(alloc(), y, y, outputType);
   1.899 +            current->add(mul);
   1.900 +            output = mul;
   1.901 +        }
   1.902 +    }
   1.903 +
   1.904 +    // Use MPow for other powers
   1.905 +    if (!output) {
   1.906 +        if (powerType == MIRType_Float32)
   1.907 +            powerType = MIRType_Double;
   1.908 +        MPow *pow = MPow::New(alloc(), base, power, powerType);
   1.909 +        current->add(pow);
   1.910 +        output = pow;
   1.911 +    }
   1.912 +
   1.913 +    // Cast to the right type
   1.914 +    if (outputType == MIRType_Int32 && output->type() != MIRType_Int32) {
   1.915 +        MToInt32 *toInt = MToInt32::New(alloc(), output);
   1.916 +        current->add(toInt);
   1.917 +        output = toInt;
   1.918 +    }
   1.919 +    if (outputType == MIRType_Double && output->type() != MIRType_Double) {
   1.920 +        MToDouble *toDouble = MToDouble::New(alloc(), output);
   1.921 +        current->add(toDouble);
   1.922 +        output = toDouble;
   1.923 +    }
   1.924 +
   1.925 +    current->push(output);
   1.926 +    return InliningStatus_Inlined;
   1.927 +}
   1.928 +
   1.929 +IonBuilder::InliningStatus
   1.930 +IonBuilder::inlineMathRandom(CallInfo &callInfo)
   1.931 +{
   1.932 +    if (callInfo.constructing())
   1.933 +        return InliningStatus_NotInlined;
   1.934 +
   1.935 +    if (getInlineReturnType() != MIRType_Double)
   1.936 +        return InliningStatus_NotInlined;
   1.937 +
   1.938 +    callInfo.setImplicitlyUsedUnchecked();
   1.939 +
   1.940 +    MRandom *rand = MRandom::New(alloc());
   1.941 +    current->add(rand);
   1.942 +    current->push(rand);
   1.943 +    return InliningStatus_Inlined;
   1.944 +}
   1.945 +
   1.946 +IonBuilder::InliningStatus
   1.947 +IonBuilder::inlineMathImul(CallInfo &callInfo)
   1.948 +{
   1.949 +    if (callInfo.argc() != 2 || callInfo.constructing())
   1.950 +        return InliningStatus_NotInlined;
   1.951 +
   1.952 +    MIRType returnType = getInlineReturnType();
   1.953 +    if (returnType != MIRType_Int32)
   1.954 +        return InliningStatus_NotInlined;
   1.955 +
   1.956 +    if (!IsNumberType(callInfo.getArg(0)->type()))
   1.957 +        return InliningStatus_NotInlined;
   1.958 +    if (!IsNumberType(callInfo.getArg(1)->type()))
   1.959 +        return InliningStatus_NotInlined;
   1.960 +
   1.961 +    callInfo.setImplicitlyUsedUnchecked();
   1.962 +
   1.963 +    MInstruction *first = MTruncateToInt32::New(alloc(), callInfo.getArg(0));
   1.964 +    current->add(first);
   1.965 +
   1.966 +    MInstruction *second = MTruncateToInt32::New(alloc(), callInfo.getArg(1));
   1.967 +    current->add(second);
   1.968 +
   1.969 +    MMul *ins = MMul::New(alloc(), first, second, MIRType_Int32, MMul::Integer);
   1.970 +    current->add(ins);
   1.971 +    current->push(ins);
   1.972 +    return InliningStatus_Inlined;
   1.973 +}
   1.974 +
   1.975 +IonBuilder::InliningStatus
   1.976 +IonBuilder::inlineMathFRound(CallInfo &callInfo)
   1.977 +{
   1.978 +    if (!LIRGenerator::allowFloat32Optimizations())
   1.979 +        return InliningStatus_NotInlined;
   1.980 +
   1.981 +    if (callInfo.argc() != 1 || callInfo.constructing())
   1.982 +        return InliningStatus_NotInlined;
   1.983 +
   1.984 +    // MIRType can't be Float32, as this point, as getInlineReturnType uses JSVal types
   1.985 +    // to infer the returned MIR type.
   1.986 +    types::TemporaryTypeSet *returned = getInlineReturnTypeSet();
   1.987 +    if (returned->empty()) {
   1.988 +        // As there's only one possible returned type, just add it to the observed
   1.989 +        // returned typeset
   1.990 +        returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
   1.991 +    } else {
   1.992 +        MIRType returnType = getInlineReturnType();
   1.993 +        if (!IsNumberType(returnType))
   1.994 +            return InliningStatus_NotInlined;
   1.995 +    }
   1.996 +
   1.997 +    MIRType arg = callInfo.getArg(0)->type();
   1.998 +    if (!IsNumberType(arg))
   1.999 +        return InliningStatus_NotInlined;
  1.1000 +
  1.1001 +    callInfo.setImplicitlyUsedUnchecked();
  1.1002 +
  1.1003 +    MToFloat32 *ins = MToFloat32::New(alloc(), callInfo.getArg(0));
  1.1004 +    current->add(ins);
  1.1005 +    current->push(ins);
  1.1006 +    return InliningStatus_Inlined;
  1.1007 +}
  1.1008 +
  1.1009 +IonBuilder::InliningStatus
  1.1010 +IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
  1.1011 +{
  1.1012 +    if (callInfo.argc() < 2 || callInfo.constructing())
  1.1013 +        return InliningStatus_NotInlined;
  1.1014 +
  1.1015 +    MIRType returnType = getInlineReturnType();
  1.1016 +    if (!IsNumberType(returnType))
  1.1017 +        return InliningStatus_NotInlined;
  1.1018 +
  1.1019 +    for (unsigned i = 0; i < callInfo.argc(); i++) {
  1.1020 +        MIRType argType = callInfo.getArg(i)->type();
  1.1021 +        if (!IsNumberType(argType))
  1.1022 +            return InliningStatus_NotInlined;
  1.1023 +
  1.1024 +        // When one of the arguments is double, do a double MMinMax.
  1.1025 +        if (returnType == MIRType_Int32 && IsFloatingPointType(argType))
  1.1026 +            returnType = MIRType_Double;
  1.1027 +    }
  1.1028 +
  1.1029 +    callInfo.setImplicitlyUsedUnchecked();
  1.1030 +
  1.1031 +    // Chain N-1 MMinMax instructions to compute the MinMax.
  1.1032 +    MMinMax *last = MMinMax::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), returnType, max);
  1.1033 +    current->add(last);
  1.1034 +
  1.1035 +    for (unsigned i = 2; i < callInfo.argc(); i++) {
  1.1036 +        MMinMax *ins = MMinMax::New(alloc(), last, callInfo.getArg(i), returnType, max);
  1.1037 +        current->add(ins);
  1.1038 +        last = ins;
  1.1039 +    }
  1.1040 +
  1.1041 +    current->push(last);
  1.1042 +    return InliningStatus_Inlined;
  1.1043 +}
  1.1044 +
  1.1045 +IonBuilder::InliningStatus
  1.1046 +IonBuilder::inlineStringObject(CallInfo &callInfo)
  1.1047 +{
  1.1048 +    if (callInfo.argc() != 1 || !callInfo.constructing())
  1.1049 +        return InliningStatus_NotInlined;
  1.1050 +
  1.1051 +    // ConvertToString doesn't support objects.
  1.1052 +    if (callInfo.getArg(0)->mightBeType(MIRType_Object))
  1.1053 +        return InliningStatus_NotInlined;
  1.1054 +
  1.1055 +    JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js_String);
  1.1056 +    if (!templateObj)
  1.1057 +        return InliningStatus_NotInlined;
  1.1058 +    JS_ASSERT(templateObj->is<StringObject>());
  1.1059 +
  1.1060 +    callInfo.setImplicitlyUsedUnchecked();
  1.1061 +
  1.1062 +    MNewStringObject *ins = MNewStringObject::New(alloc(), callInfo.getArg(0), templateObj);
  1.1063 +    current->add(ins);
  1.1064 +    current->push(ins);
  1.1065 +
  1.1066 +    if (!resumeAfter(ins))
  1.1067 +        return InliningStatus_Error;
  1.1068 +
  1.1069 +    return InliningStatus_Inlined;
  1.1070 +}
  1.1071 +
  1.1072 +IonBuilder::InliningStatus
  1.1073 +IonBuilder::inlineStringSplit(CallInfo &callInfo)
  1.1074 +{
  1.1075 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1076 +        return InliningStatus_NotInlined;
  1.1077 +    if (callInfo.thisArg()->type() != MIRType_String)
  1.1078 +        return InliningStatus_NotInlined;
  1.1079 +    if (callInfo.getArg(0)->type() != MIRType_String)
  1.1080 +        return InliningStatus_NotInlined;
  1.1081 +
  1.1082 +    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js::str_split);
  1.1083 +    if (!templateObject)
  1.1084 +        return InliningStatus_NotInlined;
  1.1085 +    JS_ASSERT(templateObject->is<ArrayObject>());
  1.1086 +
  1.1087 +    types::TypeObjectKey *retType = types::TypeObjectKey::get(templateObject);
  1.1088 +    if (retType->unknownProperties())
  1.1089 +        return InliningStatus_NotInlined;
  1.1090 +
  1.1091 +    types::HeapTypeSetKey key = retType->property(JSID_VOID);
  1.1092 +    if (!key.maybeTypes())
  1.1093 +        return InliningStatus_NotInlined;
  1.1094 +
  1.1095 +    if (!key.maybeTypes()->hasType(types::Type::StringType())) {
  1.1096 +        key.freeze(constraints());
  1.1097 +        return InliningStatus_NotInlined;
  1.1098 +    }
  1.1099 +
  1.1100 +    callInfo.setImplicitlyUsedUnchecked();
  1.1101 +
  1.1102 +    MStringSplit *ins = MStringSplit::New(alloc(), constraints(), callInfo.thisArg(),
  1.1103 +                                          callInfo.getArg(0), templateObject);
  1.1104 +    current->add(ins);
  1.1105 +    current->push(ins);
  1.1106 +
  1.1107 +    return InliningStatus_Inlined;
  1.1108 +}
  1.1109 +
  1.1110 +IonBuilder::InliningStatus
  1.1111 +IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
  1.1112 +{
  1.1113 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1114 +        return InliningStatus_NotInlined;
  1.1115 +
  1.1116 +    if (getInlineReturnType() != MIRType_Int32)
  1.1117 +        return InliningStatus_NotInlined;
  1.1118 +    if (callInfo.thisArg()->type() != MIRType_String && callInfo.thisArg()->type() != MIRType_Value)
  1.1119 +        return InliningStatus_NotInlined;
  1.1120 +    MIRType argType = callInfo.getArg(0)->type();
  1.1121 +    if (argType != MIRType_Int32 && argType != MIRType_Double)
  1.1122 +        return InliningStatus_NotInlined;
  1.1123 +
  1.1124 +    callInfo.setImplicitlyUsedUnchecked();
  1.1125 +
  1.1126 +    MInstruction *index = MToInt32::New(alloc(), callInfo.getArg(0));
  1.1127 +    current->add(index);
  1.1128 +
  1.1129 +    MStringLength *length = MStringLength::New(alloc(), callInfo.thisArg());
  1.1130 +    current->add(length);
  1.1131 +
  1.1132 +    index = addBoundsCheck(index, length);
  1.1133 +
  1.1134 +    MCharCodeAt *charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
  1.1135 +    current->add(charCode);
  1.1136 +    current->push(charCode);
  1.1137 +    return InliningStatus_Inlined;
  1.1138 +}
  1.1139 +
  1.1140 +IonBuilder::InliningStatus
  1.1141 +IonBuilder::inlineStrFromCharCode(CallInfo &callInfo)
  1.1142 +{
  1.1143 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1144 +        return InliningStatus_NotInlined;
  1.1145 +
  1.1146 +    if (getInlineReturnType() != MIRType_String)
  1.1147 +        return InliningStatus_NotInlined;
  1.1148 +    if (callInfo.getArg(0)->type() != MIRType_Int32)
  1.1149 +        return InliningStatus_NotInlined;
  1.1150 +
  1.1151 +    callInfo.setImplicitlyUsedUnchecked();
  1.1152 +
  1.1153 +    MToInt32 *charCode = MToInt32::New(alloc(), callInfo.getArg(0));
  1.1154 +    current->add(charCode);
  1.1155 +
  1.1156 +    MFromCharCode *string = MFromCharCode::New(alloc(), charCode);
  1.1157 +    current->add(string);
  1.1158 +    current->push(string);
  1.1159 +    return InliningStatus_Inlined;
  1.1160 +}
  1.1161 +
  1.1162 +IonBuilder::InliningStatus
  1.1163 +IonBuilder::inlineStrCharAt(CallInfo &callInfo)
  1.1164 +{
  1.1165 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1166 +        return InliningStatus_NotInlined;
  1.1167 +
  1.1168 +    if (getInlineReturnType() != MIRType_String)
  1.1169 +        return InliningStatus_NotInlined;
  1.1170 +    if (callInfo.thisArg()->type() != MIRType_String)
  1.1171 +        return InliningStatus_NotInlined;
  1.1172 +    MIRType argType = callInfo.getArg(0)->type();
  1.1173 +    if (argType != MIRType_Int32 && argType != MIRType_Double)
  1.1174 +        return InliningStatus_NotInlined;
  1.1175 +
  1.1176 +    callInfo.setImplicitlyUsedUnchecked();
  1.1177 +
  1.1178 +    MInstruction *index = MToInt32::New(alloc(), callInfo.getArg(0));
  1.1179 +    current->add(index);
  1.1180 +
  1.1181 +    MStringLength *length = MStringLength::New(alloc(), callInfo.thisArg());
  1.1182 +    current->add(length);
  1.1183 +
  1.1184 +    index = addBoundsCheck(index, length);
  1.1185 +
  1.1186 +    // String.charAt(x) = String.fromCharCode(String.charCodeAt(x))
  1.1187 +    MCharCodeAt *charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
  1.1188 +    current->add(charCode);
  1.1189 +
  1.1190 +    MFromCharCode *string = MFromCharCode::New(alloc(), charCode);
  1.1191 +    current->add(string);
  1.1192 +    current->push(string);
  1.1193 +    return InliningStatus_Inlined;
  1.1194 +}
  1.1195 +
  1.1196 +IonBuilder::InliningStatus
  1.1197 +IonBuilder::inlineRegExpExec(CallInfo &callInfo)
  1.1198 +{
  1.1199 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1200 +        return InliningStatus_NotInlined;
  1.1201 +
  1.1202 +    if (callInfo.thisArg()->type() != MIRType_Object)
  1.1203 +        return InliningStatus_NotInlined;
  1.1204 +
  1.1205 +    types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
  1.1206 +    const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr;
  1.1207 +    if (clasp != &RegExpObject::class_)
  1.1208 +        return InliningStatus_NotInlined;
  1.1209 +
  1.1210 +    if (callInfo.getArg(0)->mightBeType(MIRType_Object))
  1.1211 +        return InliningStatus_NotInlined;
  1.1212 +
  1.1213 +    callInfo.setImplicitlyUsedUnchecked();
  1.1214 +
  1.1215 +    MInstruction *exec = MRegExpExec::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
  1.1216 +    current->add(exec);
  1.1217 +    current->push(exec);
  1.1218 +
  1.1219 +    if (!resumeAfter(exec))
  1.1220 +        return InliningStatus_Error;
  1.1221 +
  1.1222 +    if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), true))
  1.1223 +        return InliningStatus_Error;
  1.1224 +
  1.1225 +    return InliningStatus_Inlined;
  1.1226 +}
  1.1227 +
  1.1228 +IonBuilder::InliningStatus
  1.1229 +IonBuilder::inlineRegExpTest(CallInfo &callInfo)
  1.1230 +{
  1.1231 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1232 +        return InliningStatus_NotInlined;
  1.1233 +
  1.1234 +    // TI can infer a nullptr return type of regexp_test with eager compilation.
  1.1235 +    if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean)
  1.1236 +        return InliningStatus_NotInlined;
  1.1237 +
  1.1238 +    if (callInfo.thisArg()->type() != MIRType_Object)
  1.1239 +        return InliningStatus_NotInlined;
  1.1240 +    types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
  1.1241 +    const Class *clasp = thisTypes ? thisTypes->getKnownClass() : nullptr;
  1.1242 +    if (clasp != &RegExpObject::class_)
  1.1243 +        return InliningStatus_NotInlined;
  1.1244 +    if (callInfo.getArg(0)->mightBeType(MIRType_Object))
  1.1245 +        return InliningStatus_NotInlined;
  1.1246 +
  1.1247 +    callInfo.setImplicitlyUsedUnchecked();
  1.1248 +
  1.1249 +    MInstruction *match = MRegExpTest::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
  1.1250 +    current->add(match);
  1.1251 +    current->push(match);
  1.1252 +    if (!resumeAfter(match))
  1.1253 +        return InliningStatus_Error;
  1.1254 +
  1.1255 +    return InliningStatus_Inlined;
  1.1256 +}
  1.1257 +
  1.1258 +IonBuilder::InliningStatus
  1.1259 +IonBuilder::inlineStrReplace(CallInfo &callInfo)
  1.1260 +{
  1.1261 +    if (callInfo.argc() != 2 || callInfo.constructing())
  1.1262 +        return InliningStatus_NotInlined;
  1.1263 +
  1.1264 +    // Return: String.
  1.1265 +    if (getInlineReturnType() != MIRType_String)
  1.1266 +        return InliningStatus_NotInlined;
  1.1267 +
  1.1268 +    // This: String.
  1.1269 +    if (callInfo.thisArg()->type() != MIRType_String)
  1.1270 +        return InliningStatus_NotInlined;
  1.1271 +
  1.1272 +    // Arg 0: RegExp.
  1.1273 +    types::TemporaryTypeSet *arg0Type = callInfo.getArg(0)->resultTypeSet();
  1.1274 +    const Class *clasp = arg0Type ? arg0Type->getKnownClass() : nullptr;
  1.1275 +    if (clasp != &RegExpObject::class_ && callInfo.getArg(0)->type() != MIRType_String)
  1.1276 +        return InliningStatus_NotInlined;
  1.1277 +
  1.1278 +    // Arg 1: String.
  1.1279 +    if (callInfo.getArg(1)->type() != MIRType_String)
  1.1280 +        return InliningStatus_NotInlined;
  1.1281 +
  1.1282 +    callInfo.setImplicitlyUsedUnchecked();
  1.1283 +
  1.1284 +    MInstruction *cte;
  1.1285 +    if (callInfo.getArg(0)->type() == MIRType_String) {
  1.1286 +        cte = MStringReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
  1.1287 +                                  callInfo.getArg(1));
  1.1288 +    } else {
  1.1289 +        cte = MRegExpReplace::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
  1.1290 +                                  callInfo.getArg(1));
  1.1291 +    }
  1.1292 +    current->add(cte);
  1.1293 +    current->push(cte);
  1.1294 +    if (cte->isEffectful() && !resumeAfter(cte))
  1.1295 +        return InliningStatus_Error;
  1.1296 +    return InliningStatus_Inlined;
  1.1297 +}
  1.1298 +
  1.1299 +IonBuilder::InliningStatus
  1.1300 +IonBuilder::inlineUnsafePutElements(CallInfo &callInfo)
  1.1301 +{
  1.1302 +    uint32_t argc = callInfo.argc();
  1.1303 +    if (argc < 3 || (argc % 3) != 0 || callInfo.constructing())
  1.1304 +        return InliningStatus_NotInlined;
  1.1305 +
  1.1306 +    /* Important:
  1.1307 +     *
  1.1308 +     * Here we inline each of the stores resulting from a call to
  1.1309 +     * UnsafePutElements().  It is essential that these stores occur
  1.1310 +     * atomically and cannot be interrupted by a stack or recursion
  1.1311 +     * check.  If this is not true, race conditions can occur.
  1.1312 +     */
  1.1313 +
  1.1314 +    for (uint32_t base = 0; base < argc; base += 3) {
  1.1315 +        uint32_t arri = base + 0;
  1.1316 +        uint32_t idxi = base + 1;
  1.1317 +        uint32_t elemi = base + 2;
  1.1318 +
  1.1319 +        MDefinition *obj = callInfo.getArg(arri);
  1.1320 +        MDefinition *id = callInfo.getArg(idxi);
  1.1321 +        MDefinition *elem = callInfo.getArg(elemi);
  1.1322 +
  1.1323 +        bool isDenseNative = ElementAccessIsDenseNative(obj, id);
  1.1324 +
  1.1325 +        bool writeNeedsBarrier = false;
  1.1326 +        if (isDenseNative) {
  1.1327 +            writeNeedsBarrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
  1.1328 +                                                              &obj, nullptr, &elem,
  1.1329 +                                                              /* canModify = */ false);
  1.1330 +        }
  1.1331 +
  1.1332 +        // We can only inline setelem on dense arrays that do not need type
  1.1333 +        // barriers and on typed arrays and on typed object arrays.
  1.1334 +        ScalarTypeDescr::Type arrayType;
  1.1335 +        if ((!isDenseNative || writeNeedsBarrier) &&
  1.1336 +            !ElementAccessIsTypedArray(obj, id, &arrayType) &&
  1.1337 +            !elementAccessIsTypedObjectArrayOfScalarType(obj, id, &arrayType))
  1.1338 +        {
  1.1339 +            return InliningStatus_NotInlined;
  1.1340 +        }
  1.1341 +    }
  1.1342 +
  1.1343 +    callInfo.setImplicitlyUsedUnchecked();
  1.1344 +
  1.1345 +    // Push the result first so that the stack depth matches up for
  1.1346 +    // the potential bailouts that will occur in the stores below.
  1.1347 +    MConstant *udef = MConstant::New(alloc(), UndefinedValue());
  1.1348 +    current->add(udef);
  1.1349 +    current->push(udef);
  1.1350 +
  1.1351 +    for (uint32_t base = 0; base < argc; base += 3) {
  1.1352 +        uint32_t arri = base + 0;
  1.1353 +        uint32_t idxi = base + 1;
  1.1354 +
  1.1355 +        MDefinition *obj = callInfo.getArg(arri);
  1.1356 +        MDefinition *id = callInfo.getArg(idxi);
  1.1357 +
  1.1358 +        if (ElementAccessIsDenseNative(obj, id)) {
  1.1359 +            if (!inlineUnsafeSetDenseArrayElement(callInfo, base))
  1.1360 +                return InliningStatus_Error;
  1.1361 +            continue;
  1.1362 +        }
  1.1363 +
  1.1364 +        ScalarTypeDescr::Type arrayType;
  1.1365 +        if (ElementAccessIsTypedArray(obj, id, &arrayType)) {
  1.1366 +            if (!inlineUnsafeSetTypedArrayElement(callInfo, base, arrayType))
  1.1367 +                return InliningStatus_Error;
  1.1368 +            continue;
  1.1369 +        }
  1.1370 +
  1.1371 +        if (elementAccessIsTypedObjectArrayOfScalarType(obj, id, &arrayType)) {
  1.1372 +            if (!inlineUnsafeSetTypedObjectArrayElement(callInfo, base, arrayType))
  1.1373 +                return InliningStatus_Error;
  1.1374 +            continue;
  1.1375 +        }
  1.1376 +
  1.1377 +        MOZ_ASSUME_UNREACHABLE("Element access not dense array nor typed array");
  1.1378 +    }
  1.1379 +
  1.1380 +    return InliningStatus_Inlined;
  1.1381 +}
  1.1382 +
  1.1383 +bool
  1.1384 +IonBuilder::elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
  1.1385 +                                                        ScalarTypeDescr::Type *arrayType)
  1.1386 +{
  1.1387 +    if (obj->type() != MIRType_Object) // lookupTypeDescrSet() tests for TypedObject
  1.1388 +        return false;
  1.1389 +
  1.1390 +    if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
  1.1391 +        return false;
  1.1392 +
  1.1393 +    TypeDescrSet objDescrs;
  1.1394 +    if (!lookupTypeDescrSet(obj, &objDescrs))
  1.1395 +        return false;
  1.1396 +
  1.1397 +    if (!objDescrs.allOfArrayKind())
  1.1398 +        return false;
  1.1399 +
  1.1400 +    TypeDescrSet elemDescrs;
  1.1401 +    if (!objDescrs.arrayElementType(*this, &elemDescrs))
  1.1402 +        return false;
  1.1403 +
  1.1404 +    if (elemDescrs.empty() || elemDescrs.kind() != TypeDescr::Scalar)
  1.1405 +        return false;
  1.1406 +
  1.1407 +    JS_ASSERT(TypeDescr::isSized(elemDescrs.kind()));
  1.1408 +
  1.1409 +    return elemDescrs.scalarType(arrayType);
  1.1410 +}
  1.1411 +
  1.1412 +bool
  1.1413 +IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base)
  1.1414 +{
  1.1415 +    // Note: we do not check the conditions that are asserted as true
  1.1416 +    // in intrinsic_UnsafePutElements():
  1.1417 +    // - arr is a dense array
  1.1418 +    // - idx < initialized length
  1.1419 +    // Furthermore, note that inlineUnsafePutElements ensures the type of the
  1.1420 +    // value is reflected in the JSID_VOID property of the array.
  1.1421 +
  1.1422 +    MDefinition *obj = callInfo.getArg(base + 0);
  1.1423 +    MDefinition *id = callInfo.getArg(base + 1);
  1.1424 +    MDefinition *elem = callInfo.getArg(base + 2);
  1.1425 +
  1.1426 +    types::TemporaryTypeSet::DoubleConversion conversion =
  1.1427 +        obj->resultTypeSet()->convertDoubleElements(constraints());
  1.1428 +    if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
  1.1429 +        return false;
  1.1430 +    return true;
  1.1431 +}
  1.1432 +
  1.1433 +bool
  1.1434 +IonBuilder::inlineUnsafeSetTypedArrayElement(CallInfo &callInfo,
  1.1435 +                                             uint32_t base,
  1.1436 +                                             ScalarTypeDescr::Type arrayType)
  1.1437 +{
  1.1438 +    // Note: we do not check the conditions that are asserted as true
  1.1439 +    // in intrinsic_UnsafePutElements():
  1.1440 +    // - arr is a typed array
  1.1441 +    // - idx < length
  1.1442 +
  1.1443 +    MDefinition *obj = callInfo.getArg(base + 0);
  1.1444 +    MDefinition *id = callInfo.getArg(base + 1);
  1.1445 +    MDefinition *elem = callInfo.getArg(base + 2);
  1.1446 +
  1.1447 +    if (!jsop_setelem_typed(arrayType, SetElem_Unsafe, obj, id, elem))
  1.1448 +        return false;
  1.1449 +
  1.1450 +    return true;
  1.1451 +}
  1.1452 +
  1.1453 +bool
  1.1454 +IonBuilder::inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo,
  1.1455 +                                                   uint32_t base,
  1.1456 +                                                   ScalarTypeDescr::Type arrayType)
  1.1457 +{
  1.1458 +    // Note: we do not check the conditions that are asserted as true
  1.1459 +    // in intrinsic_UnsafePutElements():
  1.1460 +    // - arr is a typed array
  1.1461 +    // - idx < length
  1.1462 +
  1.1463 +    MDefinition *obj = callInfo.getArg(base + 0);
  1.1464 +    MDefinition *id = callInfo.getArg(base + 1);
  1.1465 +    MDefinition *elem = callInfo.getArg(base + 2);
  1.1466 +
  1.1467 +    if (!jsop_setelem_typed_object(arrayType, SetElem_Unsafe, true, obj, id, elem))
  1.1468 +        return false;
  1.1469 +
  1.1470 +    return true;
  1.1471 +}
  1.1472 +
  1.1473 +IonBuilder::InliningStatus
  1.1474 +IonBuilder::inlineForceSequentialOrInParallelSection(CallInfo &callInfo)
  1.1475 +{
  1.1476 +    if (callInfo.constructing())
  1.1477 +        return InliningStatus_NotInlined;
  1.1478 +
  1.1479 +    ExecutionMode executionMode = info().executionMode();
  1.1480 +    switch (executionMode) {
  1.1481 +      case ParallelExecution: {
  1.1482 +        // During Parallel Exec, we always force sequential, so
  1.1483 +        // replace with true.  This permits UCE to eliminate the
  1.1484 +        // entire path as dead, which is important.
  1.1485 +        callInfo.setImplicitlyUsedUnchecked();
  1.1486 +        MConstant *ins = MConstant::New(alloc(), BooleanValue(true));
  1.1487 +        current->add(ins);
  1.1488 +        current->push(ins);
  1.1489 +        return InliningStatus_Inlined;
  1.1490 +      }
  1.1491 +
  1.1492 +      default:
  1.1493 +        // In sequential mode, leave as is, because we'd have to
  1.1494 +        // access the "in warmup" flag of the runtime.
  1.1495 +        return InliningStatus_NotInlined;
  1.1496 +    }
  1.1497 +
  1.1498 +    MOZ_ASSUME_UNREACHABLE("Invalid execution mode");
  1.1499 +}
  1.1500 +
  1.1501 +IonBuilder::InliningStatus
  1.1502 +IonBuilder::inlineForkJoinGetSlice(CallInfo &callInfo)
  1.1503 +{
  1.1504 +    if (info().executionMode() != ParallelExecution)
  1.1505 +        return InliningStatus_NotInlined;
  1.1506 +
  1.1507 +    // Assert the way the function is used instead of testing, as it is a
  1.1508 +    // self-hosted function which must be used in a particular fashion.
  1.1509 +    MOZ_ASSERT(callInfo.argc() == 1 && !callInfo.constructing());
  1.1510 +    MOZ_ASSERT(callInfo.getArg(0)->type() == MIRType_Int32);
  1.1511 +
  1.1512 +    // Test this, as we might have not executed the native despite knowing the
  1.1513 +    // target here.
  1.1514 +    if (getInlineReturnType() != MIRType_Int32)
  1.1515 +        return InliningStatus_NotInlined;
  1.1516 +
  1.1517 +    callInfo.setImplicitlyUsedUnchecked();
  1.1518 +
  1.1519 +    switch (info().executionMode()) {
  1.1520 +      case ParallelExecution:
  1.1521 +        if (LIRGenerator::allowInlineForkJoinGetSlice()) {
  1.1522 +            MForkJoinGetSlice *getSlice = MForkJoinGetSlice::New(alloc(),
  1.1523 +                                                                 graph().forkJoinContext());
  1.1524 +            current->add(getSlice);
  1.1525 +            current->push(getSlice);
  1.1526 +            return InliningStatus_Inlined;
  1.1527 +        }
  1.1528 +        return InliningStatus_NotInlined;
  1.1529 +
  1.1530 +      default:
  1.1531 +        // ForkJoinGetSlice acts as identity for sequential execution.
  1.1532 +        current->push(callInfo.getArg(0));
  1.1533 +        return InliningStatus_Inlined;
  1.1534 +    }
  1.1535 +
  1.1536 +    MOZ_ASSUME_UNREACHABLE("Invalid execution mode");
  1.1537 +}
  1.1538 +
  1.1539 +IonBuilder::InliningStatus
  1.1540 +IonBuilder::inlineNewDenseArray(CallInfo &callInfo)
  1.1541 +{
  1.1542 +    if (callInfo.constructing() || callInfo.argc() != 1)
  1.1543 +        return InliningStatus_NotInlined;
  1.1544 +
  1.1545 +    // For now, in seq. mode we just call the C function.  In
  1.1546 +    // par. mode we use inlined MIR.
  1.1547 +    ExecutionMode executionMode = info().executionMode();
  1.1548 +    switch (executionMode) {
  1.1549 +      case ParallelExecution:
  1.1550 +        return inlineNewDenseArrayForParallelExecution(callInfo);
  1.1551 +      default:
  1.1552 +        return inlineNewDenseArrayForSequentialExecution(callInfo);
  1.1553 +    }
  1.1554 +
  1.1555 +    MOZ_ASSUME_UNREACHABLE("unknown ExecutionMode");
  1.1556 +}
  1.1557 +
  1.1558 +IonBuilder::InliningStatus
  1.1559 +IonBuilder::inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo)
  1.1560 +{
  1.1561 +    // not yet implemented; in seq. mode the C function is not so bad
  1.1562 +    return InliningStatus_NotInlined;
  1.1563 +}
  1.1564 +
  1.1565 +IonBuilder::InliningStatus
  1.1566 +IonBuilder::inlineNewDenseArrayForParallelExecution(CallInfo &callInfo)
  1.1567 +{
  1.1568 +    // Create the new parallel array object.  Parallel arrays have specially
  1.1569 +    // constructed type objects, so we can only perform the inlining if we
  1.1570 +    // already have one of these type objects.
  1.1571 +    types::TemporaryTypeSet *returnTypes = getInlineReturnTypeSet();
  1.1572 +    if (returnTypes->getKnownMIRType() != MIRType_Object)
  1.1573 +        return InliningStatus_NotInlined;
  1.1574 +    if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1)
  1.1575 +        return InliningStatus_NotInlined;
  1.1576 +    if (callInfo.getArg(0)->type() != MIRType_Int32)
  1.1577 +        return InliningStatus_NotInlined;
  1.1578 +    types::TypeObject *typeObject = returnTypes->getTypeObject(0);
  1.1579 +
  1.1580 +    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, intrinsic_NewDenseArray);
  1.1581 +    if (!templateObject || templateObject->type() != typeObject)
  1.1582 +        return InliningStatus_NotInlined;
  1.1583 +
  1.1584 +    callInfo.setImplicitlyUsedUnchecked();
  1.1585 +
  1.1586 +    MNewDenseArrayPar *newObject = MNewDenseArrayPar::New(alloc(),
  1.1587 +                                                          graph().forkJoinContext(),
  1.1588 +                                                          callInfo.getArg(0),
  1.1589 +                                                          templateObject);
  1.1590 +    current->add(newObject);
  1.1591 +    current->push(newObject);
  1.1592 +
  1.1593 +    return InliningStatus_Inlined;
  1.1594 +}
  1.1595 +
  1.1596 +IonBuilder::InliningStatus
  1.1597 +IonBuilder::inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Class *clasp2)
  1.1598 +{
  1.1599 +    // Thus far there has been no reason to complicate this beyond two classes,
  1.1600 +    // though it generalizes pretty well.
  1.1601 +    // clasp2 may be NULL.
  1.1602 +    if (callInfo.constructing() || callInfo.argc() != 1)
  1.1603 +        return InliningStatus_NotInlined;
  1.1604 +
  1.1605 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1606 +        return InliningStatus_NotInlined;
  1.1607 +    if (getInlineReturnType() != MIRType_Boolean)
  1.1608 +        return InliningStatus_NotInlined;
  1.1609 +
  1.1610 +    types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
  1.1611 +    const Class *knownClass = types ? types->getKnownClass() : nullptr;
  1.1612 +    if (knownClass) {
  1.1613 +        pushConstant(BooleanValue(knownClass == clasp1 || knownClass == clasp2));
  1.1614 +    } else {
  1.1615 +        MHasClass *hasClass1 = MHasClass::New(alloc(), callInfo.getArg(0), clasp1);
  1.1616 +        current->add(hasClass1);
  1.1617 +        if (clasp2 == nullptr) {
  1.1618 +            current->push(hasClass1);
  1.1619 +        } else {
  1.1620 +            // The following turns into branch-free, box-free code on x86, and should do so on ARM.
  1.1621 +            MHasClass *hasClass2 = MHasClass::New(alloc(), callInfo.getArg(0), clasp2);
  1.1622 +            current->add(hasClass2);
  1.1623 +            MBitOr *either = MBitOr::New(alloc(), hasClass1, hasClass2);
  1.1624 +            either->infer(inspector, pc);
  1.1625 +            current->add(either);
  1.1626 +            // Convert to bool with the '!!' idiom
  1.1627 +            MNot *resultInverted = MNot::New(alloc(), either);
  1.1628 +            resultInverted->infer();
  1.1629 +            current->add(resultInverted);
  1.1630 +            MNot *result = MNot::New(alloc(), resultInverted);
  1.1631 +            result->infer();
  1.1632 +            current->add(result);
  1.1633 +            current->push(result);
  1.1634 +        }
  1.1635 +    }
  1.1636 +
  1.1637 +    callInfo.setImplicitlyUsedUnchecked();
  1.1638 +    return InliningStatus_Inlined;
  1.1639 +}
  1.1640 +
  1.1641 +IonBuilder::InliningStatus
  1.1642 +IonBuilder::inlineObjectIsTypeDescr(CallInfo &callInfo)
  1.1643 +{
  1.1644 +    if (callInfo.constructing() || callInfo.argc() != 1)
  1.1645 +        return InliningStatus_NotInlined;
  1.1646 +
  1.1647 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1648 +        return InliningStatus_NotInlined;
  1.1649 +    if (getInlineReturnType() != MIRType_Boolean)
  1.1650 +        return InliningStatus_NotInlined;
  1.1651 +
  1.1652 +    // The test is elaborate: in-line only if there is exact
  1.1653 +    // information.
  1.1654 +
  1.1655 +    types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
  1.1656 +    if (!types)
  1.1657 +        return InliningStatus_NotInlined;
  1.1658 +
  1.1659 +    bool result = false;
  1.1660 +    switch (types->forAllClasses(IsTypeDescrClass)) {
  1.1661 +    case types::TemporaryTypeSet::ForAllResult::ALL_FALSE:
  1.1662 +    case types::TemporaryTypeSet::ForAllResult::EMPTY:
  1.1663 +        result = false;
  1.1664 +        break;
  1.1665 +    case types::TemporaryTypeSet::ForAllResult::ALL_TRUE:
  1.1666 +        result = true;
  1.1667 +        break;
  1.1668 +    case types::TemporaryTypeSet::ForAllResult::MIXED:
  1.1669 +        return InliningStatus_NotInlined;
  1.1670 +    }
  1.1671 +
  1.1672 +    pushConstant(BooleanValue(result));
  1.1673 +
  1.1674 +    callInfo.setImplicitlyUsedUnchecked();
  1.1675 +    return InliningStatus_Inlined;
  1.1676 +}
  1.1677 +
  1.1678 +IonBuilder::InliningStatus
  1.1679 +IonBuilder::inlineSetTypedObjectOffset(CallInfo &callInfo)
  1.1680 +{
  1.1681 +    if (callInfo.argc() != 2 || callInfo.constructing())
  1.1682 +        return InliningStatus_NotInlined;
  1.1683 +
  1.1684 +    MDefinition *typedObj = callInfo.getArg(0);
  1.1685 +    MDefinition *offset = callInfo.getArg(1);
  1.1686 +
  1.1687 +    // Return type should be undefined or something wacky is going on.
  1.1688 +    if (getInlineReturnType() != MIRType_Undefined)
  1.1689 +        return InliningStatus_NotInlined;
  1.1690 +
  1.1691 +    // Check typedObj is a, well, typed object. Go ahead and use TI
  1.1692 +    // data. If this check should fail, that is almost certainly a bug
  1.1693 +    // in self-hosted code -- either because it's not being careful
  1.1694 +    // with TI or because of something else -- but we'll just let it
  1.1695 +    // fall through to the SetTypedObjectOffset intrinsic in such
  1.1696 +    // cases.
  1.1697 +    types::TemporaryTypeSet *types = typedObj->resultTypeSet();
  1.1698 +    if (typedObj->type() != MIRType_Object || !types)
  1.1699 +        return InliningStatus_NotInlined;
  1.1700 +    switch (types->forAllClasses(IsTypedObjectClass)) {
  1.1701 +      case types::TemporaryTypeSet::ForAllResult::ALL_FALSE:
  1.1702 +      case types::TemporaryTypeSet::ForAllResult::EMPTY:
  1.1703 +      case types::TemporaryTypeSet::ForAllResult::MIXED:
  1.1704 +        return InliningStatus_NotInlined;
  1.1705 +      case types::TemporaryTypeSet::ForAllResult::ALL_TRUE:
  1.1706 +        break;
  1.1707 +    }
  1.1708 +
  1.1709 +    // Check type of offset argument is an integer.
  1.1710 +    if (offset->type() != MIRType_Int32)
  1.1711 +        return InliningStatus_NotInlined;
  1.1712 +
  1.1713 +    callInfo.setImplicitlyUsedUnchecked();
  1.1714 +    MInstruction *ins = MSetTypedObjectOffset::New(alloc(), typedObj, offset);
  1.1715 +    current->add(ins);
  1.1716 +    current->push(ins);
  1.1717 +    return InliningStatus_Inlined;
  1.1718 +}
  1.1719 +
  1.1720 +IonBuilder::InliningStatus
  1.1721 +IonBuilder::inlineUnsafeSetReservedSlot(CallInfo &callInfo)
  1.1722 +{
  1.1723 +    if (callInfo.argc() != 3 || callInfo.constructing())
  1.1724 +        return InliningStatus_NotInlined;
  1.1725 +    if (getInlineReturnType() != MIRType_Undefined)
  1.1726 +        return InliningStatus_NotInlined;
  1.1727 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1728 +        return InliningStatus_NotInlined;
  1.1729 +    if (callInfo.getArg(1)->type() != MIRType_Int32)
  1.1730 +        return InliningStatus_NotInlined;
  1.1731 +
  1.1732 +    // Don't inline if we don't have a constant slot.
  1.1733 +    MDefinition *arg = callInfo.getArg(1);
  1.1734 +    if (!arg->isConstant())
  1.1735 +        return InliningStatus_NotInlined;
  1.1736 +    uint32_t slot = arg->toConstant()->value().toPrivateUint32();
  1.1737 +
  1.1738 +    callInfo.setImplicitlyUsedUnchecked();
  1.1739 +
  1.1740 +    MStoreFixedSlot *store = MStoreFixedSlot::New(alloc(), callInfo.getArg(0), slot, callInfo.getArg(2));
  1.1741 +    current->add(store);
  1.1742 +    current->push(store);
  1.1743 +
  1.1744 +    if (NeedsPostBarrier(info(), callInfo.getArg(2)))
  1.1745 +        current->add(MPostWriteBarrier::New(alloc(), callInfo.thisArg(), callInfo.getArg(2)));
  1.1746 +
  1.1747 +    return InliningStatus_Inlined;
  1.1748 +}
  1.1749 +
  1.1750 +IonBuilder::InliningStatus
  1.1751 +IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo)
  1.1752 +{
  1.1753 +    if (callInfo.argc() != 2 || callInfo.constructing())
  1.1754 +        return InliningStatus_NotInlined;
  1.1755 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1756 +        return InliningStatus_NotInlined;
  1.1757 +    if (callInfo.getArg(1)->type() != MIRType_Int32)
  1.1758 +        return InliningStatus_NotInlined;
  1.1759 +
  1.1760 +    // Don't inline if we don't have a constant slot.
  1.1761 +    MDefinition *arg = callInfo.getArg(1);
  1.1762 +    if (!arg->isConstant())
  1.1763 +        return InliningStatus_NotInlined;
  1.1764 +    uint32_t slot = arg->toConstant()->value().toPrivateUint32();
  1.1765 +
  1.1766 +    callInfo.setImplicitlyUsedUnchecked();
  1.1767 +
  1.1768 +    MLoadFixedSlot *load = MLoadFixedSlot::New(alloc(), callInfo.getArg(0), slot);
  1.1769 +    current->add(load);
  1.1770 +    current->push(load);
  1.1771 +
  1.1772 +    // We don't track reserved slot types, so always emit a barrier.
  1.1773 +    if (!pushTypeBarrier(load, getInlineReturnTypeSet(), true))
  1.1774 +        return InliningStatus_Error;
  1.1775 +
  1.1776 +    return InliningStatus_Inlined;
  1.1777 +}
  1.1778 +
  1.1779 +IonBuilder::InliningStatus
  1.1780 +IonBuilder::inlineHaveSameClass(CallInfo &callInfo)
  1.1781 +{
  1.1782 +    if (callInfo.argc() != 2 || callInfo.constructing())
  1.1783 +        return InliningStatus_NotInlined;
  1.1784 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1785 +        return InliningStatus_NotInlined;
  1.1786 +    if (callInfo.getArg(1)->type() != MIRType_Object)
  1.1787 +        return InliningStatus_NotInlined;
  1.1788 +
  1.1789 +    types::TemporaryTypeSet *arg1Types = callInfo.getArg(0)->resultTypeSet();
  1.1790 +    types::TemporaryTypeSet *arg2Types = callInfo.getArg(1)->resultTypeSet();
  1.1791 +    const Class *arg1Clasp = arg1Types ? arg1Types->getKnownClass() : nullptr;
  1.1792 +    const Class *arg2Clasp = arg2Types ? arg2Types->getKnownClass() : nullptr;
  1.1793 +    if (arg1Clasp && arg2Clasp) {
  1.1794 +        MConstant *constant = MConstant::New(alloc(), BooleanValue(arg1Clasp == arg2Clasp));
  1.1795 +        current->add(constant);
  1.1796 +        current->push(constant);
  1.1797 +        return InliningStatus_Inlined;
  1.1798 +    }
  1.1799 +
  1.1800 +    callInfo.setImplicitlyUsedUnchecked();
  1.1801 +
  1.1802 +    MHaveSameClass *sameClass = MHaveSameClass::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
  1.1803 +    current->add(sameClass);
  1.1804 +    current->push(sameClass);
  1.1805 +
  1.1806 +    return InliningStatus_Inlined;
  1.1807 +}
  1.1808 +
  1.1809 +IonBuilder::InliningStatus
  1.1810 +IonBuilder::inlineIsCallable(CallInfo &callInfo)
  1.1811 +{
  1.1812 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1813 +        return InliningStatus_NotInlined;
  1.1814 +
  1.1815 +    if (getInlineReturnType() != MIRType_Boolean)
  1.1816 +        return InliningStatus_NotInlined;
  1.1817 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1818 +        return InliningStatus_NotInlined;
  1.1819 +
  1.1820 +    // Try inlining with constant true/false: only objects may be callable at
  1.1821 +    // all, and if we know the class check if it is callable.
  1.1822 +    bool isCallableKnown = false;
  1.1823 +    bool isCallableConstant;
  1.1824 +    if (callInfo.getArg(0)->type() != MIRType_Object) {
  1.1825 +        isCallableKnown = true;
  1.1826 +        isCallableConstant = false;
  1.1827 +    } else {
  1.1828 +        types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
  1.1829 +        const Class *clasp = types ? types->getKnownClass() : nullptr;
  1.1830 +        if (clasp) {
  1.1831 +            isCallableKnown = true;
  1.1832 +            isCallableConstant = clasp->isCallable();
  1.1833 +        }
  1.1834 +    }
  1.1835 +
  1.1836 +    callInfo.setImplicitlyUsedUnchecked();
  1.1837 +
  1.1838 +    if (isCallableKnown) {
  1.1839 +        MConstant *constant = MConstant::New(alloc(), BooleanValue(isCallableConstant));
  1.1840 +        current->add(constant);
  1.1841 +        current->push(constant);
  1.1842 +        return InliningStatus_Inlined;
  1.1843 +    }
  1.1844 +
  1.1845 +    MIsCallable *isCallable = MIsCallable::New(alloc(), callInfo.getArg(0));
  1.1846 +    current->add(isCallable);
  1.1847 +    current->push(isCallable);
  1.1848 +
  1.1849 +    return InliningStatus_Inlined;
  1.1850 +}
  1.1851 +
  1.1852 +IonBuilder::InliningStatus
  1.1853 +IonBuilder::inlineToObject(CallInfo &callInfo)
  1.1854 +{
  1.1855 +    if (callInfo.argc() != 1 || callInfo.constructing())
  1.1856 +        return InliningStatus_NotInlined;
  1.1857 +
  1.1858 +    // If we know the input type is an object, nop ToObject.
  1.1859 +    if (getInlineReturnType() != MIRType_Object)
  1.1860 +        return InliningStatus_NotInlined;
  1.1861 +    if (callInfo.getArg(0)->type() != MIRType_Object)
  1.1862 +        return InliningStatus_NotInlined;
  1.1863 +
  1.1864 +    callInfo.setImplicitlyUsedUnchecked();
  1.1865 +    MDefinition *object = callInfo.getArg(0);
  1.1866 +
  1.1867 +    current->push(object);
  1.1868 +    return InliningStatus_Inlined;
  1.1869 +}
  1.1870 +
  1.1871 +IonBuilder::InliningStatus
  1.1872 +IonBuilder::inlineBailout(CallInfo &callInfo)
  1.1873 +{
  1.1874 +    callInfo.setImplicitlyUsedUnchecked();
  1.1875 +
  1.1876 +    current->add(MBail::New(alloc()));
  1.1877 +
  1.1878 +    MConstant *undefined = MConstant::New(alloc(), UndefinedValue());
  1.1879 +    current->add(undefined);
  1.1880 +    current->push(undefined);
  1.1881 +    return InliningStatus_Inlined;
  1.1882 +}
  1.1883 +
  1.1884 +IonBuilder::InliningStatus
  1.1885 +IonBuilder::inlineAssertFloat32(CallInfo &callInfo)
  1.1886 +{
  1.1887 +    callInfo.setImplicitlyUsedUnchecked();
  1.1888 +
  1.1889 +    MDefinition *secondArg = callInfo.getArg(1);
  1.1890 +
  1.1891 +    JS_ASSERT(secondArg->type() == MIRType_Boolean);
  1.1892 +    JS_ASSERT(secondArg->isConstant());
  1.1893 +
  1.1894 +    bool mustBeFloat32 = JSVAL_TO_BOOLEAN(secondArg->toConstant()->value());
  1.1895 +    current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32));
  1.1896 +
  1.1897 +    MConstant *undefined = MConstant::New(alloc(), UndefinedValue());
  1.1898 +    current->add(undefined);
  1.1899 +    current->push(undefined);
  1.1900 +    return InliningStatus_Inlined;
  1.1901 +}
  1.1902 +
  1.1903 +IonBuilder::InliningStatus
  1.1904 +IonBuilder::inlineBoundFunction(CallInfo &nativeCallInfo, JSFunction *target)
  1.1905 +{
  1.1906 +     if (!target->getBoundFunctionTarget()->is<JSFunction>())
  1.1907 +         return InliningStatus_NotInlined;
  1.1908 +
  1.1909 +    JSFunction *scriptedTarget = &(target->getBoundFunctionTarget()->as<JSFunction>());
  1.1910 +    JSRuntime *runtime = scriptedTarget->runtimeFromMainThread();
  1.1911 +
  1.1912 +    // Don't optimize if we're constructing and the callee is not a
  1.1913 +    // constructor, so that CallKnown does not have to handle this case
  1.1914 +    // (it should always throw).
  1.1915 +    if (nativeCallInfo.constructing() && !scriptedTarget->isInterpretedConstructor() &&
  1.1916 +        !scriptedTarget->isNativeConstructor())
  1.1917 +    {
  1.1918 +        return InliningStatus_NotInlined;
  1.1919 +    }
  1.1920 +
  1.1921 +    if (gc::IsInsideNursery(runtime, scriptedTarget))
  1.1922 +        return InliningStatus_NotInlined;
  1.1923 +
  1.1924 +    for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++) {
  1.1925 +        const Value val = target->getBoundFunctionArgument(i);
  1.1926 +        if (val.isObject() && gc::IsInsideNursery(runtime, &val.toObject()))
  1.1927 +            return InliningStatus_NotInlined;
  1.1928 +    }
  1.1929 +
  1.1930 +    const Value thisVal = target->getBoundFunctionThis();
  1.1931 +    if (thisVal.isObject() && gc::IsInsideNursery(runtime, &thisVal.toObject()))
  1.1932 +        return InliningStatus_NotInlined;
  1.1933 +
  1.1934 +    size_t argc = target->getBoundFunctionArgumentCount() + nativeCallInfo.argc();
  1.1935 +    if (argc > ARGS_LENGTH_MAX)
  1.1936 +        return InliningStatus_NotInlined;
  1.1937 +
  1.1938 +    nativeCallInfo.thisArg()->setImplicitlyUsedUnchecked();
  1.1939 +
  1.1940 +    CallInfo callInfo(alloc(), nativeCallInfo.constructing());
  1.1941 +    callInfo.setFun(constant(ObjectValue(*scriptedTarget)));
  1.1942 +    callInfo.setThis(constant(target->getBoundFunctionThis()));
  1.1943 +
  1.1944 +    if (!callInfo.argv().reserve(argc))
  1.1945 +        return InliningStatus_Error;
  1.1946 +
  1.1947 +    for (size_t i = 0; i < target->getBoundFunctionArgumentCount(); i++)
  1.1948 +        callInfo.argv().infallibleAppend(constant(target->getBoundFunctionArgument(i)));
  1.1949 +    for (size_t i = 0; i < nativeCallInfo.argc(); i++)
  1.1950 +        callInfo.argv().infallibleAppend(nativeCallInfo.getArg(i));
  1.1951 +
  1.1952 +    if (!makeCall(scriptedTarget, callInfo, false))
  1.1953 +        return InliningStatus_Error;
  1.1954 +
  1.1955 +    return InliningStatus_Inlined;
  1.1956 +}
  1.1957 +
  1.1958 +} // namespace jit
  1.1959 +} // namespace js

mercurial