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,
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());
@ -4063,18 +4058,22 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
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);
@ -4083,7 +4082,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
if (targets.length() == 1)
target = targets[0]->toFunction();
return makeCall(target, callInfo, calleeTypes, hasClones);
return makeCallBarrier(target, callInfo, calleeTypes, hasClones);
}
MDefinition *

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

@ -382,41 +382,40 @@ class IonBuilder : public MIRGenerator
};
// 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,

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

@ -18,105 +18,72 @@ 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;
}
@ -129,65 +96,78 @@ IonBuilder::getInlineReturnType()
}
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;
@ -197,9 +177,7 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
return InliningStatus_NotInlined;
}
MDefinitionVector argv;
if (!discardCall(argc, argv, current))
return InliningStatus_Error;
callInfo.unwrapArgs();
JSObject *templateObject = getNewArrayTemplateObject(initLength);
if (!templateObject)
@ -213,7 +191,7 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
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);
@ -226,7 +204,7 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
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);
@ -250,15 +228,15 @@ IonBuilder::inlineArray(uint32_t argc, bool constructing)
}
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
@ -272,7 +250,7 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool c
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))
@ -281,15 +259,14 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool c
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);
@ -300,19 +277,19 @@ IonBuilder::inlineArrayPopShift(MArrayPopShift::Mode mode, uint32_t argc, bool c
}
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 |
@ -328,11 +305,9 @@ IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
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)
{
@ -341,7 +316,7 @@ IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
value = valueDouble;
}
MArrayPush *ins = MArrayPush::New(argv[0], value);
MArrayPush *ins = MArrayPush::New(callInfo.thisArg(), value);
current->add(ins);
current->push(ins);
@ -351,22 +326,22 @@ IonBuilder::inlineArrayPush(uint32_t argc, bool constructing)
}
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;
@ -431,11 +406,9 @@ IonBuilder::inlineArrayConcat(uint32_t argc, bool constructing)
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);
@ -445,26 +418,24 @@ IonBuilder::inlineArrayConcat(uint32_t argc, bool constructing)
}
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);
@ -472,33 +443,29 @@ IonBuilder::inlineMathAbs(uint32_t argc, bool constructing)
}
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;
@ -508,31 +475,27 @@ IonBuilder::inlineMathFloor(uint32_t argc, bool constructing)
}
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;
@ -542,72 +505,71 @@ IonBuilder::inlineMathRound(uint32_t argc, bool constructing)
}
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();
// 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.
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;
@ -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.
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);
@ -627,13 +589,13 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// 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;
@ -641,9 +603,9 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// 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;
@ -651,7 +613,7 @@ IonBuilder::inlineMathPow(uint32_t argc, bool constructing)
// 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);
@ -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->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);
@ -686,28 +646,26 @@ IonBuilder::inlineMathRandom(uint32_t argc, bool constructing)
}
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);
@ -717,60 +675,56 @@ IonBuilder::inlineMathImul(uint32_t argc, bool constructing)
}
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);
@ -781,53 +735,49 @@ IonBuilder::inlineStringObject(uint32_t argc, bool constructing)
}
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);
@ -837,33 +787,31 @@ IonBuilder::inlineStrFromCharCode(uint32_t argc, bool constructing)
}
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);
@ -873,25 +821,23 @@ IonBuilder::inlineStrCharAt(uint32_t argc, bool constructing)
}
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))