diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 2cd7dcbd78a6..e00ca7f5ff80 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -3750,7 +3750,7 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target) } // Capture formals in the outer resume point. - MOZ_TRY(callInfo.pushFormals(this, current)); + MOZ_TRY(callInfo.pushCallStack(this, current)); MResumePoint* outerResumePoint = MResumePoint::New(alloc(), current, pc, MResumePoint::Outer); @@ -3759,7 +3759,7 @@ IonBuilder::inlineScriptedCall(CallInfo& callInfo, JSFunction* target) current->setOuterResumePoint(outerResumePoint); // Pop formals again, except leave |fun| on stack for duration of call. - callInfo.popFormals(current); + callInfo.popCallStack(current); current->push(callInfo.fun()); JSScript* calleeScript = target->nonLazyScript(); @@ -4416,7 +4416,7 @@ IonBuilder::inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasic CallInfo fallbackInfo(alloc(), pc, callInfo.constructing(), callInfo.ignoresReturnValue()); if (!fallbackInfo.init(callInfo)) return abort(AbortReason::Alloc); - fallbackInfo.popFormals(fallbackBlock); + fallbackInfo.popCallStack(fallbackBlock); // Generate an MCall, which uses stateful |current|. MOZ_TRY(setCurrentAndSpecializePhis(fallbackBlock)); @@ -4473,7 +4473,7 @@ IonBuilder::inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchB MBasicBlock* prepBlock; MOZ_TRY_VAR(prepBlock, newBlock(dispatchBlock, pc)); graph().addBlock(prepBlock); - fallbackInfo.popFormals(prepBlock); + fallbackInfo.popCallStack(prepBlock); // Construct a block into which the MGetPropertyCache can be moved. // This is subtle: the pc and resume point are those of the MGetPropertyCache! @@ -4536,7 +4536,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const InliningTargets& targets, Bool MBasicBlock* dispatchBlock = current; callInfo.setImplicitlyUsedUnchecked(); - MOZ_TRY(callInfo.pushFormals(this, dispatchBlock)); + MOZ_TRY(callInfo.pushCallStack(this, dispatchBlock)); // Patch any InlinePropertyTable to only contain functions that are // inlineable. The InlinePropertyTable will also be patched at the end to @@ -4569,7 +4569,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const InliningTargets& targets, Bool // Set up stack, used to manually create a post-call resume point. returnBlock->inheritSlots(dispatchBlock); - callInfo.popFormals(returnBlock); + callInfo.popCallStack(returnBlock); MPhi* retPhi = MPhi::New(alloc()); returnBlock->addPhi(retPhi); @@ -4632,7 +4632,7 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const InliningTargets& targets, Bool CallInfo inlineInfo(alloc(), pc, callInfo.constructing(), callInfo.ignoresReturnValue()); if (!inlineInfo.init(callInfo)) return abort(AbortReason::Alloc); - inlineInfo.popFormals(inlineBlock); + inlineInfo.popCallStack(inlineBlock); inlineInfo.setFun(funcDef); if (maybeCache) { @@ -5264,6 +5264,20 @@ IonBuilder::jsop_funapplyarray(uint32_t argc) return pushTypeBarrier(apply, types, BarrierKind::TypeSet); } +AbortReasonOr +CallInfo::savePriorCallStack(MIRGenerator* mir, MBasicBlock* current, size_t peekDepth) +{ + MOZ_ASSERT(priorArgs_.empty()); + if (!priorArgs_.reserve(peekDepth)) + return mir->abort(AbortReason::Alloc); + while (peekDepth) { + priorArgs_.infallibleAppend(current->peek(0 - int32_t(peekDepth))); + peekDepth--; + } + return Ok(); +} + + AbortReasonOr IonBuilder::jsop_funapplyarguments(uint32_t argc) { @@ -5319,6 +5333,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc) CallInfo callInfo(alloc(), pc, /* constructing = */ false, /* ignoresReturnValue = */ BytecodeIsPopped(pc)); + callInfo.savePriorCallStack(this, current, 4); // Vp MDefinition* vp = current->pop(); diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 9f252bf0ef22..a9339e4b82e4 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1192,6 +1192,9 @@ class CallInfo MDefinition* thisArg_; MDefinition* newTargetArg_; MDefinitionVector args_; + // If non-empty, this corresponds to the stack prior any implicit inlining + // such as before JSOP_FUNAPPLY. + MDefinitionVector priorArgs_; bool constructing_:1; @@ -1207,6 +1210,7 @@ class CallInfo thisArg_(nullptr), newTargetArg_(nullptr), args_(alloc), + priorArgs_(alloc), constructing_(constructing), ignoresReturnValue_(ignoresReturnValue), setter_(false), @@ -1250,11 +1254,30 @@ class CallInfo return true; } - void popFormals(MBasicBlock* current) { + // Before doing any pop to the stack, capture whatever flows into the + // instruction, such that we can restore it later. + AbortReasonOr savePriorCallStack(MIRGenerator* mir, MBasicBlock* current, size_t peekDepth); + + void popPriorCallStack(MBasicBlock* current) { + if (priorArgs_.empty()) + popCallStack(current); + else + current->popn(priorArgs_.length()); + } + + AbortReasonOr pushPriorCallStack(MIRGenerator* mir, MBasicBlock* current) { + if (priorArgs_.empty()) + return pushCallStack(mir, current); + for (MDefinition* def : priorArgs_) + current->push(def); + return Ok(); + } + + void popCallStack(MBasicBlock* current) { current->popn(numFormals()); } - AbortReasonOr pushFormals(MIRGenerator* mir, MBasicBlock* current) { + AbortReasonOr pushCallStack(MIRGenerator* mir, MBasicBlock* current) { // Ensure sufficient space in the slots: needed for inlining from FUNAPPLY. if (apply_) { uint32_t depth = current->stackDepth() + numFormals(); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index ea6e10e8bd83..98a6a07d7897 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -846,7 +846,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) // Restore the stack, such that resume points are created with the stack // as it was before the call. - MOZ_TRY(callInfo.pushFormals(this, current)); + callInfo.pushPriorCallStack(this, current); } MInstruction* ins = nullptr; @@ -879,7 +879,7 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo) if (callInfo.argc() > 1) { // Fix the stack to represent the state after the call execution. - callInfo.popFormals(current); + callInfo.popPriorCallStack(current); } current->push(ins);