Bug 838469 - Use CallInfo for inlining natives. r=h4writer
authorSean Stangl <sstangl@mozilla.com>
Wed, 06 Feb 2013 12:34:15 -0800
changeset 130929 6abdc780ba2b0170fa870a9d7e31cb6ecd810c0a
parent 130928 2308bb67a6fab2b037a5627df1a46e3eff6f8156
child 130930 b3e63d9ea7acd9c52f92d6a4674ad959edf4c0e9
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs838469
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 838469 - Use CallInfo for inlining natives. r=h4writer
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.h
js/src/ion/MCallOptimize.cpp
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -3365,22 +3365,17 @@ IonBuilder::makePolyInlineDispatch(JSCon
                                     fallbackPrepBlock, fallbackBlock,
                                     fallbackEndBlock);
 }
 
 bool
 IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &originals,
                                 CallInfo &callInfo)
 {
-    // Add typeInference hints if not set
-    if (!callInfo.hasTypeInfo()) {
-        types::StackTypeSet *barrier;
-        types::StackTypeSet *types = oracle->returnTypeSet(script(), pc, &barrier);
-        callInfo.setTypeInfo(types, barrier);
-    }
+    JS_ASSERT(callInfo.hasTypeInfo());
 
     // Unwrap the arguments
     JS_ASSERT(callInfo.isWrapped());
     callInfo.unwrapArgs();
     callInfo.pushFormals(current);
 
 #ifdef DEBUG
     uint32_t origStackDepth = current->stackDepth();
@@ -4058,37 +4053,41 @@ IonBuilder::jsop_call(uint32_t argc, boo
             if (!fun)
                 return false;
             hasClones = true;
         }
         if (!targets.append(fun))
             return false;
     }
 
+    CallInfo callInfo(cx, constructing);
+    if (!callInfo.init(current, argc))
+        return false;
+
+    types::StackTypeSet *barrier;
+    types::StackTypeSet *types = oracle->returnTypeSet(script(), pc, &barrier);
+    callInfo.setTypeInfo(types, barrier);
+
     // Inline native call.
     if (inliningEnabled() && targets.length() == 1 && targets[0]->toFunction()->isNative()) {
-        RootedFunction target(cx, targets[0]->toFunction());
-        InliningStatus status = inlineNativeCall(target->native(), argc, constructing);
+        InliningStatus status = inlineNativeCall(callInfo, targets[0]->toFunction()->native());
         if (status != InliningStatus_NotInlined)
             return status != InliningStatus_Error;
     }
 
     // Inline scriped call(s).
-    CallInfo callInfo(cx, constructing);
-    if (!callInfo.init(current, argc))
-        return false;
     if (inliningEnabled() && targets.length() > 0 && makeInliningDecision(targets, argc))
         return inlineScriptedCalls(targets, originals, callInfo);
 
     // No inline, just make the call.
     RootedFunction target(cx, NULL);
     if (targets.length() == 1)
         target = targets[0]->toFunction();
 
-    return makeCall(target, callInfo, calleeTypes, hasClones);
+    return makeCallBarrier(target, callInfo, calleeTypes, hasClones);
 }
 
 MDefinition *
 IonBuilder::makeCallsiteClone(HandleFunction target, MDefinition *fun)
 {
     // Bake in the clone eagerly if we have a known target. We have arrived here
     // because TI told us that the known target is a should-clone-at-callsite
     // function, which means that target already is the clone.
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -377,51 +377,50 @@ class IonBuilder : public MIRGenerator
     enum InliningStatus
     {
         InliningStatus_Error,
         InliningStatus_NotInlined,
         InliningStatus_Inlined
     };
 
     // Inlining helpers.
-    bool discardCallArgs(uint32_t argc, MDefinitionVector &argv, MBasicBlock *bb);
-    bool discardCall(uint32_t argc, MDefinitionVector &argv, MBasicBlock *bb);
     types::StackTypeSet *getInlineReturnTypeSet();
     MIRType getInlineReturnType();
-    types::StackTypeSet *getInlineArgTypeSet(uint32_t argc, uint32_t arg);
-    MIRType getInlineArgType(uint32_t argc, uint32_t arg);
+    types::StackTypeSet *getInlineThisTypeSet(CallInfo &callInfo);
+    MIRType getInlineThisType(CallInfo &callInfo);
+    types::StackTypeSet *getInlineArgTypeSet(CallInfo &callInfo, uint32_t arg);
+    MIRType getInlineArgType(CallInfo &callInfo, uint32_t arg);
 
     // Array natives.
-    InliningStatus inlineArray(uint32_t argc, bool constructing);
-    InliningStatus inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool constructing);
-    InliningStatus inlineArrayPush(uint32_t argc, bool constructing);
-    InliningStatus inlineArrayConcat(uint32_t argc, bool constructing);
+    InliningStatus inlineArray(CallInfo &callInfo);
+    InliningStatus inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode);
+    InliningStatus inlineArrayPush(CallInfo &callInfo);
+    InliningStatus inlineArrayConcat(CallInfo &callInfo);
 
     // Math natives.
