Bug 838469 - Use CallInfo for inlining natives. r=h4writer

This commit is contained in:
Sean Stangl 2013-02-06 12:34:15 -08:00
Родитель 93dea27aff
Коммит 1a3e66e87f
3 изменённых файлов: 219 добавлений и 275 удалений

Просмотреть файл

@ -3370,12 +3370,7 @@ bool
IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &originals, IonBuilder::inlineScriptedCalls(AutoObjectVector &targets, AutoObjectVector &originals,
CallInfo &callInfo) CallInfo &callInfo)
{ {
// Add typeInference hints if not set JS_ASSERT(callInfo.hasTypeInfo());
if (!callInfo.hasTypeInfo()) {
types::StackTypeSet *barrier;
types::StackTypeSet *types = oracle->returnTypeSet(script(), pc, &barrier);
callInfo.setTypeInfo(types, barrier);
}
// Unwrap the arguments // Unwrap the arguments
JS_ASSERT(callInfo.isWrapped()); JS_ASSERT(callInfo.isWrapped());
@ -4063,18 +4058,22 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
return false; 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. // Inline native call.
if (inliningEnabled() && targets.length() == 1 && targets[0]->toFunction()->isNative()) { if (inliningEnabled() && targets.length() == 1 && targets[0]->toFunction()->isNative()) {
RootedFunction target(cx, targets[0]->toFunction()); InliningStatus status = inlineNativeCall(callInfo, targets[0]->toFunction()->native());
InliningStatus status = inlineNativeCall(target->native(), argc, constructing);
if (status != InliningStatus_NotInlined) if (status != InliningStatus_NotInlined)
return status != InliningStatus_Error; return status != InliningStatus_Error;
} }
// Inline scriped call(s). // Inline scriped call(s).
CallInfo callInfo(cx, constructing);
if (!callInfo.init(current, argc))
return false;
if (inliningEnabled() && targets.length() > 0 && makeInliningDecision(targets, argc)) if (inliningEnabled() && targets.length() > 0 && makeInliningDecision(targets, argc))
return inlineScriptedCalls(targets, originals, callInfo); return inlineScriptedCalls(targets, originals, callInfo);
@ -4083,7 +4082,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
if (targets.length() == 1) if (targets.length() == 1)
target = targets[0]->toFunction(); target = targets[0]->toFunction();
return makeCall(target, callInfo, calleeTypes, hasClones); return makeCallBarrier(target, callInfo, calleeTypes, hasClones);
} }
MDefinition * MDefinition *

Просмотреть файл

