Bug 824473: IonMonkey: Enable inlining of JSOP_FUNAPPLY, r=dvander

This commit is contained in:
Hannes Verschore 2013-01-27 22:51:41 +01:00
parent 8b45633296
commit ceda8b6153
9 changed files with 72 additions and 7 deletions

View File

@ -179,7 +179,12 @@ StackFrame::initFromBailout(JSContext *cx, SnapshotIterator &iter)
IonSpew(IonSpew_Bailouts, " new PC is offset %u within script %p (line %d)",
pcOff, (void *)script(), PCToLineNumber(script(), regs.pc));
JS_ASSERT(exprStackSlots == js_ReconstructStackDepth(cx, script(), regs.pc));
// For fun.apply({}, arguments) the reconstructStackDepth will have stackdepth 4,
// but it could be that we inlined the funapply. In that case exprStackSlots,
// will have the real arguments in the slots and not be 4.
JS_ASSERT_IF(JSOp(*regs.pc) != JSOP_FUNAPPLY,
exprStackSlots == js_ReconstructStackDepth(cx, script(), regs.pc));
}
static StackFrame *
@ -192,8 +197,11 @@ PushInlinedFrame(JSContext *cx, StackFrame *callerFrame)
// which will not be the case when we inline getters (in which case it would be a
// JSOP_GETPROP). That will have to be handled differently.
FrameRegs &regs = cx->regs();
JS_ASSERT(JSOp(*regs.pc) == JSOP_CALL || JSOp(*regs.pc) == JSOP_NEW);
JS_ASSERT(JSOp(*regs.pc) == JSOP_CALL || JSOp(*regs.pc) == JSOP_NEW ||
JSOp(*regs.pc) == JSOP_FUNAPPLY);
int callerArgc = GET_ARGC(regs.pc);
if (JSOp(*regs.pc) == JSOP_FUNAPPLY)
callerArgc = callerFrame->nactual();
const Value &calleeVal = regs.sp[-callerArgc - 2];
RootedFunction fun(cx, calleeVal.toObject().toFunction());

View File

@ -46,6 +46,20 @@ class FixedList
length_ -= num;
}
bool increase(size_t num) {
T *list = (T *)GetIonContext()->temp->allocate((length_ + num) * sizeof(T));
if (list != NULL) {
for (size_t i = 0; i < length_; i++)
list[i] = list_[i];
length_ += num;
list_ = list;
return true;
}
return false;
}
T &operator[](size_t index) {
JS_ASSERT(index < length_);
return list_[index];

View File

@ -2856,6 +2856,11 @@ IonBuilder::inlineScriptedCall(HandleFunction target, CallInfo &callInfo)
// Create resumepoint if not provided. This resume point collects outer variables only.
// It is used to recover the stack state before the current bytecode.
// Make sure there is enough place in the slots
uint32_t depth = current->stackDepth() + callInfo.argc() + 2;
if (depth > current->nslots())
current->increaseSlots(depth - current->nslots());
// Push formals to capture in the resumepoint
callInfo.pushFormals(current);
@ -3984,8 +3989,22 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
// Pop apply function.
current->pop();
// Set type information
types::StackTypeSet *barrier;
types::StackTypeSet *types = oracle->returnTypeSet(script(), pc, &barrier);
callInfo.setTypeInfo(types, barrier);
// Try inlining call
if (target != NULL) {
AutoObjectVector targets(cx);
targets.append(target);
if (makeInliningDecision(targets, argc))
return inlineScriptedCall(target, callInfo);
}
callInfo.wrapArgs(current);
return makeCall(target, callInfo, funTypes, false);
return makeCallBarrier(target, callInfo, funTypes, false);
}
bool

View File

@ -932,7 +932,10 @@ InlineFrameIterator::findNextFrame()
JS_ASSERT(js_CodeSpec[*pc_].format & JOF_INVOKE);
// Recover the number of actual arguments from the script.
numActualArgs_ = GET_ARGC(pc_);
if (JSOp(*pc_) != JSOP_FUNAPPLY)
numActualArgs_ = GET_ARGC(pc_);
JS_ASSERT(numActualArgs_ != 0xbad);
// Skip over non-argument slots, as well as |this|.
unsigned skipCount = (si_.slots() - 1) - numActualArgs_ - 1;

View File

@ -155,6 +155,12 @@ MBasicBlock::init()
return slots_.init(info_.nslots());
}
bool
MBasicBlock::increaseSlots(size_t num)
{
return slots_.increase(num);
}
void
MBasicBlock::copySlots(MBasicBlock *from)
{
@ -341,7 +347,7 @@ MBasicBlock::rewriteAtDepth(int32_t depth, MDefinition *ins)
void
MBasicBlock::push(MDefinition *ins)
{
JS_ASSERT(stackPosition_ < info_.nslots());
JS_ASSERT(stackPosition_ < nslots());
slots_[stackPosition_++] = ins;
}

View File

@ -105,6 +105,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
MDefinition *scopeChain();
// Increase the number of slots available
bool increaseSlots(size_t num);
// Initializes a slot value; must not be called for normal stack
// operations, as it will not create new SSA names for copies.
void initSlot(uint32_t index, MDefinition *ins);
@ -220,6 +223,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
jsbytecode *pc() const {
return pc_;
}
uint32_t nslots() const {
return slots_.length();
}
uint32_t id() const {
return id_;
}

View File

@ -541,8 +541,12 @@ TypeInferenceOracle::canInlineCall(HandleScript caller, jsbytecode *pc)
{
JS_ASSERT(types::IsInlinableCall(pc));
JSOp op = JSOp(*pc);
Bytecode *code = caller->analysis()->maybeCode(pc);
if (code->monitoredTypes)
// For foo.apply(this, arguments), the caller is foo and not the js_fun_apply function.
// Ignore code->monitoredTypes, as we know the caller is foo
if (op != JSOP_FUNAPPLY && code->monitoredTypes)
return false;
// Gets removed in Bug 796114

View File

@ -223,7 +223,11 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
DebugOnly<jsbytecode *> bailPC = pc;
if (mir->mode() == MResumePoint::ResumeAfter)
bailPC = GetNextPc(pc);
JS_ASSERT_IF(GetIonContext()->cx,
// For fun.apply({}, arguments) the reconstructStackDepth will have stackdepth 4,
// but it could be that we inlined the funapply. In that case exprStackSlots,
// will have the real arguments in the slots and not be 4.
JS_ASSERT_IF(GetIonContext()->cx && JSOp(*bailPC) != JSOP_FUNAPPLY,
exprStack == js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC));
#ifdef TRACK_SNAPSHOTS

View File

@ -433,6 +433,7 @@ class StackFrame
Value *base() const { return slots() + script()->nfixed; }
Value *formals() const { return (Value *)this - fun()->nargs; }
Value *actuals() const { return formals() - (flags_ & OVERFLOW_ARGS ? 2 + u.nactual : 0); }
unsigned nactual() const { return u.nactual; }
private:
friend class FrameRegs;