-    InliningStatus inlineMathAbs(uint32_t argc, bool constructing);
-    InliningStatus inlineMathFloor(uint32_t argc, bool constructing);
-    InliningStatus inlineMathRound(uint32_t argc, bool constructing);
-    InliningStatus inlineMathSqrt(uint32_t argc, bool constructing);
-    InliningStatus inlineMathMinMax(bool max, uint32_t argc, bool constructing);
-    InliningStatus inlineMathPow(uint32_t argc, bool constructing);
-    InliningStatus inlineMathRandom(uint32_t argc, bool constructing);
-    InliningStatus inlineMathImul(uint32_t argc, bool constructing);
-    InliningStatus inlineMathFunction(MMathFunction::Function function, uint32_t argc,
-                                      bool constructing);
+    InliningStatus inlineMathAbs(CallInfo &callInfo);
+    InliningStatus inlineMathFloor(CallInfo &callInfo);
+    InliningStatus inlineMathRound(CallInfo &callInfo);
+    InliningStatus inlineMathSqrt(CallInfo &callInfo);
+    InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max);
+    InliningStatus inlineMathPow(CallInfo &callInfo);
+    InliningStatus inlineMathRandom(CallInfo &callInfo);
+    InliningStatus inlineMathImul(CallInfo &callInfo);
+    InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function);
 
     // String natives.
-    InliningStatus inlineStringObject(uint32_t argc, bool constructing);
-    InliningStatus inlineStrCharCodeAt(uint32_t argc, bool constructing);
-    InliningStatus inlineStrFromCharCode(uint32_t argc, bool constructing);
-    InliningStatus inlineStrCharAt(uint32_t argc, bool constructing);
+    InliningStatus inlineStringObject(CallInfo &callInfo);
+    InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
+    InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
+    InliningStatus inlineStrCharAt(CallInfo &callInfo);
 
     // RegExp natives.
-    InliningStatus inlineRegExpTest(uint32_t argc, bool constructing);
+    InliningStatus inlineRegExpTest(CallInfo &callInfo);
 
-    InliningStatus inlineNativeCall(JSNative native, uint32_t argc, bool constructing);
+    InliningStatus inlineNativeCall(CallInfo &callInfo, JSNative native);
 
     // Call functions
     bool jsop_call_inline(HandleFunction callee, CallInfo &callInfo, MBasicBlock *bottom,
                           Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
     bool inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &originals,
                              CallInfo &callInfo);
     bool inlineScriptedCall(HandleFunction target, CallInfo &callInfo);
     bool makeInliningDecision(AutoObjectVector &targets, uint32_t argc);