@ -382,41 +382,40 @@ class IonBuilder : public MIRGenerator
}; };
// Inlining helpers. // Inlining helpers.
bool discardCallArgs(uint32_t argc, MDefinitionVector &argv, MBasicBlock *bb);
bool discardCall(uint32_t argc, MDefinitionVector &argv, MBasicBlock *bb);
types::StackTypeSet *getInlineReturnTypeSet(); types::StackTypeSet *getInlineReturnTypeSet();
MIRType getInlineReturnType(); MIRType getInlineReturnType();
types::StackTypeSet *getInlineArgTypeSet(uint32_t argc, uint32_t arg); types::StackTypeSet *getInlineThisTypeSet(CallInfo &callInfo);
MIRType getInlineArgType(uint32_t argc, uint32_t arg); MIRType getInlineThisType(CallInfo &callInfo);
types::StackTypeSet *getInlineArgTypeSet(CallInfo &callInfo, uint32_t arg);
MIRType getInlineArgType(CallInfo &callInfo, uint32_t arg);
// Array natives. // Array natives.
InliningStatus inlineArray(uint32_t argc, bool constructing); InliningStatus inlineArray(CallInfo &callInfo);
InliningStatus inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool constructing); InliningStatus inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode);
InliningStatus inlineArrayPush(uint32_t argc, bool constructing); InliningStatus inlineArrayPush(CallInfo &callInfo);
InliningStatus inlineArrayConcat(uint32_t argc, bool constructing); InliningStatus inlineArrayConcat(CallInfo &callInfo);
// Math natives. // Math natives.
InliningStatus inlineMathAbs(uint32_t argc, bool constructing); InliningStatus inlineMathAbs(CallInfo &callInfo);
InliningStatus inlineMathFloor(uint32_t argc, bool constructing); InliningStatus inlineMathFloor(CallInfo &callInfo);
InliningStatus inlineMathRound(uint32_t argc, bool constructing); InliningStatus inlineMathRound(CallInfo &callInfo);
InliningStatus inlineMathSqrt(uint32_t argc, bool constructing); InliningStatus inlineMathSqrt(CallInfo &callInfo);
InliningStatus inlineMathMinMax(bool max, uint32_t argc, bool constructing); InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max);
InliningStatus inlineMathPow(uint32_t argc, bool constructing); InliningStatus inlineMathPow(CallInfo &callInfo);
InliningStatus inlineMathRandom(uint32_t argc, bool constructing); InliningStatus inlineMathRandom(CallInfo &callInfo);
InliningStatus inlineMathImul(uint32_t argc, bool constructing); InliningStatus inlineMathImul(CallInfo &callInfo);
InliningStatus inlineMathFunction(MMathFunction::Function function, uint32_t argc, InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function);
bool constructing);
// String natives. // String natives.
InliningStatus inlineStringObject(uint32_t argc, bool constructing); InliningStatus inlineStringObject(CallInfo &callInfo);
InliningStatus inlineStrCharCodeAt(uint32_t argc, bool constructing); InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
InliningStatus inlineStrFromCharCode(uint32_t argc, bool constructing); InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
InliningStatus inlineStrCharAt(uint32_t argc, bool constructing); InliningStatus inlineStrCharAt(CallInfo &callInfo);
// RegExp natives. // 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 // Call functions
bool jsop_call_inline(HandleFunction callee, CallInfo &callInfo, MBasicBlock *bottom, bool jsop_call_inline(HandleFunction callee, CallInfo &callInfo, MBasicBlock *bottom,

Просмотреть файл

@ -18,105 +18,72 @@ namespace js {
namespace ion { namespace ion {
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineNativeCall(JSNative native, uint32_t argc, bool constructing) IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
{ {
// Array natives. // Array natives.
if (native == js_Array) if (native == js_Array)
return inlineArray(argc, constructing); return inlineArray(callInfo);
if (native == js::array_pop) if (native == js::array_pop)
return inlineArrayPopShift(MArrayPopShift::Pop, argc, constructing); return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
if (native == js::array_shift) if (native == js::array_shift)
return inlineArrayPopShift(MArrayPopShift::Shift, argc, constructing); return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
if (native == js::array_push) if (native == js::array_push)
return inlineArrayPush(argc, constructing); return inlineArrayPush(callInfo);
if (native == js::array_concat) if (native == js::array_concat)
return inlineArrayConcat(argc, constructing); return inlineArrayConcat(callInfo);
// Math natives. // Math natives.
if (native == js_math_abs) if (native == js_math_abs)
return inlineMathAbs(argc, constructing); return inlineMathAbs(callInfo);
if (native == js_math_floor) if (native == js_math_floor)
return inlineMathFloor(argc, constructing); return inlineMathFloor(callInfo);
if (native == js_math_round) if (native == js_math_round)
return inlineMathRound(argc, constructing); return inlineMathRound(callInfo);
if (native == js_math_sqrt) if (native == js_math_sqrt)
return inlineMathSqrt(argc, constructing); return inlineMathSqrt(callInfo);
if (native == js_math_max) if (native == js_math_max)
return inlineMathMinMax(true /* max */, argc, constructing); return inlineMathMinMax(callInfo, true /* max */);
if (native == js_math_min) if (native == js_math_min)
return inlineMathMinMax(false /* max */, argc, constructing); return inlineMathMinMax(callInfo, false /* max */);
if (native == js_math_pow) if (native == js_math_pow)
return inlineMathPow(argc, constructing); return inlineMathPow(callInfo);
if (native == js_math_random) if (native == js_math_random)
return inlineMathRandom(argc, constructing); return inlineMathRandom(callInfo);
if (native == js::math_imul) if (native == js::math_imul)
return inlineMathImul(argc, constructing); return inlineMathImul(callInfo);
if (native == js::math_sin) if (native == js::math_sin)
return inlineMathFunction(MMathFunction::Sin, argc, constructing); return inlineMathFunction(callInfo, MMathFunction::Sin);
if (native == js::math_cos) if (native == js::math_cos)
return inlineMathFunction(MMathFunction::Cos, argc, constructing); return inlineMathFunction(callInfo, MMathFunction::Cos);
if (native == js::math_tan) if (native == js::math_tan)
return inlineMathFunction(MMathFunction::Tan, argc, constructing); return inlineMathFunction(callInfo, MMathFunction::Tan);
if (native == js::math_log) if (native == js::math_log)
return inlineMathFunction(MMathFunction::Log, argc, constructing); return inlineMathFunction(callInfo, MMathFunction::Log);
// String natives. // String natives.
if (native == js_String) if (native == js_String)
return inlineStringObject(argc, constructing); return inlineStringObject(callInfo);
if (native == js_str_charCodeAt) if (native == js_str_charCodeAt)
return inlineStrCharCodeAt(argc, constructing); return inlineStrCharCodeAt(callInfo);
if (native == js::str_fromCharCode) if (native == js::str_fromCharCode)
return inlineStrFromCharCode(argc, constructing); return inlineStrFromCharCode(callInfo);
if (native == js_str_charAt) if (native == js_str_charAt)
return inlineStrCharAt(argc, constructing); return inlineStrCharAt(callInfo);
// RegExp natives. // RegExp natives.
if (native == regexp_exec && !CallResultEscapes(pc)) if (native == regexp_exec && !CallResultEscapes(pc))
return inlineRegExpTest(argc, constructing); return inlineRegExpTest(callInfo);
if (native == regexp_test) if (native == regexp_test)
return inlineRegExpTest(argc, constructing); return inlineRegExpTest(callInfo);
return InliningStatus_NotInlined; 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 * types::StackTypeSet *
IonBuilder::getInlineReturnTypeSet() IonBuilder::getInlineReturnTypeSet()
{ {
types::StackTypeSet *barrier; types::StackTypeSet *barrier;
types::StackTypeSet *returnTypes = oracle->returnTypeSet(script(), pc, &barrier); types::StackTypeSet *returnTypes = oracle->returnTypeSet(script(), pc, &barrier);
JS_ASSERT(returnTypes); JS_ASSERT(returnTypes);
return returnTypes; return returnTypes;
} }
@ -129,65 +96,78 @@ IonBuilder::getInlineReturnType()
} }
types::StackTypeSet * 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); JS_ASSERT(argTypes);
return argTypes; return argTypes;
} }
MIRType 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()); return MIRTypeFromValueType(argTypes->getKnownTypeTag());
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
if (argc != 1) if (callInfo.argc() != 1)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Double) if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (!IsNumberType(getInlineArgType(argc, 1))) if (!IsNumberType(getInlineArgType(callInfo, 0)))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MathCache *cache = cx->runtime->getMathCache(cx); MathCache *cache = cx->runtime->getMathCache(cx);
if (!cache) if (!cache)
return InliningStatus_Error; return InliningStatus_Error;
MMathFunction *ins = MMathFunction::New(argv[1], function, cache); MMathFunction *ins = MMathFunction::New(callInfo.getArg(0), function, cache);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineArray(uint32_t argc, bool constructing) IonBuilder::inlineArray(CallInfo &callInfo)
{ {
uint32_t initLength = 0; uint32_t initLength = 0;
MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating; MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating;
// Multiple arguments imply array initialization, not just construction. // Multiple arguments imply array initialization, not just construction.
if (argc >= 2) { if (callInfo.argc() >= 2) {
initLength = argc; initLength = callInfo.argc();
allocating = MNewArray::NewArray_Allocating; allocating = MNewArray::NewArray_Allocating;
} }
// A single integer argument denotes initial length. // A single integer argument denotes initial length.
if (argc == 1) { if (callInfo.argc() == 1) {
if (getInlineArgType(argc, 1) != MIRType_Int32) if (getInlineArgType(callInfo, 0) != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinition *arg = current->peek(-1)->toPassArg()->getArgument(); MDefinition *arg = callInfo.getArg(0)->toPassArg()->getArgument();
if (!arg->isConstant()) if (!arg->isConstant())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
@ -197,9 +177,7 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
} }
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
JSObject *templateObject = getNewArrayTemplateObject(initLength); JSObject *templateObject = getNewArrayTemplateObject(initLength);
if (!templateObject) if (!templateObject)
@ -213,7 +191,7 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
if (argc >= 2) { if (callInfo.argc() >= 2) {
// Get the elements vector. // Get the elements vector.
MElements *elements = MElements::New(ins); MElements *elements = MElements::New(ins);
current->add(elements); current->add(elements);
@ -226,7 +204,7 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
id = MConstant::New(Int32Value(i)); id = MConstant::New(Int32Value(i));
current->add(id); current->add(id);
MDefinition *value = argv[i + 1]; MDefinition *value = callInfo.getArg(i);
if (convertDoubles) { if (convertDoubles) {
MInstruction *valueDouble = MToDouble::New(value); MInstruction *valueDouble = MToDouble::New(value);
current->add(valueDouble); current->add(valueDouble);
@ -250,15 +228,15 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType(); MIRType returnType = getInlineReturnType();
if (returnType == MIRType_Undefined || returnType == MIRType_Null) if (returnType == MIRType_Undefined || returnType == MIRType_Null)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_Object) if (getInlineThisType(callInfo) != MIRType_Object)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
// Pop and shift are only handled for dense arrays that have never been // Pop and shift are only handled for dense arrays that have never been
@ -272,7 +250,7 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool c
types::OBJECT_FLAG_LENGTH_OVERFLOW | types::OBJECT_FLAG_LENGTH_OVERFLOW |
types::OBJECT_FLAG_ITERATED; types::OBJECT_FLAG_ITERATED;
types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0); types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
if (thisTypes->getKnownClass() != &ArrayClass) if (thisTypes->getKnownClass() != &ArrayClass)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(cx, unhandledFlags)) if (thisTypes->hasObjectFlags(cx, unhandledFlags))
@ -281,15 +259,14 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool c
if (types::ArrayPrototypeHasIndexedProperty(cx, script)) if (types::ArrayPrototypeHasIndexedProperty(cx, script))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
types::StackTypeSet *returnTypes = getInlineReturnTypeSet(); types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED); bool needsHoleCheck = thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED);
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType()); 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->add(ins);
current->push(ins); current->push(ins);
ins->setResultType(returnType); ins->setResultType(returnType);
@ -300,19 +277,19 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool c
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Int32) if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_Object) if (getInlineThisType(callInfo) != MIRType_Object)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
// Inference's TypeConstraintCall generates the constraints that propagate // Inference's TypeConstraintCall generates the constraints that propagate
// properties directly into the result type set. // properties directly into the result type set.
types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0); types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
if (thisTypes->getKnownClass() != &ArrayClass) if (thisTypes->getKnownClass() != &ArrayClass)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES | if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPARSE_INDEXES |
@ -328,11 +305,9 @@ IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
if (conversion == types::StackTypeSet::AmbiguousDoubleConversion) if (conversion == types::StackTypeSet::AmbiguousDoubleConversion)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MDefinition *value = argv[1]; MDefinition *value = callInfo.getArg(0);
if (conversion == types::StackTypeSet::AlwaysConvertToDoubles || if (conversion == types::StackTypeSet::AlwaysConvertToDoubles ||
conversion == types::StackTypeSet::MaybeConvertToDoubles) conversion == types::StackTypeSet::MaybeConvertToDoubles)
{ {
@ -341,7 +316,7 @@ IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
value = valueDouble; value = valueDouble;
} }
MArrayPush *ins = MArrayPush::New(argv[0], value); MArrayPush *ins = MArrayPush::New(callInfo.thisArg(), value);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
@ -351,22 +326,22 @@ IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
// Ensure |this|, argument and result are objects. // Ensure |this|, argument and result are objects.
if (getInlineReturnType() != MIRType_Object) if (getInlineReturnType() != MIRType_Object)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_Object) if (getInlineThisType(callInfo) != MIRType_Object)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 1) != MIRType_Object) if (getInlineArgType(callInfo, 0) != MIRType_Object)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
// |this| and the argument must be dense arrays. // |this| and the argument must be dense arrays.
types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0); types::StackTypeSet *thisTypes = getInlineThisTypeSet(callInfo);
types::StackTypeSet *argTypes = getInlineArgTypeSet(argc, 1); types::StackTypeSet *argTypes = getInlineArgTypeSet(callInfo, 0);
if (thisTypes->getKnownClass() != &ArrayClass) if (thisTypes->getKnownClass() != &ArrayClass)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
@ -431,11 +406,9 @@ IonBuilder::inlineArrayConcat(uint32_t argc, bool constructing)
return InliningStatus_Error; return InliningStatus_Error;
templateObj->setType(thisType); templateObj->setType(thisType);
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MArrayConcat *ins = MArrayConcat::New(argv[0], argv[1], templateObj); MArrayConcat *ins = MArrayConcat::New(callInfo.thisArg(), callInfo.getArg(0), templateObj);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
@ -445,26 +418,24 @@ IonBuilder::inlineArrayConcat(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathAbs(uint32_t argc, bool constructing) IonBuilder::inlineMathAbs(CallInfo &callInfo)
{ {
if (constructing) if (callInfo.constructing())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argc != 1) if (callInfo.argc() != 1)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType(); MIRType returnType = getInlineReturnType();
MIRType argType = getInlineArgType(argc, 1); MIRType argType = getInlineArgType(callInfo, 0);
if (argType != MIRType_Int32 && argType != MIRType_Double) if (argType != MIRType_Int32 && argType != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argType != returnType) if (argType != returnType)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MAbs *ins = MAbs::New(argv[1], returnType); MAbs *ins = MAbs::New(callInfo.getArg(0), returnType);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
@ -472,33 +443,29 @@ IonBuilder::inlineMathAbs(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathFloor(uint32_t argc, bool constructing) IonBuilder::inlineMathFloor(CallInfo &callInfo)
{ {
if (constructing) if (callInfo.constructing())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argc != 1) if (callInfo.argc() != 1)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(argc, 1); MIRType argType = getInlineArgType(callInfo, 0);
if (getInlineReturnType() != MIRType_Int32) if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
// Math.floor(int(x)) == int(x) // Math.floor(int(x)) == int(x)
if (argType == MIRType_Int32) { if (argType == MIRType_Int32) {
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current)) current->push(callInfo.getArg(0));
return InliningStatus_Error;
current->push(argv[1]);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
if (argType == MIRType_Double) { if (argType == MIRType_Double) {
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current)) MFloor *ins = new MFloor(callInfo.getArg(0));
return InliningStatus_Error;
MFloor *ins = new MFloor(argv[1]);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
return InliningStatus_Inlined; return InliningStatus_Inlined;
@ -508,31 +475,27 @@ IonBuilder::inlineMathFloor(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathRound(uint32_t argc, bool constructing) IonBuilder::inlineMathRound(CallInfo &callInfo)
{ {
if (constructing) if (callInfo.constructing())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argc != 1) if (callInfo.argc() != 1)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType(); MIRType returnType = getInlineReturnType();
MIRType argType = getInlineArgType(argc, 1); MIRType argType = getInlineArgType(callInfo, 0);
// Math.round(int(x)) == int(x) // Math.round(int(x)) == int(x)
if (argType == MIRType_Int32 && returnType == MIRType_Int32) { if (argType == MIRType_Int32 && returnType == MIRType_Int32) {
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current)) current->push(callInfo.getArg(0));
return InliningStatus_Error;
current->push(argv[1]);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
if (argType == MIRType_Double && returnType == MIRType_Int32) { if (argType == MIRType_Double && returnType == MIRType_Int32) {
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current)) MRound *ins = new MRound(callInfo.getArg(0));
return InliningStatus_Error;
MRound *ins = new MRound(argv[1]);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
return InliningStatus_Inlined; return InliningStatus_Inlined;
@ -542,72 +505,71 @@ IonBuilder::inlineMathRound(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathSqrt(uint32_t argc, bool constructing) IonBuilder::inlineMathSqrt(CallInfo &callInfo)
{ {
if (constructing) if (callInfo.constructing())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argc != 1) if (callInfo.argc() != 1)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(argc, 1); MIRType argType = getInlineArgType(callInfo, 0);
if (getInlineReturnType() != MIRType_Double) if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argType != MIRType_Double && argType != MIRType_Int32) if (argType != MIRType_Double && argType != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MSqrt *sqrt = MSqrt::New(argv[1]); MSqrt *sqrt = MSqrt::New(callInfo.getArg(0));
current->add(sqrt); current->add(sqrt);
current->push(sqrt); current->push(sqrt);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathPow(uint32_t argc, bool constructing) IonBuilder::inlineMathPow(CallInfo &callInfo)
{ {
if (constructing) if (callInfo.constructing())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (argc != 2) if (callInfo.argc() != 2)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
// Typechecking. // Typechecking.
if (getInlineReturnType() != MIRType_Double) if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType arg1Type = getInlineArgType(argc, 1); MIRType baseType = getInlineArgType(callInfo, 0);
MIRType arg2Type = getInlineArgType(argc, 2); MIRType powerType = getInlineArgType(callInfo, 1);
if (arg1Type != MIRType_Int32 && arg1Type != MIRType_Double) if (baseType != MIRType_Int32 && baseType != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (arg2Type != MIRType_Int32 && arg2Type != MIRType_Double) if (powerType != MIRType_Int32 && powerType != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
// If the non-power input is integer, convert it to a Double. MDefinition *base = callInfo.getArg(0);
MDefinition *power = callInfo.getArg(1);
// If the base is integer, convert it to a Double.
// Safe since the output must be a Double. // Safe since the output must be a Double.
if (arg1Type == MIRType_Int32) { if (baseType == MIRType_Int32) {
MToDouble *conv = MToDouble::New(argv[1]); MToDouble *conv = MToDouble::New(base);
current->add(conv); current->add(conv);
argv[1] = conv; base = conv;
} }
// Optimize some constant powers. // Optimize some constant powers.
if (argv[2]->isConstant()) { if (callInfo.getArg(1)->isConstant()) {
double pow; double pow;
if (!ToNumber(GetIonContext()->cx, argv[2]->toConstant()->value(), &pow)) if (!ToNumber(GetIonContext()->cx, callInfo.getArg(1)->toConstant()->value(), &pow))
return InliningStatus_Error; return InliningStatus_Error;
// Math.pow(x, 0.5) is a sqrt with edge-case detection. // Math.pow(x, 0.5) is a sqrt with edge-case detection.
if (pow == 0.5) { if (pow == 0.5) {
MPowHalf *half = MPowHalf::New(argv[1]); MPowHalf *half = MPowHalf::New(base);
current->add(half); current->add(half);
current->push(half); current->push(half);
return InliningStatus_Inlined; return InliningStatus_Inlined;
@ -615,7 +577,7 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases. // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
if (pow == -0.5) { if (pow == -0.5) {
MPowHalf *half = MPowHalf::New(argv[1]); MPowHalf *half = MPowHalf::New(base);
current->add(half); current->add(half);
MConstant *one = MConstant::New(DoubleValue(1.0)); MConstant *one = MConstant::New(DoubleValue(1.0));
current->add(one); current->add(one);
@ -627,13 +589,13 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// Math.pow(x, 1) == x. // Math.pow(x, 1) == x.
if (pow == 1.0) { if (pow == 1.0) {
current->push(argv[1]); current->push(base);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
// Math.pow(x, 2) == x*x. // Math.pow(x, 2) == x*x.
if (pow == 2.0) { 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->add(mul);
current->push(mul); current->push(mul);
return InliningStatus_Inlined; return InliningStatus_Inlined;
@ -641,9 +603,9 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// Math.pow(x, 3) == x*x*x. // Math.pow(x, 3) == x*x*x.
if (pow == 3.0) { 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); current->add(mul1);
MMul *mul2 = MMul::New(argv[1], mul1, MIRType_Double); MMul *mul2 = MMul::New(base, mul1, MIRType_Double);
current->add(mul2); current->add(mul2);
current->push(mul2); current->push(mul2);
return InliningStatus_Inlined; return InliningStatus_Inlined;
@ -651,7 +613,7 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// Math.pow(x, 4) == y*y, where y = x*x. // Math.pow(x, 4) == y*y, where y = x*x.
if (pow == 4.0) { 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); current->add(y);
MMul *mul = MMul::New(y, y, MIRType_Double); MMul *mul = MMul::New(y, y, MIRType_Double);
current->add(mul); current->add(mul);
@ -660,24 +622,22 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
} }
} }
MPow *ins = MPow::New(argv[1], argv[2], arg2Type); MPow *ins = MPow::New(base, power, powerType);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathRandom(uint32_t argc, bool constructing) IonBuilder::inlineMathRandom(CallInfo &callInfo)
{ {
if (constructing) if (callInfo.constructing())
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Double) if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MRandom *rand = MRandom::New(); MRandom *rand = MRandom::New();
current->add(rand); current->add(rand);
@ -686,28 +646,26 @@ IonBuilder::inlineMathRandom(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType(); MIRType returnType = getInlineReturnType();
if (returnType != MIRType_Int32) if (returnType != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (!IsNumberType(getInlineArgType(argc, 1))) if (!IsNumberType(getInlineArgType(callInfo, 0)))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (!IsNumberType(getInlineArgType(argc, 2))) if (!IsNumberType(getInlineArgType(callInfo, 1)))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MInstruction *first = MTruncateToInt32::New(argv[1]); MInstruction *first = MTruncateToInt32::New(callInfo.getArg(0));
current->add(first); current->add(first);
MInstruction *second = MTruncateToInt32::New(argv[2]); MInstruction *second = MTruncateToInt32::New(callInfo.getArg(1));
current->add(second); current->add(second);
MMul *ins = MMul::New(first, second, MIRType_Int32, MMul::Integer); MMul *ins = MMul::New(first, second, MIRType_Int32, MMul::Integer);
@ -717,60 +675,56 @@ IonBuilder::inlineMathImul(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType(); MIRType returnType = getInlineReturnType();
if (!IsNumberType(returnType)) if (!IsNumberType(returnType))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType arg1Type = getInlineArgType(argc, 1); MIRType arg0Type = getInlineArgType(callInfo, 0);
if (!IsNumberType(arg1Type)) if (!IsNumberType(arg0Type))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType arg2Type = getInlineArgType(argc, 2); MIRType arg1Type = getInlineArgType(callInfo, 1);
if (!IsNumberType(arg2Type)) if (!IsNumberType(arg1Type))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (returnType == MIRType_Int32 && 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. // We would need to inform TI, if we happen to return a double.
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
} }
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
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->add(ins);
current->push(ins); current->push(ins);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
// MToString only supports int32 or string values. // MToString only supports int32 or string values.
MIRType type = getInlineArgType(argc, 1); MIRType type = getInlineArgType(callInfo, 0);
if (type != MIRType_Int32 && type != MIRType_String) if (type != MIRType_Int32 && type != MIRType_String)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
RootedString emptyString(cx, cx->runtime->emptyString); RootedString emptyString(cx, cx->runtime->emptyString);
RootedObject templateObj(cx, StringObject::create(cx, emptyString)); RootedObject templateObj(cx, StringObject::create(cx, emptyString));
if (!templateObj) if (!templateObj)
return InliningStatus_Error; return InliningStatus_Error;
MNewStringObject *ins = MNewStringObject::New(argv[1], templateObj); MNewStringObject *ins = MNewStringObject::New(callInfo.getArg(0), templateObj);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
@ -781,53 +735,49 @@ IonBuilder::inlineStringObject(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Int32) if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_String) if (getInlineThisType(callInfo) != MIRType_String)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(argc, 1); MIRType argType = getInlineArgType(callInfo, 0);
if (argType != MIRType_Int32 && argType != MIRType_Double) if (argType != MIRType_Int32 && argType != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MInstruction *index = MToInt32::New(argv[1]); MInstruction *index = MToInt32::New(callInfo.getArg(0));
current->add(index); current->add(index);
MStringLength *length = MStringLength::New(argv[0]); MStringLength *length = MStringLength::New(callInfo.thisArg());
current->add(length); current->add(length);
index = addBoundsCheck(index, length); index = addBoundsCheck(index, length);
MCharCodeAt *charCode = MCharCodeAt::New(argv[0], index); MCharCodeAt *charCode = MCharCodeAt::New(callInfo.thisArg(), index);
current->add(charCode); current->add(charCode);
current->push(charCode); current->push(charCode);
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_String) if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 1) != MIRType_Int32) if (getInlineArgType(callInfo, 0) != MIRType_Int32)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MToInt32 *charCode = MToInt32::New(argv[1]); MToInt32 *charCode = MToInt32::New(callInfo.getArg(0));
current->add(charCode); current->add(charCode);
MFromCharCode *string = MFromCharCode::New(charCode); MFromCharCode *string = MFromCharCode::New(charCode);
@ -837,33 +787,31 @@ IonBuilder::inlineStrFromCharCode(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_String) if (getInlineReturnType() != MIRType_String)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_String) if (getInlineThisType(callInfo) != MIRType_String)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MIRType argType = getInlineArgType(argc, 1); MIRType argType = getInlineArgType(callInfo, 0);
if (argType != MIRType_Int32 && argType != MIRType_Double) if (argType != MIRType_Int32 && argType != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MInstruction *index = MToInt32::New(argv[1]); MInstruction *index = MToInt32::New(callInfo.getArg(0));
current->add(index); current->add(index);
MStringLength *length = MStringLength::New(argv[0]); MStringLength *length = MStringLength::New(callInfo.thisArg());
current->add(length); current->add(length);
index = addBoundsCheck(index, length); index = addBoundsCheck(index, length);
// String.charAt(x) = String.fromCharCode(String.charCodeAt(x)) // 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); current->add(charCode);
MFromCharCode *string = MFromCharCode::New(charCode); MFromCharCode *string = MFromCharCode::New(charCode);
@ -873,25 +821,23 @@ IonBuilder::inlineStrCharAt(uint32_t argc, bool constructing)
} }
IonBuilder::InliningStatus 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; return InliningStatus_NotInlined;
// TI can infer a NULL return type of regexp_test with eager compilation. // TI can infer a NULL return type of regexp_test with eager compilation.
if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean) if (CallResultEscapes(pc) && getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_Object) if (getInlineThisType(callInfo) != MIRType_Object)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
if (getInlineArgType(argc, 1) != MIRType_String) if (getInlineArgType(callInfo, 0) != MIRType_String)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinitionVector argv; callInfo.unwrapArgs();
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
MInstruction *match = MRegExpTest::New(argv[0], argv[1]); MInstruction *match = MRegExpTest::New(callInfo.thisArg(), callInfo.getArg(0));
current->add(match); current->add(match);
current->push(match); current->push(match);
if (!resumeAfter(match)) if (!resumeAfter(match))