--- a/js/src/ion/MCallOptimize.cpp
+++ b/js/src/ion/MCallOptimize.cpp
@@ -13,225 +13,203 @@
 #include "IonBuilder.h"
 
 #include "vm/StringObject-inl.h"
 
 namespace js {
 namespace ion {
 
 IonBuilder::InliningStatus
-IonBuilder::inlineNativeCall(JSNative native, uint32_t argc, bool constructing)
+IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
 {
     // Array natives.
     if (native == js_Array)
-        return inlineArray(argc, constructing);
+        return inlineArray(callInfo);
     if (native == js::array_pop)
-        return inlineArrayPopShift(MArrayPopShift::Pop, argc, constructing);
+        return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
     if (native == js::array_shift)
-        return inlineArrayPopShift(MArrayPopShift::Shift, argc, constructing);
+        return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
     if (native == js::array_push)
-        return inlineArrayPush(argc, constructing);
+        return inlineArrayPush(callInfo);
     if (native == js::array_concat)
-        return inlineArrayConcat(argc, constructing);
+        return inlineArrayConcat(callInfo);
 
     // Math natives.
     if (native == js_math_abs)
-        return inlineMathAbs(argc, constructing);
+        return inlineMathAbs(callInfo);
     if (native == js_math_floor)
-        return inlineMathFloor(argc, constructing);
+        return inlineMathFloor(callInfo);
     if (native == js_math_round)
-        return inlineMathRound(argc, constructing);
+        return inlineMathRound(callInfo);
     if (native == js_math_sqrt)
-        return inlineMathSqrt(argc, constructing);
+        return inlineMathSqrt(callInfo);
     if (native == js_math_max)
-        return inlineMathMinMax(true /* max */, argc, constructing);
+        return inlineMathMinMax(callInfo, true /* max */);
     if (native == js_math_min)
-        return inlineMathMinMax(false /* max */, argc, constructing);
+        return inlineMathMinMax(callInfo, false /* max */);
     if (native == js_math_pow)
-        return inlineMathPow(argc, constructing);
+        return inlineMathPow(callInfo);
     if (native == js_math_random)
-        return inlineMathRandom(argc, constructing);
+        return inlineMathRandom(callInfo);
     if (native == js::math_imul)
-        return inlineMathImul(argc, constructing);
+        return inlineMathImul(callInfo);
     if (native == js::math_sin)
-        return inlineMathFunction(MMathFunction::Sin, argc, constructing);
+        return inlineMathFunction(callInfo, MMathFunction::Sin);
     if (native == js::math_cos)
-        return inlineMathFunction(MMathFunction::Cos, argc, constructing);
+        return inlineMathFunction(callInfo, MMathFunction::Cos);
     if (native == js::math_tan)
-        return inlineMathFunction(MMathFunction::Tan, argc, constructing);
+        return inlineMathFunction(callInfo, MMathFunction::Tan);
     if (native == js::math_log)
-        return inlineMathFunction(MMathFunction::Log, argc, constructing);
+        return inlineMathFunction(callInfo, MMathFunction::Log);
 
     // String natives.
     if (native == js_String)
-        return inlineStringObject(argc, constructing);
+        return inlineStringObject(callInfo);
     if (native == js_str_charCodeAt)
-        return inlineStrCharCodeAt(argc, constructing);
+        return inlineStrCharCodeAt(callInfo);
     if (native == js::str_fromCharCode)
-        return inlineStrFromCharCode(argc, constructing);
+        return inlineStrFromCharCode(callInfo);
     if (native == js_str_charAt)
-        return inlineStrCharAt(argc, constructing);
+        return inlineStrCharAt(callInfo);
 
     // RegExp natives.
     if (native == regexp_exec && !CallResultEscapes(pc))
-        return inlineRegExpTest(argc, constructing);
+        return inlineRegExpTest(callInfo);
     if (native == regexp_test)
-        return inlineRegExpTest(argc, constructing);
+        return inlineRegExpTest(callInfo);
 
     return InliningStatus_NotInlined;
 }
 
-bool
-IonBuilder::discardCallArgs(uint32_t argc, MDefinitionVector &argv, MBasicBlock *bb)
-{
-    if (!argv.resizeUninitialized(argc + 1))
-        return false;
-
-    for (int32_t i = argc; i >= 0; i--) {
-        // Unwrap each MPassArg, replacing it with its contents.
-        MPassArg *passArg = bb->pop()->toPassArg();
-        MBasicBlock *block = passArg->block();
-        MDefinition *wrapped = passArg->getArgument();
-        passArg->replaceAllUsesWith(wrapped);
-        block->discard(passArg);
-
-        // Remember contents in vector.
-        argv[i] = wrapped;
-    }
-
-    return true;
-}
-
-bool
-IonBuilder::discardCall(uint32_t argc, MDefinitionVector &argv, MBasicBlock *bb)
-{
-    if (!discardCallArgs(argc, argv, bb))
-        return false;
-
-    // Function MDefinition implicitly consumed by inlining.
-    bb->pop();
-    return true;
-}
-
 types::StackTypeSet *
 IonBuilder::getInlineReturnTypeSet()
 {
     types::StackTypeSet *barrier;
     types::StackTypeSet *returnTypes = oracle->returnTypeSet(script(), pc, &barrier);
-
     JS_ASSERT(returnTypes);
     return returnTypes;
 }
 
 MIRType
 IonBuilder::getInlineReturnType()
 {
     types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
     return MIRTypeFromValueType(returnTypes->getKnownTypeTag());
 }
 
 types::StackTypeSet *
-IonBuilder::getInlineArgTypeSet(uint32_t argc, uint32_t arg)
+IonBuilder::getInlineThisTypeSet(CallInfo &callInfo)
 {
-    types::StackTypeSet *argTypes = oracle->getCallArg(script(), argc, arg, pc);
+    types::StackTypeSet *thisTypes = oracle->getCallArg(script(), callInfo.argc(), 0, pc);
+    JS_ASSERT(thisTypes);
+    return thisTypes;
+}
+
+MIRType
+IonBuilder::getInlineThisType(CallInfo &callInfo)
+{
+    types::StackTypeSet *argTypes = getInlineThisTypeSet(callInfo);
+    return MIRTypeFromValueType(argTypes->getKnownTypeTag());
+}
+
+types::StackTypeSet *
+IonBuilder::getInlineArgTypeSet(CallInfo &callInfo, uint32_t arg)
+{
+    types::StackTypeSet *argTypes = oracle->getCallArg(script(), callInfo.argc(), arg + 1, pc);
     JS_ASSERT(argTypes);
     return argTypes;
 }
 
 MIRType
-IonBuilder::getInlineArgType(uint32_t argc, uint32_t arg)
+IonBuilder::getInlineArgType(CallInfo &callInfo, uint32_t arg)
 {
-    types::StackTypeSet *argTypes = getInlineArgTypeSet(argc, arg);
+    types::StackTypeSet *argTypes = getInlineArgTypeSet(callInfo, arg);
     return MIRTypeFromValueType(argTypes->getKnownTypeTag());
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathFunction(MMathFunction::Function function, uint32_t argc, bool constructing)
+IonBuilder::inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (argc != 1)
+    if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_Double)
         return InliningStatus_NotInlined;
-    if (!IsNumberType(getInlineArgType(argc, 1)))
+    if (!IsNumberType(getInlineArgType(callInfo, 0)))
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
     MathCache *cache = cx->runtime->getMathCache(cx);
     if (!cache)
         return InliningStatus_Error;
 
-    MMathFunction *ins = MMathFunction::New(argv[1], function, cache);
+    MMathFunction *ins = MMathFunction::New(callInfo.getArg(0), function, cache);
     current->add(ins);
     current->push(ins);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineArray(uint32_t argc, bool constructing)
+IonBuilder::inlineArray(CallInfo &callInfo)
 {
     uint32_t initLength = 0;
     MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating;
 
     // Multiple arguments imply array initialization, not just construction.
-    if (argc >= 2) {
-        initLength = argc;
+    if (callInfo.argc() >= 2) {
+        initLength = callInfo.argc();
         allocating = MNewArray::NewArray_Allocating;
     }
 
     // A single integer argument denotes initial length.
-    if (argc == 1) {
-        if (getInlineArgType(argc, 1) != MIRType_Int32)
+    if (callInfo.argc() == 1) {
+        if (getInlineArgType(callInfo, 0) != MIRType_Int32)
             return InliningStatus_NotInlined;
-        MDefinition *arg = current->peek(-1)->toPassArg()->getArgument();
+        MDefinition *arg = callInfo.getArg(0)->toPassArg()->getArgument();
         if (!arg->isConstant())
             return InliningStatus_NotInlined;
 
         // Negative lengths generate a RangeError, unhandled by the inline path.
         initLength = arg->toConstant()->value().toInt32();
         if (initLength >= JSObject::NELEMENTS_LIMIT)
             return InliningStatus_NotInlined;
     }
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
     JSObject *templateObject = getNewArrayTemplateObject(initLength);
     if (!templateObject)
         return InliningStatus_Error;
 
     bool convertDoubles = oracle->arrayResultShouldHaveDoubleConversion(script(), pc);
     if (convertDoubles)
         templateObject->setShouldConvertDoubleElements();
 
     MNewArray *ins = new MNewArray(initLength, templateObject, allocating);
     current->add(ins);
     current->push(ins);
 
-    if (argc >= 2) {
+    if (callInfo.argc() >= 2) {
         // Get the elements vector.
         MElements *elements = MElements::New(ins);
         current->add(elements);
 
         // Store all values, no need to initialize the length after each as
         // jsop_initelem_array is doing because we do not expect to bailout
         // because the memory is supposed to be allocated by now.
         MConstant *id = NULL;
         for (uint32_t i = 0; i < initLength; i++) {
             id = MConstant::New(Int32Value(i));
             current->add(id);
 
-            MDefinition *value = argv[i + 1];
+            MDefinition *value = callInfo.getArg(i);
             if (convertDoubles) {
                 MInstruction *valueDouble = MToDouble::New(value);
                 current->add(valueDouble);
                 value = valueDouble;
             }
 
             MStoreElement *store = MStoreElement::New(elements, id, value,
                                                       /* needsHoleCheck = */ false);
@@ -245,133 +223,130 @@ IonBuilder::inlineArray(uint32_t argc, b
         if (!resumeAfter(length))
             return InliningStatus_Error;
     }
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool constructing)
+IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
     MIRType returnType = getInlineReturnType();
     if (returnType == MIRType_Undefined || returnType == MIRType_Null)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 0) != MIRType_Object)
+    if (getInlineThisType(callInfo) != MIRType_Object)
         return InliningStatus_NotInlined;
 
     // Pop and shift are only handled for dense arrays that have never been
     // used in an iterator: popping elements does not account for suppressing
     // deleted properties in active iterators.
     //
     // Inference's TypeConstraintCall generates the constraints that propagate
     // properties directly into the result type set.
     types::TypeObjectFlags unhandledFlags =
         types::OBJECT_FLAG_SPARSE_INDEXES |
         types::OBJECT_FLAG_LENGTH_OVERFLOW |
         types::OBJECT_FLAG_ITERATED;
 
-    types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
+    types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
     if (thisTypes->getKnownClass() != &ArrayClass)
         return InliningStatus_NotInlined;
     if (thisTypes->hasObjectFlags(cx, unhandledFlags))
         return InliningStatus_NotInlined;
     RootedScript script(cx, script_);
     if (types::ArrayPrototypeHasIndexedProperty(cx, script))
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
     types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
     bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
     bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
 
-    MArrayPopShift *ins = MArrayPopShift::New(argv[0], mode, needsHoleCheck, maybeUndefined);
+    MArrayPopShift *ins = MArrayPopShift::New(callInfo.thisArg(), mode,
+                                              needsHoleCheck, maybeUndefined);
     current->add(ins);
     current->push(ins);
     ins->setResultType(returnType);
 
     if (!resumeAfter(ins))
         return InliningStatus_Error;
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
+IonBuilder::inlineArrayPush(CallInfo &callInfo)
 {
-    if (argc != 1 || constructing)
+    if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_Int32)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 0) != MIRType_Object)
+    if (getInlineThisType(callInfo) != MIRType_Object)
         return InliningStatus_NotInlined;
 
     // Inference's TypeConstraintCall generates the constraints that propagate
     // properties directly into the result type set.
-    types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
+    types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
     if (thisTypes->getKnownClass() != &ArrayClass)
         return InliningStatus_NotInlined;
     if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES |
                                   types::OBJECT_FLAG_LENGTH_OVERFLOW))
     {
         return InliningStatus_NotInlined;
     }
     RootedScript script(cx, script_);
     if (types::ArrayPrototypeHasIndexedProperty(cx, script))
         return InliningStatus_NotInlined;
 
     types::StackTypeSet::DoubleConversion conversion = thisTypes->convertDoubleElements(cx);
     if (conversion == types::StackTypeSet::AmbiguousDoubleConversion)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MDefinition *value = argv[1];
+    MDefinition *value = callInfo.getArg(0);
     if (conversion == types::StackTypeSet::AlwaysConvertToDoubles ||
         conversion == types::StackTypeSet::MaybeConvertToDoubles)
     {
         MInstruction *valueDouble = MToDouble::New(value);
         current->add(valueDouble);
         value = valueDouble;
     }
 
-    MArrayPush *ins = MArrayPush::New(argv[0], value);
+    MArrayPush *ins = MArrayPush::New(callInfo.thisArg(), value);
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return InliningStatus_Error;
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineArrayConcat(uint32_t argc, bool constructing)
+IonBuilder::inlineArrayConcat(CallInfo &callInfo)
 {
-    if (argc != 1 || constructing)
+    if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     // Ensure |this|, argument and result are objects.
     if (getInlineReturnType() != MIRType_Object)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 0) != MIRType_Object)
+    if (getInlineThisType(callInfo) != MIRType_Object)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 1) != MIRType_Object)
+    if (getInlineArgType(callInfo, 0) != MIRType_Object)
         return InliningStatus_NotInlined;
 
     // |this| and the argument must be dense arrays.
-    types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
-    types::StackTypeSet *argTypes = getInlineArgTypeSet(argc, 1);
+    types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
+    types::StackTypeSet *argTypes = getInlineArgTypeSet(callInfo, 0);
 
     if (thisTypes->getKnownClass() != &ArrayClass)
         return InliningStatus_NotInlined;
     if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES |
                                   types::OBJECT_FLAG_LENGTH_OVERFLOW))
     {
         return InliningStatus_NotInlined;
     }
@@ -426,477 +401,448 @@ IonBuilder::inlineArrayConcat(uint32_t a
     }
 
     // Inline the call.
     RootedObject templateObj(cx, NewDenseEmptyArray(cx, thisType->proto));
     if (!templateObj)
         return InliningStatus_Error;
     templateObj->setType(thisType);
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MArrayConcat *ins = MArrayConcat::New(argv[0], argv[1], templateObj);
+    MArrayConcat *ins = MArrayConcat::New(callInfo.thisArg(), callInfo.getArg(0), templateObj);
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return InliningStatus_Error;
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathAbs(uint32_t argc, bool constructing)
+IonBuilder::inlineMathAbs(CallInfo &callInfo)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (argc != 1)
+    if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
     MIRType returnType = getInlineReturnType();
-    MIRType argType = getInlineArgType(argc, 1);
+    MIRType argType = getInlineArgType(callInfo, 0);
     if (argType != MIRType_Int32 && argType != MIRType_Double)
         return InliningStatus_NotInlined;
     if (argType != returnType)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MAbs *ins = MAbs::New(argv[1], returnType);
+    MAbs *ins = MAbs::New(callInfo.getArg(0), returnType);
     current->add(ins);
     current->push(ins);
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathFloor(uint32_t argc, bool constructing)
+IonBuilder::inlineMathFloor(CallInfo &callInfo)
 {
 
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (argc != 1)
+    if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
-    MIRType argType = getInlineArgType(argc, 1);
+    MIRType argType = getInlineArgType(callInfo, 0);
     if (getInlineReturnType() != MIRType_Int32)
         return InliningStatus_NotInlined;
 
     // Math.floor(int(x)) == int(x)
     if (argType == MIRType_Int32) {
-        MDefinitionVector argv;
-        if (!discardCall(argc, argv, current))
-            return InliningStatus_Error;
-        current->push(argv[1]);
+        callInfo.unwrapArgs();
+        current->push(callInfo.getArg(0));
         return InliningStatus_Inlined;
     }
 
     if (argType == MIRType_Double) {
-        MDefinitionVector argv;
-        if (!discardCall(argc, argv, current))
-            return InliningStatus_Error;
-        MFloor *ins = new MFloor(argv[1]);
+        callInfo.unwrapArgs();
+        MFloor *ins = new MFloor(callInfo.getArg(0));
         current->add(ins);
         current->push(ins);
         return InliningStatus_Inlined;
     }
 
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathRound(uint32_t argc, bool constructing)
+IonBuilder::inlineMathRound(CallInfo &callInfo)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (argc != 1)
+    if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
     MIRType returnType = getInlineReturnType();
-    MIRType argType = getInlineArgType(argc, 1);
+    MIRType argType = getInlineArgType(callInfo, 0);
 
     // Math.round(int(x)) == int(x)
     if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
-        MDefinitionVector argv;
-        if (!discardCall(argc, argv, current))
-            return InliningStatus_Error;
-        current->push(argv[1]);
+        callInfo.unwrapArgs();
+        current->push(callInfo.getArg(0));
         return InliningStatus_Inlined;
     }
 
     if (argType == MIRType_Double && returnType == MIRType_Int32) {
-        MDefinitionVector argv;
-        if (!discardCall(argc, argv, current))
-            return InliningStatus_Error;
-        MRound *ins = new MRound(argv[1]);
+        callInfo.unwrapArgs();
+        MRound *ins = new MRound(callInfo.getArg(0));
         current->add(ins);
         current->push(ins);
         return InliningStatus_Inlined;
     }
 
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathSqrt(uint32_t argc, bool constructing)
+IonBuilder::inlineMathSqrt(CallInfo &callInfo)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (argc != 1)
+    if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
-    MIRType argType = getInlineArgType(argc, 1);
+    MIRType argType = getInlineArgType(callInfo, 0);
     if (getInlineReturnType() != MIRType_Double)
         return InliningStatus_NotInlined;
     if (argType != MIRType_Double && argType != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MSqrt *sqrt = MSqrt::New(argv[1]);
+    MSqrt *sqrt = MSqrt::New(callInfo.getArg(0));
     current->add(sqrt);
     current->push(sqrt);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
+IonBuilder::inlineMathPow(CallInfo &callInfo)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (argc != 2)
+    if (callInfo.argc() != 2)
         return InliningStatus_NotInlined;
 
     // Typechecking.
     if (getInlineReturnType() != MIRType_Double)
         return InliningStatus_NotInlined;
 
-    MIRType arg1Type = getInlineArgType(argc, 1);
-    MIRType arg2Type = getInlineArgType(argc, 2);
+    MIRType baseType = getInlineArgType(callInfo, 0);
+    MIRType powerType = getInlineArgType(callInfo, 1);
 
-    if (arg1Type != MIRType_Int32 && arg1Type != MIRType_Double)
+    if (baseType != MIRType_Int32 && baseType != MIRType_Double)
         return InliningStatus_NotInlined;
-    if (arg2Type != MIRType_Int32 && arg2Type != MIRType_Double)
+    if (powerType != MIRType_Int32 && powerType != MIRType_Double)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
+
+    MDefinition *base = callInfo.getArg(0);
+    MDefinition *power = callInfo.getArg(1);
 
-    // If the non-power input is integer, convert it to a Double.
+    // If the base is integer, convert it to a Double.
     // Safe since the output must be a Double.
-    if (arg1Type == MIRType_Int32) {
-        MToDouble *conv = MToDouble::New(argv[1]);
+    if (baseType == MIRType_Int32) {
+        MToDouble *conv = MToDouble::New(base);
         current->add(conv);
-        argv[1] = conv;
+        base = conv;
     }
 
     // Optimize some constant powers.
-    if (argv[2]->isConstant()) {
+    if (callInfo.getArg(1)->isConstant()) {
         double pow;
-        if (!ToNumber(GetIonContext()->cx, argv[2]->toConstant()->value(), &pow))
+        if (!ToNumber(GetIonContext()->cx, callInfo.getArg(1)->toConstant()->value(), &pow))
             return InliningStatus_Error;
 
         // Math.pow(x, 0.5) is a sqrt with edge-case detection.
         if (pow == 0.5) {
-            MPowHalf *half = MPowHalf::New(argv[1]);
+            MPowHalf *half = MPowHalf::New(base);
             current->add(half);
             current->push(half);
             return InliningStatus_Inlined;
         }
 
         // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
         if (pow == -0.5) {
-            MPowHalf *half = MPowHalf::New(argv[1]);
+            MPowHalf *half = MPowHalf::New(base);
             current->add(half);
             MConstant *one = MConstant::New(DoubleValue(1.0));
             current->add(one);
             MDiv *div = MDiv::New(one, half, MIRType_Double);
             current->add(div);
             current->push(div);
             return InliningStatus_Inlined;
         }
 
         // Math.pow(x, 1) == x.
         if (pow == 1.0) {
-            current->push(argv[1]);
+            current->push(base);
             return InliningStatus_Inlined;
         }
 
         // Math.pow(x, 2) == x*x.
         if (pow == 2.0) {
-            MMul *mul = MMul::New(argv[1], argv[1], MIRType_Double);
+            MMul *mul = MMul::New(base, base, MIRType_Double);
             current->add(mul);
             current->push(mul);
             return InliningStatus_Inlined;
         }
 
         // Math.pow(x, 3) == x*x*x.
         if (pow == 3.0) {
-            MMul *mul1 = MMul::New(argv[1], argv[1], MIRType_Double);
+            MMul *mul1 = MMul::New(base, base, MIRType_Double);
             current->add(mul1);
-            MMul *mul2 = MMul::New(argv[1], mul1, MIRType_Double);
+            MMul *mul2 = MMul::New(base, mul1, MIRType_Double);
             current->add(mul2);
             current->push(mul2);
             return InliningStatus_Inlined;
         }
 
         // Math.pow(x, 4) == y*y, where y = x*x.
         if (pow == 4.0) {
-            MMul *y = MMul::New(argv[1], argv[1], MIRType_Double);
+            MMul *y = MMul::New(base, base, MIRType_Double);
             current->add(y);
             MMul *mul = MMul::New(y, y, MIRType_Double);
             current->add(mul);
             current->push(mul);
             return InliningStatus_Inlined;
         }
     }
 
-    MPow *ins = MPow::New(argv[1], argv[2], arg2Type);
+    MPow *ins = MPow::New(base, power, powerType);
     current->add(ins);
     current->push(ins);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathRandom(uint32_t argc, bool constructing)
+IonBuilder::inlineMathRandom(CallInfo &callInfo)
 {
-    if (constructing)
+    if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_Double)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
     MRandom *rand = MRandom::New();
     current->add(rand);
     current->push(rand);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathImul(uint32_t argc, bool constructing)
+IonBuilder::inlineMathImul(CallInfo &callInfo)
 {
-    if (argc != 2 || constructing)
+    if (callInfo.argc() != 2 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     MIRType returnType = getInlineReturnType();
     if (returnType != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    if (!IsNumberType(getInlineArgType(argc, 1)))
+    if (!IsNumberType(getInlineArgType(callInfo, 0)))
         return InliningStatus_NotInlined;
-    if (!IsNumberType(getInlineArgType(argc, 2)))
+    if (!IsNumberType(getInlineArgType(callInfo, 1)))
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MInstruction *first = MTruncateToInt32::New(argv[1]);
+    MInstruction *first = MTruncateToInt32::New(callInfo.getArg(0));
     current->add(first);
 
-    MInstruction *second = MTruncateToInt32::New(argv[2]);
+    MInstruction *second = MTruncateToInt32::New(callInfo.getArg(1));
     current->add(second);
 
     MMul *ins = MMul::New(first, second, MIRType_Int32, MMul::Integer);
     current->add(ins);
     current->push(ins);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineMathMinMax(bool max, uint32_t argc, bool constructing)
+IonBuilder::inlineMathMinMax(CallInfo &callInfo, bool max)
 {
-    if (argc != 2 || constructing)
+    if (callInfo.argc() != 2 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     MIRType returnType = getInlineReturnType();
     if (!IsNumberType(returnType))
         return InliningStatus_NotInlined;
 
-    MIRType arg1Type = getInlineArgType(argc, 1);
-    if (!IsNumberType(arg1Type))
+    MIRType arg0Type = getInlineArgType(callInfo, 0);
+    if (!IsNumberType(arg0Type))
         return InliningStatus_NotInlined;
-    MIRType arg2Type = getInlineArgType(argc, 2);
-    if (!IsNumberType(arg2Type))
+    MIRType arg1Type = getInlineArgType(callInfo, 1);
+    if (!IsNumberType(arg1Type))
         return InliningStatus_NotInlined;
 
     if (returnType == MIRType_Int32 &&
-        (arg1Type == MIRType_Double || arg2Type == MIRType_Double))
+        (arg0Type == MIRType_Double || arg1Type == MIRType_Double))
     {
         // We would need to inform TI, if we happen to return a double.
         return InliningStatus_NotInlined;
     }
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MMinMax *ins = MMinMax::New(argv[1], argv[2], returnType, max);
+    MMinMax *ins = MMinMax::New(callInfo.getArg(0), callInfo.getArg(1), returnType, max);
     current->add(ins);
     current->push(ins);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineStringObject(uint32_t argc, bool constructing)
+IonBuilder::inlineStringObject(CallInfo &callInfo)
 {
-    if (argc != 1 || !constructing)
+    if (callInfo.argc() != 1 || !callInfo.constructing())
         return InliningStatus_NotInlined;
 
     // MToString only supports int32 or string values.
-    MIRType type = getInlineArgType(argc, 1);
+    MIRType type = getInlineArgType(callInfo, 0);
     if (type != MIRType_Int32 && type != MIRType_String)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
     RootedString emptyString(cx, cx->runtime->emptyString);
     RootedObject templateObj(cx, StringObject::create(cx, emptyString));
     if (!templateObj)
         return InliningStatus_Error;
 
-    MNewStringObject *ins = MNewStringObject::New(argv[1], templateObj);
+    MNewStringObject *ins = MNewStringObject::New(callInfo.getArg(0), templateObj);
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineStrCharCodeAt(uint32_t argc, bool constructing)
+IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
 {
-    if (argc != 1 || constructing)
+    if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_Int32)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 0) != MIRType_String)
+    if (getInlineThisType(callInfo) != MIRType_String)
         return InliningStatus_NotInlined;
-    MIRType argType = getInlineArgType(argc, 1);
+    MIRType argType = getInlineArgType(callInfo, 0);
     if (argType != MIRType_Int32 && argType != MIRType_Double)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MInstruction *index = MToInt32::New(argv[1]);
+    MInstruction *index = MToInt32::New(callInfo.getArg(0));
     current->add(index);
 
-    MStringLength *length = MStringLength::New(argv[0]);
+    MStringLength *length = MStringLength::New(callInfo.thisArg());
     current->add(length);
 
     index = addBoundsCheck(index, length);
 
-    MCharCodeAt *charCode = MCharCodeAt::New(argv[0], index);
+    MCharCodeAt *charCode = MCharCodeAt::New(callInfo.thisArg(), index);
     current->add(charCode);
     current->push(charCode);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineStrFromCharCode(uint32_t argc, bool constructing)
+IonBuilder::inlineStrFromCharCode(CallInfo &callInfo)
 {
-    if (argc != 1 || constructing)
+    if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_String)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 1) != MIRType_Int32)
+    if (getInlineArgType(callInfo, 0) != MIRType_Int32)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MToInt32 *charCode = MToInt32::New(argv[1]);
+    MToInt32 *charCode = MToInt32::New(callInfo.getArg(0));
     current->add(charCode);
 
     MFromCharCode *string = MFromCharCode::New(charCode);
     current->add(string);
     current->push(string);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineStrCharAt(uint32_t argc, bool constructing)
+IonBuilder::inlineStrCharAt(CallInfo &callInfo)
 {
-    if (argc != 1 || constructing)
+    if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_String)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 0) != MIRType_String)
+    if (getInlineThisType(callInfo) != MIRType_String)
         return InliningStatus_NotInlined;
-    MIRType argType = getInlineArgType(argc, 1);
+    MIRType argType = getInlineArgType(callInfo, 0);
     if (argType != MIRType_Int32 && argType != MIRType_Double)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MInstruction *index = MToInt32::New(argv[1]);
+    MInstruction *index = MToInt32::New(callInfo.getArg(0));
     current->add(index);
 
-    MStringLength *length = MStringLength::New(argv[0]);
+    MStringLength *length = MStringLength::New(callInfo.thisArg());
     current->add(length);
 
     index = addBoundsCheck(index, length);
 
     // String.charAt(x) = String.fromCharCode(String.charCodeAt(x))
-    MCharCodeAt *charCode = MCharCodeAt::New(argv[0], index);
+    MCharCodeAt *charCode = MCharCodeAt::New(callInfo.thisArg(), index);
     current->add(charCode);
 
     MFromCharCode *string = MFromCharCode::New(charCode);
     current->add(string);
     current->push(string);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
-IonBuilder::inlineRegExpTest(uint32_t argc, bool constructing)
+IonBuilder::inlineRegExpTest(CallInfo &callInfo)
 {
-    if (argc != 1 || constructing)
+    if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
     // TI can infer a NULL return type of regexp_test with eager compilation.
     if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean)
         return InliningStatus_NotInlined;
 
-    if (getInlineArgType(argc, 0) != MIRType_Object)
+    if (getInlineThisType(callInfo) != MIRType_Object)
         return InliningStatus_NotInlined;
-    if (getInlineArgType(argc, 1) != MIRType_String)
+    if (getInlineArgType(callInfo, 0) != MIRType_String)
         return InliningStatus_NotInlined;
 
-    MDefinitionVector argv;
-    if (!discardCall(argc, argv, current))
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
-    MInstruction *match = MRegExpTest::New(argv[0], argv[1]);
+    MInstruction *match = MRegExpTest::New(callInfo.thisArg(), callInfo.getArg(0));
     current->add(match);
     current->push(match);
     if (!resumeAfter(match))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }