зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1057082 - 5/7 - Remove SPS instrumentation and replace with exitaddr instrumentation. r=jandem
This commit is contained in:
Родитель
1c98a3a982
Коммит
fc658deb60
|
@ -50,31 +50,17 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
|
|||
MOZ_ASSERT(IsBaselineEnabled(cx));
|
||||
|
||||
*bailoutInfo = nullptr;
|
||||
bool poppedLastSPSFrame = false;
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
|
||||
/* excInfo = */ nullptr, &poppedLastSPSFrame);
|
||||
/* excInfo = */ nullptr);
|
||||
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
|
||||
retval == BAILOUT_RETURN_FATAL_ERROR ||
|
||||
retval == BAILOUT_RETURN_OVERRECURSED);
|
||||
MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
|
||||
|
||||
if (retval != BAILOUT_RETURN_OK) {
|
||||
// If the bailout failed, then bailout trampoline will pop the
|
||||
// current frame and jump straight to exception handling code when
|
||||
// this function returns. Any SPS entry pushed for this frame will
|
||||
// be silently forgotten.
|
||||
//
|
||||
// We call ExitScript here to ensure that if the ionScript had SPS
|
||||
// instrumentation, then the SPS entry for it is popped.
|
||||
//
|
||||
// However, if the bailout was during argument check, then a
|
||||
// pseudostack frame would not have been pushed in the first
|
||||
// place, so don't pop anything in that case.
|
||||
bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
|
||||
(SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
|
||||
!poppedLastSPSFrame;
|
||||
JSScript *script = iter.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
/* popSPSFrame = */ false);
|
||||
|
||||
EnsureExitFrame(iter.jsFrame());
|
||||
}
|
||||
|
@ -140,9 +126,8 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
|
|||
MOZ_ASSERT(IsBaselineEnabled(cx));
|
||||
|
||||
*bailoutInfo = nullptr;
|
||||
bool poppedLastSPSFrame = false;
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo,
|
||||
/* excInfo = */ nullptr, &poppedLastSPSFrame);
|
||||
/* excInfo = */ nullptr);
|
||||
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
|
||||
retval == BAILOUT_RETURN_FATAL_ERROR ||
|
||||
retval == BAILOUT_RETURN_OVERRECURSED);
|
||||
|
@ -160,11 +145,9 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
|
|||
// However, if the bailout was during argument check, then a
|
||||
// pseudostack frame would not have been pushed in the first
|
||||
// place, so don't pop anything in that case.
|
||||
bool popSPSFrame = iter.ionScript()->hasSPSInstrumentation() &&
|
||||
(SnapshotIterator(iter).bailoutKind() != Bailout_ArgumentCheck) &&
|
||||
!poppedLastSPSFrame;
|
||||
JSScript *script = iter.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
/* popSPSFrame = */ false);
|
||||
|
||||
JitFrameLayout *frame = iter.jsFrame();
|
||||
JitSpew(JitSpew_IonInvalidate, "Bailout failed (%s): converting to exit frame",
|
||||
|
@ -207,7 +190,7 @@ uint32_t
|
|||
jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
|
||||
ResumeFromException *rfe,
|
||||
const ExceptionBailoutInfo &excInfo,
|
||||
bool *overrecursed, bool *poppedLastSPSFrameOut)
|
||||
bool *overrecursed)
|
||||
{
|
||||
// We can be propagating debug mode exceptions without there being an
|
||||
// actual exception pending. For instance, when we return false from an
|
||||
|
@ -224,7 +207,7 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
|
|||
|
||||
BaselineBailoutInfo *bailoutInfo = nullptr;
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true,
|
||||
&bailoutInfo, &excInfo, poppedLastSPSFrameOut);
|
||||
&bailoutInfo, &excInfo);
|
||||
|
||||
if (retval == BAILOUT_RETURN_OK) {
|
||||
MOZ_ASSERT(bailoutInfo);
|
||||
|
|
|
@ -209,7 +209,7 @@ class ExceptionBailoutInfo
|
|||
uint32_t ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
|
||||
ResumeFromException *rfe,
|
||||
const ExceptionBailoutInfo &excInfo,
|
||||
bool *overrecursed, bool *poppedLastSPSFrameOut);
|
||||
bool *overrecursed);
|
||||
|
||||
uint32_t FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo);
|
||||
|
||||
|
|
|
@ -551,16 +551,13 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
HandleFunction fun, HandleScript script, IonScript *ionScript,
|
||||
SnapshotIterator &iter, bool invalidate, BaselineStackBuilder &builder,
|
||||
AutoValueVector &startFrameFormals, MutableHandleFunction nextCallee,
|
||||
jsbytecode **callPC, const ExceptionBailoutInfo *excInfo,
|
||||
bool *poppedLastSPSFrameOut)
|
||||
jsbytecode **callPC, const ExceptionBailoutInfo *excInfo)
|
||||
{
|
||||
// The Baseline frames we will reconstruct on the heap are not rooted, so GC
|
||||
// must be suppressed here.
|
||||
MOZ_ASSERT(cx->mainThread().suppressGC);
|
||||
|
||||
MOZ_ASSERT(script->hasBaselineScript());
|
||||
MOZ_ASSERT(poppedLastSPSFrameOut);
|
||||
MOZ_ASSERT(!*poppedLastSPSFrameOut);
|
||||
|
||||
// Are we catching an exception?
|
||||
bool catchingException = excInfo && excInfo->catchingException();
|
||||
|
@ -626,16 +623,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
|
||||
uint32_t flags = 0;
|
||||
|
||||
// If SPS Profiler is enabled, mark the frame as having pushed an SPS entry.
|
||||
// This may be wrong for the last frame of ArgumentCheck bailout, but
|
||||
// that will be fixed later.
|
||||
if (ionScript->hasSPSInstrumentation()) {
|
||||
if (callerPC == nullptr) {
|
||||
JitSpew(JitSpew_BaselineBailouts, " Setting SPS flag on top frame!");
|
||||
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are bailing to a script whose execution is observed, mark the
|
||||
// baseline frame as a debuggee frame. This is to cover the case where we
|
||||
// don't rematerialize the Ion frame via the Debugger.
|
||||
|
@ -1098,35 +1085,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
opReturnAddr = baselineScript->prologueEntryAddr();
|
||||
JitSpew(JitSpew_BaselineBailouts, " Resuming into prologue.");
|
||||
|
||||
// If bailing into prologue, HAS_PUSHED_SPS_FRAME should not be set on frame.
|
||||
blFrame->unsetPushedSPSFrame();
|
||||
|
||||
if (cx->runtime()->spsProfiler.enabled()) {
|
||||
// 1. If resuming into inline code, then the top SPS entry will be
|
||||
// for the outermost caller, and will have an uninitialized PC.
|
||||
// This will be fixed up later in BailoutIonToBaseline.
|
||||
//
|
||||
// 2. If resuming into top-level code prologue, with ArgumentCheck,
|
||||
// no SPS entry will have been pushed. Can be left alone.
|
||||
//
|
||||
// 3. If resuming into top-level code prologue, without ArgumentCheck,
|
||||
// an SPS entry will have been pushed, and needs to be popped.
|
||||
//
|
||||
// 4. If resuming into top-level code main body, an SPS entry will
|
||||
// have been pushed, and can be left alone.
|
||||
//
|
||||
// Only need to handle case 3 here.
|
||||
if (!caller && bailoutKind != Bailout_ArgumentCheck) {
|
||||
JitSpew(JitSpew_BaselineBailouts,
|
||||
" Popping SPS entry for outermost frame");
|
||||
cx->runtime()->spsProfiler.exit(script, fun);
|
||||
|
||||
// Notify caller that the last SPS frame was popped, so not
|
||||
// to do it again.
|
||||
if (poppedLastSPSFrameOut)
|
||||
*poppedLastSPSFrameOut = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
opReturnAddr = nativeCodeForPC;
|
||||
}
|
||||
|
@ -1135,16 +1093,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
}
|
||||
|
||||
if (cx->runtime()->spsProfiler.enabled()) {
|
||||
if (blFrame->hasPushedSPSFrame()) {
|
||||
// Set PC index to 0 for the innermost frame to match what the
|
||||
// interpreter and Baseline do: they update the SPS pc for
|
||||
// JSOP_CALL ops but set it to 0 when running other ops. Ion code
|
||||
// can set the pc to NullPCIndex and this will confuse SPS when
|
||||
// Baseline calls into the VM at non-CALL ops and re-enters JS.
|
||||
JitSpew(JitSpew_BaselineBailouts, " Setting PCidx for last frame to 0");
|
||||
cx->runtime()->spsProfiler.updatePC(script, script->code());
|
||||
}
|
||||
|
||||
// Register bailout with profiler.
|
||||
const char *filename = script->filename();
|
||||
if (filename == nullptr)
|
||||
|
@ -1381,14 +1329,11 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
uint32_t
|
||||
jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
|
||||
bool invalidate, BaselineBailoutInfo **bailoutInfo,
|
||||
const ExceptionBailoutInfo *excInfo, bool *poppedLastSPSFrameOut)
|
||||
const ExceptionBailoutInfo *excInfo)
|
||||
{
|
||||
MOZ_ASSERT(bailoutInfo != nullptr);
|
||||
MOZ_ASSERT(*bailoutInfo == nullptr);
|
||||
|
||||
MOZ_ASSERT(poppedLastSPSFrameOut);
|
||||
MOZ_ASSERT(!*poppedLastSPSFrameOut);
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogStopEvent(logger, TraceLogger_IonMonkey);
|
||||
TraceLogStartEvent(logger, TraceLogger_Baseline);
|
||||
|
@ -1492,9 +1437,6 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
|||
RootedFunction fun(cx, callee);
|
||||
AutoValueVector startFrameFormals(cx);
|
||||
|
||||
RootedScript topCaller(cx);
|
||||
jsbytecode *topCallerPC = nullptr;
|
||||
|
||||
gc::AutoSuppressGC suppress(cx);
|
||||
|
||||
while (true) {
|
||||
|
@ -1524,8 +1466,7 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
|||
RootedFunction nextCallee(cx, nullptr);
|
||||
if (!InitFromBailout(cx, caller, callerPC, fun, scr, iter.ionScript(),
|
||||
snapIter, invalidate, builder, startFrameFormals,
|
||||
&nextCallee, &callPC, passExcInfo ? excInfo : nullptr,
|
||||
poppedLastSPSFrameOut))
|
||||
&nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
|
||||
{
|
||||
return BAILOUT_RETURN_FATAL_ERROR;
|
||||
}
|
||||
|
@ -1545,24 +1486,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
|
|||
fun = nextCallee;
|
||||
scr = fun->existingScriptForInlinedFunction();
|
||||
|
||||
// Save top caller info for adjusting SPS frames later.
|
||||
if (!topCaller) {
|
||||
MOZ_ASSERT(frameNo == 0);
|
||||
topCaller = caller;
|
||||
topCallerPC = callerPC;
|
||||
}
|
||||
|
||||
frameNo++;
|
||||
|
||||
snapIter.nextInstruction();
|
||||
}
|
||||
JitSpew(JitSpew_BaselineBailouts, " Done restoring frames");
|
||||
|
||||
// If there were multiple inline frames unpacked, then the current top SPS frame
|
||||
// is for the outermost caller, and has an uninitialized PC. Initialize it now.
|
||||
if (frameNo > 0)
|
||||
cx->runtime()->spsProfiler.updatePC(topCaller, topCallerPC);
|
||||
|
||||
BailoutKind bailoutKind = snapIter.bailoutKind();
|
||||
|
||||
if (!startFrameFormals.empty()) {
|
||||
|
|
|
@ -175,7 +175,6 @@ BaselineCompiler::compile()
|
|||
|
||||
prologueOffset_.fixup(&masm);
|
||||
epilogueOffset_.fixup(&masm);
|
||||
spsPushToggleOffset_.fixup(&masm);
|
||||
profilerEnterFrameToggleOffset_.fixup(&masm);
|
||||
profilerExitFrameToggleOffset_.fixup(&masm);
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
|
@ -190,7 +189,6 @@ BaselineCompiler::compile()
|
|||
mozilla::UniquePtr<BaselineScript, JS::DeletePolicy<BaselineScript> > baselineScript(
|
||||
BaselineScript::New(script, prologueOffset_.offset(),
|
||||
epilogueOffset_.offset(),
|
||||
spsPushToggleOffset_.offset(),
|
||||
profilerEnterFrameToggleOffset_.offset(),
|
||||
profilerExitFrameToggleOffset_.offset(),
|
||||
traceLoggerEnterToggleOffset_.offset(),
|
||||
|
@ -246,10 +244,6 @@ BaselineCompiler::compile()
|
|||
if (cx->zone()->needsIncrementalBarrier())
|
||||
baselineScript->toggleBarriers(true);
|
||||
|
||||
// All SPS instrumentation is emitted toggled off. Toggle them on if needed.
|
||||
if (cx->runtime()->spsProfiler.enabled())
|
||||
baselineScript->toggleSPS(true);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
// Initialize the tracelogger instrumentation.
|
||||
baselineScript->initTraceLogger(cx->runtime(), script);
|
||||
|
@ -422,9 +416,6 @@ BaselineCompiler::emitPrologue()
|
|||
if (!emitArgumentTypeChecks())
|
||||
return false;
|
||||
|
||||
if (!emitSPSPush())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -442,9 +433,6 @@ BaselineCompiler::emitEpilogue()
|
|||
return false;
|
||||
#endif
|
||||
|
||||
// Pop SPS frame if necessary
|
||||
emitSPSPop();
|
||||
|
||||
masm.mov(BaselineFrameReg, BaselineStackReg);
|
||||
masm.pop(BaselineFrameReg);
|
||||
|
||||
|
@ -839,35 +827,6 @@ BaselineCompiler::emitTraceLoggerExit()
|
|||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitSPSPush()
|
||||
{
|
||||
// Enter the IC, guarded by a toggled jump (initially disabled).
|
||||
Label noPush;
|
||||
CodeOffsetLabel toggleOffset = masm.toggledJump(&noPush);
|
||||
MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
|
||||
ICProfiler_Fallback::Compiler compiler(cx);
|
||||
if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
|
||||
return false;
|
||||
masm.bind(&noPush);
|
||||
|
||||
// Store the start offset in the appropriate location.
|
||||
MOZ_ASSERT(spsPushToggleOffset_.offset() == 0);
|
||||
spsPushToggleOffset_ = toggleOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BaselineCompiler::emitSPSPop()
|
||||
{
|
||||
// If profiler entry was pushed on this frame, pop it.
|
||||
Label noPop;
|
||||
masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
|
||||
Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), &noPop);
|
||||
masm.spsPopFrameSafe(&cx->runtime()->spsProfiler, R1.scratchReg());
|
||||
masm.bind(&noPop);
|
||||
}
|
||||
|
||||
void
|
||||
BaselineCompiler::emitProfilerEnterFrame()
|
||||
{
|
||||
|
|
|
@ -256,8 +256,6 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
|||
bool emitDebugTrap();
|
||||
bool emitTraceLoggerEnter();
|
||||
bool emitTraceLoggerExit();
|
||||
bool emitSPSPush();
|
||||
void emitSPSPop();
|
||||
|
||||
void emitProfilerEnterFrame();
|
||||
void emitProfilerExitFrame();
|
||||
|
|
|
@ -172,19 +172,6 @@ BaselineFrame::initForOsr(InterpreterFrame *fp, uint32_t numStackValues)
|
|||
if (fp->hasReturnValue())
|
||||
setReturnValue(fp->returnValue());
|
||||
|
||||
// If the interpreter pushed an SPS frame when it entered the function, the
|
||||
// interpreter will pop it after the OSR trampoline returns. In order for
|
||||
// the Baseline frame to have its SPS flag set, it must have its own SPS
|
||||
// frame, which the Baseline code will pop on return. Note that the
|
||||
// profiler may have been enabled or disabled after the function was entered
|
||||
// but before OSR.
|
||||
JSContext *cx = GetJSContextFromJitCode();
|
||||
SPSProfiler *p = &(cx->runtime()->spsProfiler);
|
||||
if (p->enabled()) {
|
||||
p->enter(fp->script(), fp->maybeFun());
|
||||
flags_ |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
|
||||
}
|
||||
|
||||
frameSize_ = BaselineFrame::FramePointerOffset +
|
||||
BaselineFrame::Size() +
|
||||
numStackValues * sizeof(Value);
|
||||
|
@ -195,6 +182,8 @@ BaselineFrame::initForOsr(InterpreterFrame *fp, uint32_t numStackValues)
|
|||
*valueSlot(i) = fp->slots()[i];
|
||||
|
||||
if (fp->isDebuggee()) {
|
||||
JSContext *cx = GetJSContextFromJitCode();
|
||||
|
||||
// For debuggee frames, update any Debugger.Frame objects for the
|
||||
// InterpreterFrame to point to the BaselineFrame.
|
||||
|
||||
|
|
|
@ -56,9 +56,6 @@ class BaselineFrame
|
|||
// Eval frame, see the "eval frames" comment.
|
||||
EVAL = 1 << 7,
|
||||
|
||||
// Frame has profiler entry pushed.
|
||||
HAS_PUSHED_SPS_FRAME = 1 << 8,
|
||||
|
||||
// Frame has over-recursed on an early check.
|
||||
OVER_RECURSED = 1 << 9,
|
||||
|
||||
|
@ -308,18 +305,6 @@ class BaselineFrame
|
|||
return evalScript_;
|
||||
}
|
||||
|
||||
bool hasPushedSPSFrame() const {
|
||||
return flags_ & HAS_PUSHED_SPS_FRAME;
|
||||
}
|
||||
|
||||
void setPushedSPSFrame() {
|
||||
flags_ |= HAS_PUSHED_SPS_FRAME;
|
||||
}
|
||||
|
||||
void unsetPushedSPSFrame() {
|
||||
flags_ &= ~HAS_PUSHED_SPS_FRAME;
|
||||
}
|
||||
|
||||
bool overRecursed() const {
|
||||
return flags_ & OVER_RECURSED;
|
||||
}
|
||||
|
|
|
@ -297,11 +297,6 @@ ICStub::trace(JSTracer *trc)
|
|||
MarkTypeObject(trc, &updateStub->type(), "baseline-update-typeobject");
|
||||
break;
|
||||
}
|
||||
case ICStub::Profiler_PushFunction: {
|
||||
ICProfiler_PushFunction *pushFunStub = toProfiler_PushFunction();
|
||||
MarkScript(trc, &pushFunStub->script(), "baseline-profilerpushfunction-stub-script");
|
||||
break;
|
||||
}
|
||||
case ICStub::GetName_Global: {
|
||||
ICGetName_Global *globalStub = toGetName_Global();
|
||||
MarkShape(trc, &globalStub->shape(), "baseline-global-stub-shape");
|
||||
|
@ -723,66 +718,6 @@ ICStubCompiler::leaveStubFrame(MacroAssembler &masm, bool calledIntoIon)
|
|||
EmitLeaveStubFrame(masm, calledIntoIon);
|
||||
}
|
||||
|
||||
void
|
||||
ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
|
||||
{
|
||||
// This should only be called from the following stubs.
|
||||
MOZ_ASSERT(kind == ICStub::Call_Scripted ||
|
||||
kind == ICStub::Call_AnyScripted ||
|
||||
kind == ICStub::Call_Native ||
|
||||
kind == ICStub::Call_ClassHook ||
|
||||
kind == ICStub::Call_ScriptedApplyArray ||
|
||||
kind == ICStub::Call_ScriptedApplyArguments ||
|
||||
kind == ICStub::Call_ScriptedFunCall ||
|
||||
kind == ICStub::GetProp_CallScripted ||
|
||||
kind == ICStub::GetProp_CallNative ||
|
||||
kind == ICStub::GetProp_CallNativePrototype ||
|
||||
kind == ICStub::GetProp_CallDOMProxyNative ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallNative ||
|
||||
kind == ICStub::GetElem_NativePrototypeCallScripted ||
|
||||
kind == ICStub::GetProp_CallDOMProxyWithGenerationNative ||
|
||||
kind == ICStub::GetProp_DOMProxyShadowed ||
|
||||
kind == ICStub::SetProp_CallScripted ||
|
||||
kind == ICStub::SetProp_CallNative);
|
||||
|
||||
// Guard on bit in frame that indicates if the SPS frame was pushed in the first
|
||||
// place. This code is expected to be called from within a stub that has already
|
||||
// entered a stub frame.
|
||||
MOZ_ASSERT(entersStubFrame_);
|
||||
masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
|
||||
masm.branchTest32(Assembler::Zero,
|
||||
Address(scratch, BaselineFrame::reverseOffsetOfFlags()),
|
||||
Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME),
|
||||
skip);
|
||||
|
||||
// Check if profiling is enabled
|
||||
uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
|
||||
masm.branch32(Assembler::Equal, AbsoluteAddress(enabledAddr), Imm32(0), skip);
|
||||
}
|
||||
|
||||
void
|
||||
ICStubCompiler::emitProfilingUpdate(MacroAssembler &masm, Register pcIdx, Register scratch,
|
||||
uint32_t stubPcOffset)
|
||||
{
|
||||
Label skipProfilerUpdate;
|
||||
|
||||
// Check if profiling is enabled.
|
||||
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
|
||||
|
||||
// Update profiling entry before leaving function.
|
||||
masm.load32(Address(BaselineStubReg, stubPcOffset), pcIdx);
|
||||
masm.spsUpdatePCIdx(&cx->runtime()->spsProfiler, pcIdx, scratch);
|
||||
|
||||
masm.bind(&skipProfilerUpdate);
|
||||
}
|
||||
|
||||
void
|
||||
ICStubCompiler::emitProfilingUpdate(MacroAssembler &masm, GeneralRegisterSet regs,
|
||||
uint32_t stubPcOffset)
|
||||
{
|
||||
emitProfilingUpdate(masm, regs.takeAny(), regs.takeAny(), stubPcOffset);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
|
||||
Register scratch, GeneralRegisterSet saveRegs)
|
||||
|
@ -863,16 +798,9 @@ EnsureCanEnterIon(JSContext *cx, ICWarmUpCounter_Fallback *stub, BaselineFrame *
|
|||
|
||||
if (isLoopEntry) {
|
||||
IonScript *ion = script->ionScript();
|
||||
MOZ_ASSERT(cx->runtime()->spsProfiler.enabled() == ion->hasSPSInstrumentation());
|
||||
MOZ_ASSERT(cx->runtime()->spsProfiler.enabled() == ion->hasProfilingInstrumentation());
|
||||
MOZ_ASSERT(ion->osrPc() == pc);
|
||||
|
||||
// If the baseline frame's SPS handling doesn't match up with the Ion code's SPS
|
||||
// handling, don't OSR.
|
||||
if (frame->hasPushedSPSFrame() != ion->hasSPSInstrumentation()) {
|
||||
JitSpew(JitSpew_BaselineOSR, " OSR crosses SPS handling boundaries, skipping!");
|
||||
return true;
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_BaselineOSR, " OSR possible!");
|
||||
*jitcodePtr = ion->method()->raw() + ion->osrEntryOffset();
|
||||
}
|
||||
|
@ -1104,99 +1032,6 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// ICProfile_Fallback
|
||||
//
|
||||
|
||||
static bool
|
||||
DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stub)
|
||||
{
|
||||
RootedScript script(cx, frame->script());
|
||||
RootedFunction func(cx, frame->maybeFun());
|
||||
mozilla::DebugOnly<ICEntry *> icEntry = stub->icEntry();
|
||||
|
||||
FallbackICSpew(cx, stub, "Profiler");
|
||||
|
||||
SPSProfiler *profiler = &cx->runtime()->spsProfiler;
|
||||
|
||||
// Manually enter SPS this time.
|
||||
MOZ_ASSERT(profiler->enabled());
|
||||
if (!cx->runtime()->spsProfiler.enter(script, func))
|
||||
return false;
|
||||
frame->setPushedSPSFrame();
|
||||
|
||||
// Unlink any existing PushFunction stub (which may hold stale 'const char *' to
|
||||
// the profile string.
|
||||
MOZ_ASSERT_IF(icEntry->firstStub() != stub,
|
||||
icEntry->firstStub()->isProfiler_PushFunction() &&
|
||||
icEntry->firstStub()->next() == stub);
|
||||
stub->unlinkStubsWithKind(cx, ICStub::Profiler_PushFunction);
|
||||
MOZ_ASSERT(icEntry->firstStub() == stub);
|
||||
|
||||
// Generate the string to use to identify this stack frame.
|
||||
const char *string = profiler->profileString(script, func);
|
||||
if (string == nullptr)
|
||||
return false;
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " Generating Profiler_PushFunction stub for %s:%d",
|
||||
script->filename(), script->lineno());
|
||||
|
||||
// Create a new optimized stub.
|
||||
ICProfiler_PushFunction::Compiler compiler(cx, string, script);
|
||||
ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!optStub)
|
||||
return false;
|
||||
stub->addNewStub(optStub);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*DoProfilerFallbackFn)(JSContext *, BaselineFrame *frame, ICProfiler_Fallback *);
|
||||
static const VMFunction DoProfilerFallbackInfo =
|
||||
FunctionInfo<DoProfilerFallbackFn>(DoProfilerFallback, TailCall);
|
||||
|
||||
bool
|
||||
ICProfiler_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
EmitRestoreTailCallReg(masm);
|
||||
|
||||
masm.push(BaselineStubReg); // Push stub.
|
||||
masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); // Push frame.
|
||||
|
||||
return tailCallVM(DoProfilerFallbackInfo, masm);
|
||||
}
|
||||
|
||||
bool
|
||||
ICProfiler_PushFunction::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
|
||||
Register scratch = R0.scratchReg();
|
||||
Register scratch2 = R1.scratchReg();
|
||||
|
||||
// Profiling should be enabled if we ever reach here.
|
||||
#ifdef DEBUG
|
||||
Label spsEnabled;
|
||||
uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
|
||||
masm.branch32(Assembler::NotEqual, AbsoluteAddress(enabledAddr), Imm32(0), &spsEnabled);
|
||||
masm.assumeUnreachable("Profiling should have been enabled.");
|
||||
masm.bind(&spsEnabled);
|
||||
#endif
|
||||
|
||||
// Push SPS entry.
|
||||
masm.spsPushFrame(&cx->runtime()->spsProfiler,
|
||||
Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfStr()),
|
||||
Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfScript()),
|
||||
scratch,
|
||||
scratch2);
|
||||
|
||||
// Mark frame as having profiler entry pushed.
|
||||
Address flagsOffset(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
|
||||
masm.or32(Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), flagsOffset);
|
||||
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// TypeMonitor_Fallback
|
||||
|
@ -4229,9 +4064,6 @@ ICGetElemNativeCompiler::emitCallNative(MacroAssembler &masm, Register objReg)
|
|||
|
||||
regs.add(objReg);
|
||||
|
||||
// Profiler hook.
|
||||
emitProfilingUpdate(masm, regs, ICGetElemNativeGetterStub::offsetOfPCOffset());
|
||||
|
||||
// Call helper.
|
||||
if (!callVM(DoCallNativeGetterInfo, masm))
|
||||
return false;
|
||||
|
@ -4297,16 +4129,6 @@ ICGetElemNativeCompiler::emitCallScripted(MacroAssembler &masm, Register objReg)
|
|||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, callee and scratch can
|
||||
// be clobbered.
|
||||
{
|
||||
GeneralRegisterSet availRegs = availableGeneralRegs(0);
|
||||
availRegs.take(ArgumentsRectifierReg);
|
||||
availRegs.take(code);
|
||||
emitProfilingUpdate(masm, availRegs, ICGetElemNativeGetterStub::offsetOfPCOffset());
|
||||
}
|
||||
|
||||
masm.callJit(code);
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -7463,16 +7285,6 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, callee and scratch can
|
||||
// be clobbered.
|
||||
{
|
||||
GeneralRegisterSet availRegs = availableGeneralRegs(0);
|
||||
availRegs.take(ArgumentsRectifierReg);
|
||||
availRegs.take(code);
|
||||
emitProfilingUpdate(masm, availRegs, ICGetProp_CallScripted::offsetOfPCOffset());
|
||||
}
|
||||
|
||||
masm.callJit(code);
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -7534,9 +7346,6 @@ ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
if (!inputDefinitelyObject_)
|
||||
regs.add(R0);
|
||||
|
||||
// If needed, update SPS Profiler frame entry.
|
||||
emitProfilingUpdate(masm, regs, ICGetProp_CallNative::offsetOfPCOffset());
|
||||
|
||||
if (!callVM(DoCallNativeGetterInfo, masm))
|
||||
return false;
|
||||
leaveStubFrame(masm);
|
||||
|
@ -7606,9 +7415,6 @@ ICGetProp_CallNativePrototype::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
else
|
||||
regs.add(objReg);
|
||||
|
||||
// If needed, update SPS Profiler frame entry.
|
||||
emitProfilingUpdate(masm, regs, ICGetProp_CallNativePrototype::offsetOfPCOffset());
|
||||
|
||||
if (!callVM(DoCallNativeGetterInfo, masm))
|
||||
return false;
|
||||
leaveStubFrame(masm);
|
||||
|
@ -7679,9 +7485,6 @@ ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler &masm,
|
|||
// Don't have to preserve R0 anymore.
|
||||
regs.add(R0);
|
||||
|
||||
// If needed, update SPS Profiler frame entry.
|
||||
emitProfilingUpdate(masm, regs, ICGetProp_CallDOMProxyNative::offsetOfPCOffset());
|
||||
|
||||
if (!callVM(DoCallNativeGetterInfo, masm))
|
||||
return false;
|
||||
leaveStubFrame(masm);
|
||||
|
@ -7814,9 +7617,6 @@ ICGetProp_DOMProxyShadowed::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
// Don't have to preserve R0 anymore.
|
||||
regs.add(R0);
|
||||
|
||||
// If needed, update SPS Profiler frame entry.
|
||||
emitProfilingUpdate(masm, regs, ICGetProp_DOMProxyShadowed::offsetOfPCOffset());
|
||||
|
||||
if (!callVM(ProxyGetInfo, masm))
|
||||
return false;
|
||||
leaveStubFrame(masm);
|
||||
|
@ -8840,16 +8640,6 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, callee and scratch can
|
||||
// be clobbered.
|
||||
{
|
||||
GeneralRegisterSet availRegs = availableGeneralRegs(0);
|
||||
availRegs.take(ArgumentsRectifierReg);
|
||||
availRegs.take(code);
|
||||
emitProfilingUpdate(masm, availRegs, ICSetProp_CallScripted::offsetOfPCOffset());
|
||||
}
|
||||
|
||||
masm.callJit(code);
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -8935,9 +8725,6 @@ ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
// Don't need to preserve R0 anymore.
|
||||
regs.add(R0);
|
||||
|
||||
// If needed, update SPS Profiler frame entry.
|
||||
emitProfilingUpdate(masm, regs, ICSetProp_CallNative::offsetOfPCOffset());
|
||||
|
||||
if (!callVM(DoCallNativeSetterInfo, masm))
|
||||
return false;
|
||||
leaveStubFrame(masm);
|
||||
|
@ -9486,10 +9273,6 @@ DoCallFallback(JSContext *cx, BaselineFrame *frame, ICCall_Fallback *stub_, uint
|
|||
if (!TryAttachCallStub(cx, stub, script, pc, op, argc, vp, constructing, false, newType))
|
||||
return false;
|
||||
|
||||
// Maybe update PC in profiler entry before leaving this script by call.
|
||||
if (cx->runtime()->spsProfiler.enabled() && frame->hasPushedSPSFrame())
|
||||
cx->runtime()->spsProfiler.updatePC(script, pc);
|
||||
|
||||
if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
|
||||
return false;
|
||||
|
||||
|
@ -9562,10 +9345,6 @@ DoSpreadCallFallback(JSContext *cx, BaselineFrame *frame, ICCall_Fallback *stub_
|
|||
return false;
|
||||
}
|
||||
|
||||
// Maybe update PC in profiler entry before leaving this script by call.
|
||||
if (cx->runtime()->spsProfiler.enabled() && frame->hasPushedSPSFrame())
|
||||
cx->runtime()->spsProfiler.updatePC(script, pc);
|
||||
|
||||
if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
|
||||
return false;
|
||||
|
||||
|
@ -10145,18 +9924,6 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler &masm)
|
|||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
||||
// If needed, update SPS Profiler frame entry before and after call.
|
||||
{
|
||||
MOZ_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted);
|
||||
GeneralRegisterSet availRegs = availableGeneralRegs(0);
|
||||
availRegs.take(ArgumentsRectifierReg);
|
||||
availRegs.take(code);
|
||||
emitProfilingUpdate(masm, availRegs, kind == ICStub::Call_Scripted ?
|
||||
ICCall_Scripted::offsetOfPCOffset()
|
||||
: ICCall_AnyScripted::offsetOfPCOffset());
|
||||
}
|
||||
|
||||
masm.callJit(code);
|
||||
|
||||
// If this is a constructing call, and the callee returns a non-object, replace it with
|
||||
|
@ -10417,10 +10184,6 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
masm.push(BaselineTailCallReg);
|
||||
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, BaselineTailCallReg
|
||||
// and scratch can be clobbered.
|
||||
emitProfilingUpdate(masm, BaselineTailCallReg, scratch, ICCall_Native::offsetOfPCOffset());
|
||||
|
||||
// Execute call.
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
|
@ -10516,10 +10279,6 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
masm.push(BaselineTailCallReg);
|
||||
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, BaselineTailCallReg
|
||||
// and scratch can be clobbered.
|
||||
emitProfilingUpdate(masm, BaselineTailCallReg, scratch, ICCall_ClassHook::offsetOfPCOffset());
|
||||
|
||||
// Execute call.
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
|
@ -10634,11 +10393,6 @@ ICCall_ScriptedApplyArray::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
masm.bind(&noUnderflow);
|
||||
regs.add(argcReg);
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, BaselineTailCallReg
|
||||
// and scratch can be clobbered.
|
||||
emitProfilingUpdate(masm, regs.getAny(), scratch,
|
||||
ICCall_ScriptedApplyArguments::offsetOfPCOffset());
|
||||
|
||||
// Do call
|
||||
masm.callJit(target);
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -10735,11 +10489,6 @@ ICCall_ScriptedApplyArguments::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
masm.bind(&noUnderflow);
|
||||
regs.add(argcReg);
|
||||
|
||||
// If needed, update SPS Profiler frame entry. At this point, BaselineTailCallReg
|
||||
// and scratch can be clobbered.
|
||||
emitProfilingUpdate(masm, regs.getAny(), scratch,
|
||||
ICCall_ScriptedApplyArguments::offsetOfPCOffset());
|
||||
|
||||
// Do call
|
||||
masm.callJit(target);
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -10856,16 +10605,6 @@ ICCall_ScriptedFunCall::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
}
|
||||
|
||||
masm.bind(&noUnderflow);
|
||||
|
||||
// If needed, update SPS Profiler frame entry.
|
||||
{
|
||||
// Need to avoid using ArgumentsRectifierReg and code register.
|
||||
GeneralRegisterSet availRegs = availableGeneralRegs(0);
|
||||
availRegs.take(ArgumentsRectifierReg);
|
||||
availRegs.take(code);
|
||||
emitProfilingUpdate(masm, availRegs, ICCall_ScriptedFunCall::offsetOfPCOffset());
|
||||
}
|
||||
|
||||
masm.callJit(code);
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
@ -11518,13 +11257,6 @@ ICRetSub_Resume::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
return true;
|
||||
}
|
||||
|
||||
ICProfiler_PushFunction::ICProfiler_PushFunction(JitCode *stubCode, const char *str,
|
||||
HandleScript script)
|
||||
: ICStub(ICStub::Profiler_PushFunction, stubCode),
|
||||
str_(str),
|
||||
script_(script)
|
||||
{ }
|
||||
|
||||
ICTypeMonitor_SingleObject::ICTypeMonitor_SingleObject(JitCode *stubCode, HandleObject obj)
|
||||
: ICStub(TypeMonitor_SingleObject, stubCode),
|
||||
obj_(obj)
|
||||
|
|
|
@ -335,9 +335,6 @@ class ICEntry
|
|||
#define IC_STUB_KIND_LIST(_) \
|
||||
_(WarmUpCounter_Fallback) \
|
||||
\
|
||||
_(Profiler_Fallback) \
|
||||
_(Profiler_PushFunction) \
|
||||
\
|
||||
_(TypeMonitor_Fallback) \
|
||||
_(TypeMonitor_SingleObject) \
|
||||
_(TypeMonitor_TypeObject) \
|
||||
|
@ -1122,11 +1119,6 @@ class ICStubCompiler
|
|||
// given label.
|
||||
void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip);
|
||||
|
||||
// Higher-level helper to emit an update to the profiler pseudo-stack.
|
||||
void emitProfilingUpdate(MacroAssembler &masm, Register pcIdx, Register scratch,
|
||||
uint32_t stubPcOffset);
|
||||
void emitProfilingUpdate(MacroAssembler &masm, GeneralRegisterSet regs, uint32_t stubPcOffset);
|
||||
|
||||
inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const {
|
||||
GeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
MOZ_ASSERT(!regs.has(BaselineStackReg));
|
||||
|
@ -1229,91 +1221,6 @@ class ICWarmUpCounter_Fallback : public ICFallbackStub
|
|||
};
|
||||
};
|
||||
|
||||
// Profiler_Fallback
|
||||
|
||||
class ICProfiler_Fallback : public ICFallbackStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
explicit ICProfiler_Fallback(JitCode *stubCode)
|
||||
: ICFallbackStub(ICStub::Profiler_Fallback, stubCode)
|
||||
{ }
|
||||
|
||||
public:
|
||||
static inline ICProfiler_Fallback *New(ICStubSpace *space, JitCode *code) {
|
||||
if (!code)
|
||||
return nullptr;
|
||||
return space->allocate<ICProfiler_Fallback>(code);
|
||||
}
|
||||
|
||||
// Compiler for this stub kind.
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
public:
|
||||
explicit Compiler(JSContext *cx)
|
||||
: ICStubCompiler(cx, ICStub::Profiler_Fallback)
|
||||
{ }
|
||||
|
||||
ICProfiler_Fallback *getStub(ICStubSpace *space) {
|
||||
return ICProfiler_Fallback::New(space, getStubCode());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Profiler_PushFunction
|
||||
|
||||
class ICProfiler_PushFunction : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
const char *str_;
|
||||
HeapPtrScript script_;
|
||||
|
||||
ICProfiler_PushFunction(JitCode *stubCode, const char *str, HandleScript script);
|
||||
|
||||
public:
|
||||
static inline ICProfiler_PushFunction *New(ICStubSpace *space, JitCode *code,
|
||||
const char *str, HandleScript script)
|
||||
{
|
||||
if (!code)
|
||||
return nullptr;
|
||||
return space->allocate<ICProfiler_PushFunction>(code, str, script);
|
||||
}
|
||||
|
||||
HeapPtrScript &script() {
|
||||
return script_;
|
||||
}
|
||||
|
||||
static size_t offsetOfStr() {
|
||||
return offsetof(ICProfiler_PushFunction, str_);
|
||||
}
|
||||
static size_t offsetOfScript() {
|
||||
return offsetof(ICProfiler_PushFunction, script_);
|
||||
}
|
||||
|
||||
// Compiler for this stub kind.
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
const char *str_;
|
||||
RootedScript script_;
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
public:
|
||||
Compiler(JSContext *cx, const char *str, HandleScript script)
|
||||
: ICStubCompiler(cx, ICStub::Profiler_PushFunction),
|
||||
str_(str),
|
||||
script_(cx, script)
|
||||
{ }
|
||||
|
||||
ICProfiler_PushFunction *getStub(ICStubSpace *space) {
|
||||
return ICProfiler_PushFunction::New(space, getStubCode(), str_, script_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// TypeCheckPrimitiveSetStub
|
||||
// Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given
|
||||
|
|
|
@ -42,7 +42,6 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue *stackVal)
|
|||
}
|
||||
|
||||
BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset,
|
||||
|
@ -54,10 +53,6 @@ BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
|||
dependentAsmJSModules_(nullptr),
|
||||
prologueOffset_(prologueOffset),
|
||||
epilogueOffset_(epilogueOffset),
|
||||
#ifdef DEBUG
|
||||
spsOn_(false),
|
||||
#endif
|
||||
spsPushToggleOffset_(spsPushToggleOffset),
|
||||
profilerEnterToggleOffset_(profilerEnterToggleOffset),
|
||||
profilerExitToggleOffset_(profilerExitToggleOffset),
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
|
@ -347,7 +342,6 @@ jit::CanEnterBaselineMethod(JSContext *cx, RunState &state)
|
|||
|
||||
BaselineScript *
|
||||
BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset, uint32_t traceLoggerExitToggleOffset,
|
||||
uint32_t postDebugPrologueOffset,
|
||||
|
@ -377,7 +371,6 @@ BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilog
|
|||
if (!script)
|
||||
return nullptr;
|
||||
new (script) BaselineScript(prologueOffset, epilogueOffset,
|
||||
spsPushToggleOffset,
|
||||
profilerEnterToggleOffset, profilerExitToggleOffset,
|
||||
traceLoggerEnterToggleOffset, traceLoggerExitToggleOffset,
|
||||
postDebugPrologueOffset);
|
||||
|
@ -856,25 +849,6 @@ BaselineScript::toggleDebugTraps(JSScript *script, jsbytecode *pc)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::toggleSPS(bool enable)
|
||||
{
|
||||
MOZ_ASSERT(enable == !(bool)spsOn_);
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " toggling SPS %s for BaselineScript %p",
|
||||
enable ? "on" : "off", this);
|
||||
|
||||
// Toggle the jump
|
||||
CodeLocationLabel pushToggleLocation(method_, CodeOffsetLabel(spsPushToggleOffset_));
|
||||
if (enable)
|
||||
Assembler::ToggleToCmp(pushToggleLocation);
|
||||
else
|
||||
Assembler::ToggleToJmp(pushToggleLocation);
|
||||
#ifdef DEBUG
|
||||
spsOn_ = enable;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void
|
||||
BaselineScript::initTraceLogger(JSRuntime *runtime, JSScript *script)
|
||||
|
@ -965,7 +939,7 @@ BaselineScript::toggleProfilerInstrumentation(bool enable)
|
|||
if (enable == isProfilerInstrumentationOn())
|
||||
return;
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " toggling SPS %s for BaselineScript %p",
|
||||
JitSpew(JitSpew_BaselineIC, " toggling profiling %s for BaselineScript %p",
|
||||
enable ? "on" : "off", this);
|
||||
|
||||
// Toggle the jump
|
||||
|
@ -1077,14 +1051,13 @@ jit::AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf,
|
|||
}
|
||||
|
||||
void
|
||||
jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable)
|
||||
jit::ToggleBaselineProfiling(JSRuntime *runtime, bool enable)
|
||||
{
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleSPS(enable);
|
||||
script->baselineScript()->toggleProfilerInstrumentation(enable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,11 +139,7 @@ struct BaselineScript
|
|||
// returned from.
|
||||
uint32_t epilogueOffset_;
|
||||
|
||||
// The offsets for the toggledJump instructions for SPS update ICs.
|
||||
#ifdef DEBUG
|
||||
mozilla::DebugOnly<bool> spsOn_;
|
||||
#endif
|
||||
uint32_t spsPushToggleOffset_;
|
||||
// The offsets for the toggledJump instructions for profiler instrumentation.
|
||||
uint32_t profilerEnterToggleOffset_;
|
||||
uint32_t profilerExitToggleOffset_;
|
||||
|
||||
|
@ -219,7 +215,6 @@ struct BaselineScript
|
|||
public:
|
||||
// Do not call directly, use BaselineScript::New. This is public for cx->new_.
|
||||
BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset,
|
||||
|
@ -228,7 +223,6 @@ struct BaselineScript
|
|||
|
||||
static BaselineScript *New(JSScript *jsscript, uint32_t prologueOffset,
|
||||
uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset,
|
||||
|
@ -398,7 +392,6 @@ struct BaselineScript
|
|||
// toggle traps at |pc|.
|
||||
void toggleDebugTraps(JSScript *script, jsbytecode *pc);
|
||||
|
||||
void toggleSPS(bool enable);
|
||||
void toggleProfilerInstrumentation(bool enable);
|
||||
bool isProfilerInstrumentationOn() const {
|
||||
return flags_ & PROFILER_INSTRUMENTATION_ON;
|
||||
|
@ -464,7 +457,7 @@ AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size
|
|||
size_t *fallbackStubs);
|
||||
|
||||
void
|
||||
ToggleBaselineSPS(JSRuntime *runtime, bool enable);
|
||||
ToggleBaselineProfiling(JSRuntime *runtime, bool enable);
|
||||
|
||||
void
|
||||
ToggleBaselineTraceLoggerScripts(JSRuntime *runtime, bool enable);
|
||||
|
@ -516,8 +509,7 @@ struct BaselineBailoutInfo
|
|||
uint32_t
|
||||
BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
|
||||
bool invalidate, BaselineBailoutInfo **bailoutInfo,
|
||||
const ExceptionBailoutInfo *exceptionInfo,
|
||||
bool *poppedLastSPSFrame);
|
||||
const ExceptionBailoutInfo *exceptionInfo);
|
||||
|
||||
// Mark baseline scripts on the stack as active, so that they are not discarded
|
||||
// during GC.
|
||||
|
|
|
@ -3654,7 +3654,7 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
masm.callWithABINoProfiling(callee);
|
||||
masm.callWithABI(callee);
|
||||
restoreVolatile();
|
||||
|
||||
masm.bind(&done);
|
||||
|
@ -3720,7 +3720,7 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
|
|||
masm.loadJSContext(temp2);
|
||||
masm.passABIArg(temp2);
|
||||
masm.passABIArg(temp1);
|
||||
masm.callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, AssertValidValue));
|
||||
masm.popValue(output);
|
||||
restoreVolatile();
|
||||
|
||||
|
@ -6933,9 +6933,6 @@ CodeGenerator::generateAsmJS(AsmJSFunctionLabels *labels)
|
|||
{
|
||||
JitSpew(JitSpew_Codegen, "# Emitting asm.js code");
|
||||
|
||||
// AsmJS doesn't do SPS instrumentation.
|
||||
sps_.disable();
|
||||
|
||||
if (!omitOverRecursedCheck())
|
||||
labels->overflowThunk.emplace();
|
||||
|
||||
|
@ -7212,8 +7209,8 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
ionScript->setSkipArgCheckEntryOffset(getSkipArgCheckEntryOffset());
|
||||
|
||||
// If SPS is enabled, mark IonScript as having been instrumented with SPS
|
||||
if (sps_.enabled())
|
||||
ionScript->setHasSPSInstrumentation();
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
ionScript->setHasProfilingInstrumentation();
|
||||
|
||||
SetIonScript(cx, script, executionMode, ionScript);
|
||||
|
||||
|
@ -8899,49 +8896,6 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty *ins)
|
|||
MOZ_ASSERT(masm.framePushed() == initialStack);
|
||||
}
|
||||
|
||||
typedef bool(*SPSFn)(JSContext *, HandleScript);
|
||||
static const VMFunction SPSEnterInfo = FunctionInfo<SPSFn>(SPSEnter);
|
||||
static const VMFunction SPSExitInfo = FunctionInfo<SPSFn>(SPSExit);
|
||||
|
||||
void
|
||||
CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
|
||||
{
|
||||
Register temp = ToRegister(lir->temp()->output());
|
||||
|
||||
switch (lir->type()) {
|
||||
case MProfilerStackOp::Enter:
|
||||
if (gen->options.spsSlowAssertionsEnabled()) {
|
||||
saveLive(lir);
|
||||
pushArg(ImmGCPtr(lir->script()));
|
||||
callVM(SPSEnterInfo, lir);
|
||||
restoreLive(lir);
|
||||
sps_.pushManual(lir->script(), masm, temp, /* inlinedFunction = */ false);
|
||||
} else {
|
||||
masm.propagateOOM(sps_.push(lir->script(), masm, temp,
|
||||
/* inlinedFunction = */ false));
|
||||
}
|
||||
return;
|
||||
|
||||
case MProfilerStackOp::Exit:
|
||||
if (gen->options.spsSlowAssertionsEnabled()) {
|
||||
saveLive(lir);
|
||||
pushArg(ImmGCPtr(lir->script()));
|
||||
// Once we've exited, then we shouldn't emit instrumentation for
|
||||
// the corresponding reenter() because we no longer have a
|
||||
// frame.
|
||||
sps_.skipNextReenter();
|
||||
callVM(SPSExitInfo, lir);
|
||||
restoreLive(lir);
|
||||
} else {
|
||||
sps_.pop(masm, temp, /* inlinedFunction = */ false);
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("invalid LProfilerStackOp type");
|
||||
}
|
||||
}
|
||||
|
||||
class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LIsCallable *ins_;
|
||||
|
|
|
@ -293,7 +293,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
void visitInstanceOfO(LInstanceOfO *ins);
|
||||
void visitInstanceOfV(LInstanceOfV *ins);
|
||||
void visitCallInstanceOf(LCallInstanceOf *ins);
|
||||
void visitProfilerStackOp(LProfilerStackOp *lir);
|
||||
void visitGetDOMProperty(LGetDOMProperty *lir);
|
||||
void visitGetDOMMemberV(LGetDOMMemberV *lir);
|
||||
void visitGetDOMMemberT(LGetDOMMemberT *lir);
|
||||
|
|
|
@ -710,7 +710,7 @@ IonScript::IonScript()
|
|||
invalidateEpilogueOffset_(0),
|
||||
invalidateEpilogueDataOffset_(0),
|
||||
numBailouts_(0),
|
||||
hasSPSInstrumentation_(false),
|
||||
hasProfilingInstrumentation_(false),
|
||||
recompiling_(false),
|
||||
runtimeData_(0),
|
||||
runtimeSize_(0),
|
||||
|
|
|
@ -708,8 +708,6 @@ IonBuilder::build()
|
|||
|
||||
// Emit the start instruction, so we can begin real instructions.
|
||||
current->add(MStart::New(alloc(), MStart::StartType_Default));
|
||||
if (instrumentedProfiling())
|
||||
current->add(MProfilerStackOp::New(alloc(), script(), MProfilerStackOp::Enter));
|
||||
|
||||
// Guard against over-recursion. Do this before we start unboxing, since
|
||||
// this will create an OSI point that will read the incoming argument
|
||||
|
@ -4075,9 +4073,6 @@ IonBuilder::processReturn(JSOp op)
|
|||
MOZ_CRASH("unknown return op");
|
||||
}
|
||||
|
||||
if (instrumentedProfiling() && inliningDepth_ == 0) {
|
||||
current->add(MProfilerStackOp::New(alloc(), script(), MProfilerStackOp::Exit));
|
||||
}
|
||||
MReturn *ret = MReturn::New(alloc(), def);
|
||||
current->end(ret);
|
||||
|
||||
|
|
|
@ -193,8 +193,8 @@ struct IonScript
|
|||
// Number of times this script bailed out without invalidation.
|
||||
uint32_t numBailouts_;
|
||||
|
||||
// Flag set if IonScript was compiled with SPS profiling enabled.
|
||||
bool hasSPSInstrumentation_;
|
||||
// Flag set if IonScript was compiled with profiling enabled.
|
||||
bool hasProfilingInstrumentation_;
|
||||
|
||||
// Flag for if this script is getting recompiled.
|
||||
uint32_t recompiling_;
|
||||
|
@ -412,14 +412,14 @@ struct IonScript
|
|||
bool bailoutExpected() const {
|
||||
return numBailouts_ > 0;
|
||||
}
|
||||
void setHasSPSInstrumentation() {
|
||||
hasSPSInstrumentation_ = true;
|
||||
void setHasProfilingInstrumentation() {
|
||||
hasProfilingInstrumentation_ = true;
|
||||
}
|
||||
void clearHasSPSInstrumentation() {
|
||||
hasSPSInstrumentation_ = false;
|
||||
void clearHasProfilingInstrumentation() {
|
||||
hasProfilingInstrumentation_ = false;
|
||||
}
|
||||
bool hasSPSInstrumentation() const {
|
||||
return hasSPSInstrumentation_;
|
||||
bool hasProfilingInstrumentation() const {
|
||||
return hasProfilingInstrumentation_;
|
||||
}
|
||||
void setTraceLoggerEvent(TraceLoggerEvent &event) {
|
||||
traceLoggerScriptEvent_ = event;
|
||||
|
|
|
@ -19,23 +19,12 @@ typedef SPSInstrumentation<MacroAssembler, Register> BaseInstrumentation;
|
|||
|
||||
class IonInstrumentation : public BaseInstrumentation
|
||||
{
|
||||
jsbytecode **trackedPc_;
|
||||
|
||||
public:
|
||||
IonInstrumentation(SPSProfiler *profiler, jsbytecode **pc)
|
||||
: BaseInstrumentation(profiler),
|
||||
trackedPc_(pc)
|
||||
: BaseInstrumentation(profiler)
|
||||
{
|
||||
MOZ_ASSERT(pc != nullptr);
|
||||
}
|
||||
|
||||
void leave(MacroAssembler &masm, Register reg, bool inlinedFunction = false) {
|
||||
BaseInstrumentation::leave(*trackedPc_, masm, reg, inlinedFunction);
|
||||
}
|
||||
|
||||
bool enterInlineFrame() {
|
||||
return BaseInstrumentation::enterInlineFrame(*trackedPc_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -379,7 +379,7 @@ CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32_t loca
|
|||
|
||||
static void
|
||||
HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromException *rfe,
|
||||
bool *overrecursed, bool *poppedLastSPSFrameOut)
|
||||
bool *overrecursed)
|
||||
{
|
||||
RootedScript script(cx, frame.script());
|
||||
jsbytecode *pc = frame.pc();
|
||||
|
@ -411,8 +411,7 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
|
|||
// to the stack depth at the snapshot, as we could've thrown in the
|
||||
// middle of a call.
|
||||
ExceptionBailoutInfo propagateInfo;
|
||||
uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed,
|
||||
poppedLastSPSFrameOut);
|
||||
uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, propagateInfo, overrecursed);
|
||||
if (retval == BAILOUT_RETURN_OK)
|
||||
return;
|
||||
}
|
||||
|
@ -454,8 +453,7 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
|
|||
// Bailout at the start of the catch block.
|
||||
jsbytecode *catchPC = script->main() + tn->start + tn->length;
|
||||
ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC, tn->stackDepth);
|
||||
uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed,
|
||||
poppedLastSPSFrameOut);
|
||||
uint32_t retval = ExceptionHandlerBailout(cx, frame, rfe, excInfo, overrecursed);
|
||||
if (retval == BAILOUT_RETURN_OK)
|
||||
return;
|
||||
|
||||
|
@ -763,8 +761,7 @@ HandleException(ResumeFromException *rfe)
|
|||
bool invalidated = iter.checkInvalidation(&ionScript);
|
||||
|
||||
for (;;) {
|
||||
bool poppedLastSPSFrame = false;
|
||||
HandleExceptionIon(cx, frames, rfe, &overrecursed, &poppedLastSPSFrame);
|
||||
HandleExceptionIon(cx, frames, rfe, &overrecursed);
|
||||
|
||||
if (rfe->kind == ResumeFromException::RESUME_BAILOUT) {
|
||||
if (invalidated)
|
||||
|
@ -774,29 +771,13 @@ HandleException(ResumeFromException *rfe)
|
|||
|
||||
MOZ_ASSERT(rfe->kind == ResumeFromException::RESUME_ENTRY_FRAME);
|
||||
|
||||
// Figure out whether SPS frame was pushed for this frame or not.
|
||||
// Even if profiler is enabled, the frame being popped might have
|
||||
// been entered prior to SPS being enabled, and thus not have
|
||||
// a pushed SPS frame.
|
||||
bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
|
||||
if (invalidated)
|
||||
popSPSFrame = ionScript->hasSPSInstrumentation();
|
||||
|
||||
// Don't pop an SPS frame for inlined frames, since they are not instrumented.
|
||||
if (frames.more())
|
||||
popSPSFrame = false;
|
||||
|
||||
// Don't pop the last SPS frame if it's already been popped by
|
||||
// bailing out.
|
||||
if (poppedLastSPSFrame)
|
||||
popSPSFrame = false;
|
||||
|
||||
// When profiling, each frame popped needs a notification that
|
||||
// the function has exited, so invoke the probe that a function
|
||||
// is exiting.
|
||||
|
||||
JSScript *script = frames.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
/* popSPSFrame = */ false);
|
||||
if (!frames.more()) {
|
||||
TraceLogStopEvent(logger, TraceLogger_IonMonkey);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
|
@ -847,11 +828,7 @@ HandleException(ResumeFromException *rfe)
|
|||
// Unwind profiler pseudo-stack
|
||||
JSScript *script = iter.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
iter.baselineFrame()->hasPushedSPSFrame());
|
||||
// After this point, any pushed SPS frame would have been popped if it needed
|
||||
// to be. Unset the flag here so that if we call DebugEpilogue below,
|
||||
// it doesn't try to pop the SPS frame again.
|
||||
iter.baselineFrame()->unsetPushedSPSFrame();
|
||||
/* popSPSFrame = */ false);
|
||||
|
||||
if (iter.baselineFrame()->isDebuggee() && !calledDebugEpilogue) {
|
||||
// If we still need to call the DebugEpilogue, we must
|
||||
|
|
|
@ -6165,28 +6165,6 @@ class LCallInstanceOf : public LCallInstructionHelper<1, BOX_PIECES+1, 0>
|
|||
static const size_t RHS = BOX_PIECES;
|
||||
};
|
||||
|
||||
class LProfilerStackOp : public LInstructionHelper<0, 0, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ProfilerStackOp)
|
||||
|
||||
explicit LProfilerStackOp(const LDefinition &temp) {
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
|
||||
JSScript *script() {
|
||||
return mir_->toProfilerStackOp()->script();
|
||||
}
|
||||
|
||||
MProfilerStackOp::Type type() {
|
||||
return mir_->toProfilerStackOp()->type();
|
||||
}
|
||||
};
|
||||
|
||||
class LIsCallable : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -305,7 +305,6 @@
|
|||
_(InterruptCheck) \
|
||||
_(AsmJSInterruptCheck) \
|
||||
_(InterruptCheckImplicit) \
|
||||
_(ProfilerStackOp) \
|
||||
_(GetDOMProperty) \
|
||||
_(GetDOMMemberV) \
|
||||
_(GetDOMMemberT) \
|
||||
|
|
|
@ -3492,18 +3492,6 @@ LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitProfilerStackOp(MProfilerStackOp *ins)
|
||||
{
|
||||
LProfilerStackOp *lir = new(alloc()) LProfilerStackOp(temp());
|
||||
add(lir, ins);
|
||||
|
||||
// If slow assertions are enabled, then this node will result in a callVM
|
||||
// out to a C++ function for the assertions, so we will need a safepoint.
|
||||
if (gen->options.spsSlowAssertionsEnabled())
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitIsCallable(MIsCallable *ins)
|
||||
{
|
||||
|
|
|
@ -248,7 +248,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitInArray(MInArray *ins);
|
||||
void visitInstanceOf(MInstanceOf *ins);
|
||||
void visitCallInstanceOf(MCallInstanceOf *ins);
|
||||
void visitProfilerStackOp(MProfilerStackOp *ins);
|
||||
void visitIsCallable(MIsCallable *ins);
|
||||
void visitIsObject(MIsObject *ins);
|
||||
void visitHasClass(MHasClass *ins);
|
||||
|
|
|
@ -11438,48 +11438,6 @@ class MNewStringObject :
|
|||
StringObject *templateObj() const;
|
||||
};
|
||||
|
||||
// Node that represents that a script has begun executing. This comes at the
|
||||
// start of the function and is called once per function (including inline
|
||||
// ones)
|
||||
class MProfilerStackOp : public MNullaryInstruction
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
Enter, // a function has begun executing and it is not inline
|
||||
Exit // any function has exited and is not inline
|
||||
};
|
||||
|
||||
private:
|
||||
JSScript *script_;
|
||||
Type type_;
|
||||
|
||||
MProfilerStackOp(JSScript *script, Type type)
|
||||
: script_(script), type_(type)
|
||||
{
|
||||
MOZ_ASSERT(script);
|
||||
setGuard();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ProfilerStackOp)
|
||||
|
||||
static MProfilerStackOp *New(TempAllocator &alloc, JSScript *script, Type type) {
|
||||
return new(alloc) MProfilerStackOp(script, type);
|
||||
}
|
||||
|
||||
JSScript *script() {
|
||||
return script_;
|
||||
}
|
||||
|
||||
Type type() {
|
||||
return type_;
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const MOZ_OVERRIDE {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
// This is an alias for MLoadFixedSlot.
|
||||
class MEnclosingScope : public MLoadFixedSlot
|
||||
{
|
||||
|
|
|
@ -226,7 +226,6 @@ namespace jit {
|
|||
_(CallInstanceOf) \
|
||||
_(InterruptCheck) \
|
||||
_(AsmJSInterruptCheck) \
|
||||
_(ProfilerStackOp) \
|
||||
_(GetDOMProperty) \
|
||||
_(GetDOMMember) \
|
||||
_(SetDOMProperty) \
|
||||
|
|
|
@ -1314,16 +1314,8 @@ MacroAssembler::handleFailure()
|
|||
{
|
||||
// Re-entry code is irrelevant because the exception will leave the
|
||||
// running function and never come back
|
||||
if (sps_)
|
||||
sps_->skipNextReenter();
|
||||
leaveSPSFrame();
|
||||
|
||||
JitCode *excTail = GetJitContext()->runtime->jitRuntime()->getExceptionTail();
|
||||
jump(excTail);
|
||||
|
||||
// Doesn't actually emit code, but balances the leave()
|
||||
if (sps_)
|
||||
sps_->reenter(*this, InvalidReg);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -1345,7 +1337,7 @@ MacroAssembler::assumeUnreachable(const char *output)
|
|||
setupUnalignedABICall(1, temp);
|
||||
movePtr(ImmPtr(output), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, AssumeUnreachable_));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, AssumeUnreachable_));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1373,7 +1365,7 @@ MacroAssembler::printf(const char *output)
|
|||
setupUnalignedABICall(1, temp);
|
||||
movePtr(ImmPtr(output), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, Printf0_));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, Printf0_));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1399,7 +1391,7 @@ MacroAssembler::printf(const char *output, Register value)
|
|||
movePtr(ImmPtr(output), temp);
|
||||
passABIArg(temp);
|
||||
passABIArg(value);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, Printf1_));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, Printf1_));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1422,7 +1414,7 @@ MacroAssembler::tracelogStartId(Register logger, uint32_t textId, bool force)
|
|||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1441,7 +1433,7 @@ MacroAssembler::tracelogStartId(Register logger, Register textId)
|
|||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStartEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1462,7 +1454,7 @@ MacroAssembler::tracelogStartEvent(Register logger, Register event)
|
|||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(event);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogFunc));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1485,7 +1477,7 @@ MacroAssembler::tracelogStopId(Register logger, uint32_t textId, bool force)
|
|||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -1504,7 +1496,7 @@ MacroAssembler::tracelogStopId(Register logger, Register textId)
|
|||
setupUnalignedABICall(2, temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABINoProfiling(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void *, TraceLogStopEventPrivate));
|
||||
|
||||
PopRegsInMask(RegisterSet::Volatile());
|
||||
}
|
||||
|
@ -2023,58 +2015,6 @@ MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Reg
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// If a pseudostack frame has this as its label, its stack pointer
|
||||
// field points to the registers saved on entry to JIT code. A native
|
||||
// stack unwinder could use that information to continue unwinding
|
||||
// past that point.
|
||||
const char MacroAssembler::enterJitLabel[] = "EnterJIT";
|
||||
|
||||
// Creates an enterJIT pseudostack frame, as described above. Pushes
|
||||
// a word to the stack to indicate whether this was done. |framePtr| is
|
||||
// the pointer to the machine-dependent saved state.
|
||||
void
|
||||
MacroAssembler::spsMarkJit(SPSProfiler *p, Register framePtr, Register temp)
|
||||
{
|
||||
Label spsNotEnabled;
|
||||
uint32_t *enabledAddr = p->addressOfEnabled();
|
||||
load32(AbsoluteAddress(enabledAddr), temp);
|
||||
push(temp); // +4: Did we push an sps frame.
|
||||
branchTest32(Assembler::Equal, temp, temp, &spsNotEnabled);
|
||||
|
||||
Label stackFull;
|
||||
// We always need the "safe" versions, because these are used in trampolines
|
||||
// and won't be regenerated when SPS state changes.
|
||||
spsProfileEntryAddressSafe(p, 0, temp, &stackFull);
|
||||
|
||||
// Push a C++ frame with non-copy label
|
||||
storePtr(ImmPtr(enterJitLabel), Address(temp, ProfileEntry::offsetOfLabel()));
|
||||
storePtr(framePtr, Address(temp, ProfileEntry::offsetOfSpOrScript()));
|
||||
store32(Imm32(0), Address(temp, ProfileEntry::offsetOfLineOrPc()));
|
||||
store32(Imm32(ProfileEntry::IS_CPP_ENTRY), Address(temp, ProfileEntry::offsetOfFlags()));
|
||||
|
||||
/* Always increment the stack size, whether or not we actually pushed. */
|
||||
bind(&stackFull);
|
||||
loadPtr(AbsoluteAddress(p->addressOfSizePointer()), temp);
|
||||
add32(Imm32(1), Address(temp, 0));
|
||||
|
||||
bind(&spsNotEnabled);
|
||||
}
|
||||
|
||||
// Pops the word pushed by spsMarkJit and, if spsMarkJit pushed an SPS
|
||||
// frame, pops it.
|
||||
void
|
||||
MacroAssembler::spsUnmarkJit(SPSProfiler *p, Register temp)
|
||||
{
|
||||
Label spsNotEnabled;
|
||||
pop(temp); // -4: Was the profiler enabled.
|
||||
branchTest32(Assembler::Equal, temp, temp, &spsNotEnabled);
|
||||
|
||||
spsPopFrameSafe(p, temp);
|
||||
|
||||
bind(&spsNotEnabled);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::profilerPreCallImpl()
|
||||
{
|
||||
|
|
|
@ -185,27 +185,18 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
mozilla::Maybe<JitContext> jitContext_;
|
||||
mozilla::Maybe<AutoJitContextAlloc> alloc_;
|
||||
|
||||
// SPS instrumentation, only used for Ion caches.
|
||||
mozilla::Maybe<IonInstrumentation> spsInstrumentation_;
|
||||
jsbytecode *spsPc_;
|
||||
|
||||
private:
|
||||
// This field is used to manage profiling instrumentation output. If
|
||||
// provided and enabled, then instrumentation will be emitted around call
|
||||
// sites. The IonInstrumentation instance is hosted inside of
|
||||
// CodeGeneratorShared and is the manager of when instrumentation is
|
||||
// actually emitted or not. If nullptr, then no instrumentation is emitted.
|
||||
IonInstrumentation *sps_;
|
||||
// sites.
|
||||
bool emitProfilingInstrumentation_;
|
||||
|
||||
// Labels for handling exceptions and failures.
|
||||
NonAssertingLabel failureLabel_;
|
||||
|
||||
public:
|
||||
// If instrumentation should be emitted, then the sps parameter should be
|
||||
// provided, but otherwise it can be safely omitted to prevent all
|
||||
// instrumentation from being emitted.
|
||||
MacroAssembler()
|
||||
: sps_(nullptr)
|
||||
: emitProfilingInstrumentation_(false)
|
||||
{
|
||||
JitContext *jcx = GetJitContext();
|
||||
JSContext *cx = jcx->cx;
|
||||
|
@ -228,7 +219,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// (for example, Trampoline-$(ARCH).cpp and IonCaches.cpp).
|
||||
explicit MacroAssembler(JSContext *cx, IonScript *ion = nullptr,
|
||||
JSScript *script = nullptr, jsbytecode *pc = nullptr)
|
||||
: sps_(nullptr)
|
||||
: emitProfilingInstrumentation_(false)
|
||||
{
|
||||
constructRoot(cx);
|
||||
jitContext_.emplace(cx, (js::jit::TempAllocator *)nullptr);
|
||||
|
@ -240,21 +231,15 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
#endif
|
||||
if (ion) {
|
||||
setFramePushed(ion->frameSize());
|
||||
if (pc && cx->runtime()->spsProfiler.enabled()) {
|
||||
// We have to update the SPS pc when this IC stub calls into
|
||||
// the VM.
|
||||
spsPc_ = pc;
|
||||
spsInstrumentation_.emplace(&cx->runtime()->spsProfiler, &spsPc_);
|
||||
sps_ = spsInstrumentation_.ptr();
|
||||
sps_->setPushed(script);
|
||||
}
|
||||
if (pc && cx->runtime()->spsProfiler.enabled())
|
||||
emitProfilingInstrumentation_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// asm.js compilation handles its own JitContext-pushing
|
||||
struct AsmJSToken {};
|
||||
explicit MacroAssembler(AsmJSToken)
|
||||
: sps_(nullptr)
|
||||
: emitProfilingInstrumentation_(false)
|
||||
{
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
initWithAllocator();
|
||||
|
@ -262,8 +247,8 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
#endif
|
||||
}
|
||||
|
||||
void setInstrumentation(IonInstrumentation *sps) {
|
||||
sps_ = sps;
|
||||
void enableProfilingInstrumentation() {
|
||||
emitProfilingInstrumentation_ = true;
|
||||
}
|
||||
|
||||
void resetForNewCodeGenerator(TempAllocator &alloc) {
|
||||
|
@ -874,51 +859,46 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// they are returning the offset of the assembler just after the call has
|
||||
// been made so that a safepoint can be made at that location.
|
||||
|
||||
template <typename T>
|
||||
void callWithABINoProfiling(const T &fun, MoveOp::Type result = MoveOp::GENERAL) {
|
||||
MacroAssemblerSpecific::callWithABI(fun, result);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void callWithABI(const T &fun, MoveOp::Type result = MoveOp::GENERAL) {
|
||||
leaveSPSFrame();
|
||||
callWithABINoProfiling(fun, result);
|
||||
reenterSPSFrame();
|
||||
profilerPreCall();
|
||||
MacroAssemblerSpecific::callWithABI(fun, result);
|
||||
profilerPostReturn();
|
||||
}
|
||||
|
||||
// see above comment for what is returned
|
||||
uint32_t callJit(Register callee) {
|
||||
leaveSPSFrame();
|
||||
profilerPreCall();
|
||||
MacroAssemblerSpecific::callJit(callee);
|
||||
uint32_t ret = currentOffset();
|
||||
reenterSPSFrame();
|
||||
profilerPostReturn();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// see above comment for what is returned
|
||||
uint32_t callWithExitFrame(Label *target) {
|
||||
leaveSPSFrame();
|
||||
profilerPreCall();
|
||||
MacroAssemblerSpecific::callWithExitFrame(target);
|
||||
uint32_t ret = currentOffset();
|
||||
reenterSPSFrame();
|
||||
profilerPostReturn();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// see above comment for what is returned
|
||||
uint32_t callWithExitFrame(JitCode *target) {
|
||||
leaveSPSFrame();
|
||||
profilerPreCall();
|
||||
MacroAssemblerSpecific::callWithExitFrame(target);
|
||||
uint32_t ret = currentOffset();
|
||||
reenterSPSFrame();
|
||||
profilerPostReturn();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// see above comment for what is returned
|
||||
uint32_t callWithExitFrame(JitCode *target, Register dynStack) {
|
||||
leaveSPSFrame();
|
||||
profilerPreCall();
|
||||
MacroAssemblerSpecific::callWithExitFrame(target, dynStack);
|
||||
uint32_t ret = currentOffset();
|
||||
reenterSPSFrame();
|
||||
profilerPostReturn();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -954,165 +934,19 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
// These two functions are helpers used around call sites throughout the
|
||||
// assembler. They are called from the above call wrappers to emit the
|
||||
// necessary instrumentation.
|
||||
void leaveSPSFrame() {
|
||||
if (!sps_ || !sps_->enabled())
|
||||
void profilerPreCall() {
|
||||
if (!emitProfilingInstrumentation_)
|
||||
return;
|
||||
// No registers are guaranteed to be available, so push/pop a register
|
||||
// so we can use one
|
||||
push(CallTempReg0);
|
||||
sps_->leave(*this, CallTempReg0);
|
||||
pop(CallTempReg0);
|
||||
profilerPreCallImpl();
|
||||
}
|
||||
|
||||
void reenterSPSFrame() {
|
||||
if (!sps_ || !sps_->enabled())
|
||||
void profilerPostReturn() {
|
||||
if (!emitProfilingInstrumentation_)
|
||||
return;
|
||||
// Attempt to use a now-free register within a given set, but if the
|
||||
// architecture being built doesn't have an available register, resort
|
||||
// to push/pop
|
||||
GeneralRegisterSet regs(Registers::TempMask & ~Registers::JSCallMask &
|
||||
~Registers::CallMask);
|
||||
if (regs.empty()) {
|
||||
push(CallTempReg0);
|
||||
sps_->reenter(*this, CallTempReg0);
|
||||
pop(CallTempReg0);
|
||||
} else {
|
||||
sps_->reenter(*this, regs.getAny());
|
||||
}
|
||||
}
|
||||
|
||||
void spsProfileEntryAddress(SPSProfiler *p, int offset, Register temp,
|
||||
Label *full)
|
||||
{
|
||||
movePtr(ImmPtr(p->sizePointer()), temp);
|
||||
load32(Address(temp, 0), temp);
|
||||
if (offset != 0)
|
||||
add32(Imm32(offset), temp);
|
||||
branch32(Assembler::GreaterThanOrEqual, temp, Imm32(p->maxSize()), full);
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(ProfileEntry) == (2 * sizeof(void *)) + 8);
|
||||
if (sizeof(void *) == 4) {
|
||||
lshiftPtr(Imm32(4), temp);
|
||||
} else {
|
||||
lshiftPtr(Imm32(3), temp);
|
||||
mulBy3(temp, temp);
|
||||
}
|
||||
|
||||
addPtr(ImmPtr(p->stack()), temp);
|
||||
}
|
||||
|
||||
// The safe version of the above method refrains from assuming that the fields
|
||||
// of the SPSProfiler class are going to stay the same across different runs of
|
||||
// the jitcode. Ion can use the more efficient unsafe version because ion jitcode
|
||||
// will not survive changes to to the profiler settings. Baseline jitcode, however,
|
||||
// can span these changes, so any hardcoded field values will be incorrect afterwards.
|
||||
// All the sps-related methods used by baseline call |spsProfileEntryAddressSafe|.
|
||||
void spsProfileEntryAddressSafe(SPSProfiler *p, int offset, Register temp,
|
||||
Label *full)
|
||||
{
|
||||
// Load size pointer
|
||||
loadPtr(AbsoluteAddress(p->addressOfSizePointer()), temp);
|
||||
|
||||
// Load size
|
||||
load32(Address(temp, 0), temp);
|
||||
if (offset != 0)
|
||||
add32(Imm32(offset), temp);
|
||||
|
||||
// Test against max size.
|
||||
branch32(Assembler::LessThanOrEqual, AbsoluteAddress(p->addressOfMaxSize()), temp, full);
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(ProfileEntry) == (2 * sizeof(void *)) + 8);
|
||||
if (sizeof(void *) == 4) {
|
||||
lshiftPtr(Imm32(4), temp);
|
||||
} else {
|
||||
lshiftPtr(Imm32(3), temp);
|
||||
mulBy3(temp, temp);
|
||||
}
|
||||
|
||||
push(temp);
|
||||
loadPtr(AbsoluteAddress(p->addressOfStack()), temp);
|
||||
addPtr(Address(StackPointer, 0), temp);
|
||||
addPtr(Imm32(sizeof(size_t)), StackPointer);
|
||||
profilerPostReturnImpl();
|
||||
}
|
||||
|
||||
public:
|
||||
// These functions are needed by the IonInstrumentation interface defined in
|
||||
// vm/SPSProfiler.h. They will modify the pseudostack provided to SPS to
|
||||
// perform the actual instrumentation.
|
||||
|
||||
void spsUpdatePCIdx(SPSProfiler *p, int32_t idx, Register temp) {
|
||||
Label stackFull;
|
||||
spsProfileEntryAddress(p, -1, temp, &stackFull);
|
||||
store32(Imm32(idx), Address(temp, ProfileEntry::offsetOfLineOrPc()));
|
||||
bind(&stackFull);
|
||||
}
|
||||
|
||||
void spsUpdatePCIdx(SPSProfiler *p, Register idx, Register temp) {
|
||||
Label stackFull;
|
||||
spsProfileEntryAddressSafe(p, -1, temp, &stackFull);
|
||||
store32(idx, Address(temp, ProfileEntry::offsetOfLineOrPc()));
|
||||
bind(&stackFull);
|
||||
}
|
||||
|
||||
// spsPushFrame variant for Ion-optimized scripts.
|
||||
void spsPushFrame(SPSProfiler *p, const char *str, JSScript *s, Register temp) {
|
||||
Label stackFull;
|
||||
spsProfileEntryAddress(p, 0, temp, &stackFull);
|
||||
|
||||
// Push a JS frame with a copy label
|
||||
storePtr(ImmPtr(str), Address(temp, ProfileEntry::offsetOfLabel()));
|
||||
storePtr(ImmGCPtr(s), Address(temp, ProfileEntry::offsetOfSpOrScript()));
|
||||
store32(Imm32(ProfileEntry::NullPCOffset), Address(temp, ProfileEntry::offsetOfLineOrPc()));
|
||||
store32(Imm32(ProfileEntry::FRAME_LABEL_COPY), Address(temp, ProfileEntry::offsetOfFlags()));
|
||||
|
||||
/* Always increment the stack size, whether or not we actually pushed. */
|
||||
bind(&stackFull);
|
||||
movePtr(ImmPtr(p->sizePointer()), temp);
|
||||
add32(Imm32(1), Address(temp, 0));
|
||||
}
|
||||
|
||||
// spsPushFrame variant for Baseline-optimized scripts.
|
||||
void spsPushFrame(SPSProfiler *p, const Address &str, const Address &script,
|
||||
Register temp, Register temp2)
|
||||
{
|
||||
Label stackFull;
|
||||
spsProfileEntryAddressSafe(p, 0, temp, &stackFull);
|
||||
|
||||
// Push a JS frame with a copy label
|
||||
loadPtr(str, temp2);
|
||||
storePtr(temp2, Address(temp, ProfileEntry::offsetOfLabel()));
|
||||
|
||||
loadPtr(script, temp2);
|
||||
storePtr(temp2, Address(temp, ProfileEntry::offsetOfSpOrScript()));
|
||||
|
||||
// Store 0 for PCIdx because that's what interpreter does.
|
||||
// (See probes::EnterScript, which calls spsProfiler.enter, which pushes an entry
|
||||
// with 0 pcIdx).
|
||||
store32(Imm32(0), Address(temp, ProfileEntry::offsetOfLineOrPc()));
|
||||
store32(Imm32(ProfileEntry::FRAME_LABEL_COPY), Address(temp, ProfileEntry::offsetOfFlags()));
|
||||
|
||||
/* Always increment the stack size, whether or not we actually pushed. */
|
||||
bind(&stackFull);
|
||||
movePtr(ImmPtr(p->addressOfSizePointer()), temp);
|
||||
loadPtr(Address(temp, 0), temp);
|
||||
add32(Imm32(1), Address(temp, 0));
|
||||
}
|
||||
|
||||
void spsPopFrame(SPSProfiler *p, Register temp) {
|
||||
movePtr(ImmPtr(p->sizePointer()), temp);
|
||||
add32(Imm32(-1), Address(temp, 0));
|
||||
}
|
||||
|
||||
// spsPropFrameSafe does not assume |profiler->sizePointer()| will stay constant.
|
||||
void spsPopFrameSafe(SPSProfiler *p, Register temp) {
|
||||
loadPtr(AbsoluteAddress(p->addressOfSizePointer()), temp);
|
||||
add32(Imm32(-1), Address(temp, 0));
|
||||
}
|
||||
|
||||
static const char enterJitLabel[];
|
||||
void spsMarkJit(SPSProfiler *p, Register framePtr, Register temp);
|
||||
void spsUnmarkJit(SPSProfiler *p, Register temp);
|
||||
|
||||
void loadBaselineOrIonRaw(Register script, Register dest, Label *failure);
|
||||
void loadBaselineOrIonNoArgCheck(Register callee, Register dest, Label *failure);
|
||||
|
||||
|
|
|
@ -576,19 +576,6 @@ NewStringObject(JSContext *cx, HandleString str)
|
|||
return StringObject::create(cx, str);
|
||||
}
|
||||
|
||||
bool
|
||||
SPSEnter(JSContext *cx, HandleScript script)
|
||||
{
|
||||
return cx->runtime()->spsProfiler.enter(script, script->functionNonDelazifying());
|
||||
}
|
||||
|
||||
bool
|
||||
SPSExit(JSContext *cx, HandleScript script)
|
||||
{
|
||||
cx->runtime()->spsProfiler.exit(script, script->functionNonDelazifying());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out)
|
||||
{
|
||||
|
@ -803,15 +790,6 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok)
|
|||
DebugScopes::onPopStrictEvalScope(frame);
|
||||
}
|
||||
|
||||
// If the frame has a pushed SPS frame, make sure to pop it.
|
||||
if (frame->hasPushedSPSFrame()) {
|
||||
cx->runtime()->spsProfiler.exit(frame->script(), frame->maybeFun());
|
||||
// Unset the pushedSPSFrame flag because DebugEpilogue may get called before
|
||||
// probes::ExitScript in baseline during exception handling, and we don't
|
||||
// want to double-pop SPS frames.
|
||||
frame->unsetPushedSPSFrame();
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
// Pop this frame by updating jitTop, so that the exception handling
|
||||
// code will start at the previous frame.
|
||||
|
|
|
@ -705,9 +705,6 @@ JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type,
|
|||
JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape, uint32_t lexicalBegin);
|
||||
JSObject *NewStringObject(JSContext *cx, HandleString str);
|
||||
|
||||
bool SPSEnter(JSContext *cx, HandleScript script);
|
||||
bool SPSExit(JSContext *cx, HandleScript script);
|
||||
|
||||
bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out);
|
||||
bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out);
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ GenerateReturn(MacroAssembler &masm, int returnCode, SPSProfiler *prof)
|
|||
// Restore non-volatile floating point registers.
|
||||
masm.transferMultipleByRuns(NonVolatileFloatRegs, IsLoad, StackPointer, IA);
|
||||
|
||||
// Unwind the sps mark.
|
||||
masm.spsUnmarkJit(prof, r8);
|
||||
// Get rid of padding word.
|
||||
masm.addPtr(Imm32(sizeof(void*)), sp);
|
||||
|
||||
// Set up return value
|
||||
masm.ma_mov(Imm32(returnCode), r0);
|
||||
|
@ -69,7 +69,8 @@ struct EnterJITStack
|
|||
double d14;
|
||||
double d15;
|
||||
|
||||
size_t hasSPSMark;
|
||||
// Padding.
|
||||
void *padding;
|
||||
|
||||
// Non-volatile registers.
|
||||
void *r4;
|
||||
|
@ -129,9 +130,8 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
// The 5th argument is located at [sp, 36]
|
||||
masm.finishDataTransfer();
|
||||
|
||||
// Push the EnterJIT sps mark. "Frame pointer" = start of saved core regs.
|
||||
masm.movePtr(sp, r8);
|
||||
masm.spsMarkJit(&cx->runtime()->spsProfiler, r8, r9);
|
||||
// Add padding word.
|
||||
masm.subPtr(Imm32(sizeof(void*)), sp);
|
||||
|
||||
// Push the float registers.
|
||||
masm.transferMultipleByRuns(NonVolatileFloatRegs, IsStore, sp, DB);
|
||||
|
|
|
@ -59,7 +59,6 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
|
|||
nativeToBytecodeNumRegions_(0),
|
||||
nativeToBytecodeScriptList_(nullptr),
|
||||
nativeToBytecodeScriptListLength_(0),
|
||||
sps_(&GetJitContext()->runtime->spsProfiler(), &lastNotInlinedPC_),
|
||||
osrEntryOffset_(0),
|
||||
skipArgCheckEntryOffset_(0),
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
|
@ -68,8 +67,8 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
|
|||
frameDepth_(graph->paddedLocalSlotsSize() + graph->argumentsSize()),
|
||||
frameInitialAdjustment_(0)
|
||||
{
|
||||
if (!gen->compilingAsmJS())
|
||||
masm.setInstrumentation(&sps_);
|
||||
if (gen->isProfilerInstrumentationEnabled())
|
||||
masm.enableProfilingInstrumentation();
|
||||
|
||||
if (gen->compilingAsmJS()) {
|
||||
// Since asm.js uses the system ABI which does not necessarily use a
|
||||
|
@ -107,7 +106,6 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, Mac
|
|||
bool
|
||||
CodeGeneratorShared::generateOutOfLineCode()
|
||||
{
|
||||
JSScript *topScript = sps_.getPushed();
|
||||
for (size_t i = 0; i < outOfLineCode_.length(); i++) {
|
||||
// Add native => bytecode mapping entries for OOL sites.
|
||||
// Not enabled on asm.js yet since asm doesn't contain bytecode mappings.
|
||||
|
@ -123,16 +121,11 @@ CodeGeneratorShared::generateOutOfLineCode()
|
|||
|
||||
masm.setFramePushed(outOfLineCode_[i]->framePushed());
|
||||
lastPC_ = outOfLineCode_[i]->pc();
|
||||
if (!sps_.prepareForOOL())
|
||||
return false;
|
||||
sps_.setPushed(outOfLineCode_[i]->script());
|
||||
outOfLineCode_[i]->bind(&masm);
|
||||
|
||||
oolIns = outOfLineCode_[i];
|
||||
outOfLineCode_[i]->generate(this);
|
||||
sps_.finishOOL();
|
||||
}
|
||||
sps_.setPushed(topScript);
|
||||
oolIns = nullptr;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -113,11 +113,6 @@ class CodeGeneratorShared : public LElementVisitor
|
|||
JSScript **nativeToBytecodeScriptList_;
|
||||
uint32_t nativeToBytecodeScriptListLength_;
|
||||
|
||||
// When profiling is enabled, this is the instrumentation manager which
|
||||
// maintains state of what script is currently being generated (for inline
|
||||
// scripts) and when instrumentation needs to be emitted or skipped.
|
||||
IonInstrumentation sps_;
|
||||
|
||||
bool isProfilerInstrumentationEnabled() {
|
||||
return gen->isProfilerInstrumentationEnabled();
|
||||
}
|
||||
|
|
|
@ -81,9 +81,6 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.vmovdqa(xmm15, Operand(rsp, 16 * 9));
|
||||
#endif
|
||||
|
||||
// Push the EnterJIT sps mark.
|
||||
masm.spsMarkJit(&cx->runtime()->spsProfiler, rbp, rbx);
|
||||
|
||||
// Save arguments passed in registers needed after function call.
|
||||
masm.push(result);
|
||||
|
||||
|
@ -281,9 +278,6 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.pop(r12); // vp
|
||||
masm.storeValue(JSReturnOperand, Operand(r12, 0));
|
||||
|
||||
// Unwind the sps mark.
|
||||
masm.spsUnmarkJit(&cx->runtime()->spsProfiler, rbx);
|
||||
|
||||
// Restore non-volatile registers.
|
||||
#if defined(_WIN64)
|
||||
masm.vmovdqa(Operand(rsp, 16 * 0), xmm6);
|
||||
|
|
|
@ -60,9 +60,6 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.push(esi);
|
||||
masm.push(edi);
|
||||
|
||||
// Push the EnterJIT sps mark.
|
||||
masm.spsMarkJit(&cx->runtime()->spsProfiler, ebp, ebx);
|
||||
|
||||
// Keep track of the stack which has to be unwound after returning from the
|
||||
// compiled function.
|
||||
masm.movl(esp, esi);
|
||||
|
@ -272,21 +269,18 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
|
||||
// |ebp| could have been clobbered by the inner function.
|
||||
// Grab the address for the Value result from the argument stack.
|
||||
// +24 ... arguments ...
|
||||
// +20 <return>
|
||||
// +16 ebp <- original %ebp pointing here.
|
||||
// +12 ebx
|
||||
// +8 esi
|
||||
// +4 edi
|
||||
// +0 hasSPSFrame
|
||||
masm.loadPtr(Address(esp, ARG_RESULT + 4 * sizeof(void *)), eax);
|
||||
// +20 ... arguments ...
|
||||
// +16 <return>
|
||||
// +12 ebp <- original %ebp pointing here.
|
||||
// +8 ebx
|
||||
// +4 esi
|
||||
// +0 edi
|
||||
masm.loadPtr(Address(esp, ARG_RESULT + 3 * sizeof(void *)), eax);
|
||||
masm.storeValue(JSReturnOperand, Operand(eax, 0));
|
||||
|
||||
/**************************************************************
|
||||
Return stack and registers to correct state
|
||||
**************************************************************/
|
||||
// Unwind the sps mark.
|
||||
masm.spsUnmarkJit(&cx->runtime()->spsProfiler, ebx);
|
||||
|
||||
// Restore non-volatile registers
|
||||
masm.pop(edi);
|
||||
|
|
|
@ -93,7 +93,7 @@ SPSProfiler::enable(bool enabled)
|
|||
* jitcode for scripts with active frames on the stack. These scripts need to have
|
||||
* their profiler state toggled so they behave properly.
|
||||
*/
|
||||
jit::ToggleBaselineSPS(rt, enabled);
|
||||
jit::ToggleBaselineProfiling(rt, enabled);
|
||||
|
||||
/* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
|
||||
* stack.
|
||||
|
@ -333,7 +333,6 @@ SPSEntryMarker::SPSEntryMarker(JSRuntime *rt,
|
|||
size_before = *profiler->size_;
|
||||
// We want to push a CPP frame so the profiler can correctly order JS and native stacks.
|
||||
profiler->push("js::RunScript", this, nullptr, nullptr, /* copy = */ false);
|
||||
// We also want to push a JS frame so the hang monitor can catch script hangs.
|
||||
profiler->push("js::RunScript", nullptr, script, script->code(), /* copy = */ false);
|
||||
}
|
||||
|
||||
|
|
|
@ -287,230 +287,19 @@ class SPSEntryMarker
|
|||
template<class Assembler, class Register>
|
||||
class SPSInstrumentation
|
||||
{
|
||||
/* Because of inline frames, this is a nested structure in a vector */
|
||||
struct FrameState {
|
||||
JSScript *script; // script for this frame, nullptr if not pushed yet
|
||||
jsbytecode *pc; // pc at which this frame was left for entry into a callee
|
||||
bool skipNext; // should the next call to reenter be skipped?
|
||||
int left; // number of leave() calls made without a matching reenter()
|
||||
};
|
||||
|
||||
SPSProfiler *profiler_; // Instrumentation location management
|
||||
|
||||
Vector<FrameState, 1, SystemAllocPolicy> frames;
|
||||
FrameState *frame;
|
||||
|
||||
static void clearFrame(FrameState *frame) {
|
||||
frame->script = nullptr;
|
||||
frame->pc = nullptr;
|
||||
frame->skipNext = false;
|
||||
frame->left = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
/*
|
||||
* Creates instrumentation which writes information out the the specified
|
||||
* profiler's stack and constituent fields.
|
||||
*/
|
||||
explicit SPSInstrumentation(SPSProfiler *profiler)
|
||||
: profiler_(profiler), frame(nullptr)
|
||||
{
|
||||
enterInlineFrame(nullptr);
|
||||
}
|
||||
explicit SPSInstrumentation(SPSProfiler *profiler) : profiler_(profiler) {}
|
||||
|
||||
/* Small proxies around SPSProfiler */
|
||||
bool enabled() { return profiler_ && profiler_->enabled(); }
|
||||
SPSProfiler *profiler() { MOZ_ASSERT(enabled()); return profiler_; }
|
||||
void disable() { profiler_ = nullptr; }
|
||||
|
||||
/* Signals an inline function returned, reverting to the previous state */
|
||||
void leaveInlineFrame() {
|
||||
if (!enabled())
|
||||
return;
|
||||
MOZ_ASSERT(frame->left == 0);
|
||||
MOZ_ASSERT(frame->script != nullptr);
|
||||
frames.shrinkBy(1);
|
||||
MOZ_ASSERT(frames.length() > 0);
|
||||
frame = &frames[frames.length() - 1];
|
||||
}
|
||||
|
||||
/* Saves the current state and assumes a fresh one for the inline function */
|
||||
bool enterInlineFrame(jsbytecode *callerPC) {
|
||||
if (!enabled())
|
||||
return true;
|
||||
MOZ_ASSERT_IF(frames.empty(), callerPC == nullptr);
|
||||
|
||||
MOZ_ASSERT_IF(frame != nullptr, frame->script != nullptr);
|
||||
MOZ_ASSERT_IF(frame != nullptr, frame->left == 1);
|
||||
if (!frames.empty()) {
|
||||
MOZ_ASSERT(frame == &frames[frames.length() - 1]);
|
||||
frame->pc = callerPC;
|
||||
}
|
||||
if (!frames.growBy(1))
|
||||
return false;
|
||||
frame = &frames[frames.length() - 1];
|
||||
clearFrame(frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Prepares the instrumenter state for generating OOL code, by
|
||||
* setting up the frame state to seem as if there are exactly
|
||||
* two pushed frames: a frame for the top-level script, and
|
||||
* a frame for the OOL code being generated. Any
|
||||
* vm-calls from the OOL code will "leave" the OOL frame and
|
||||
* return back to it.
|
||||
*/
|
||||
bool prepareForOOL() {
|
||||
if (!enabled())
|
||||
return true;
|
||||
MOZ_ASSERT(!frames.empty());
|
||||
if (frames.length() >= 2) {
|
||||
frames.shrinkBy(frames.length() - 2);
|
||||
|
||||
} else { // frames.length() == 1
|
||||
if (!frames.growBy(1))
|
||||
return false;
|
||||
}
|
||||
frames[0].pc = frames[0].script->code();
|
||||
frame = &frames[1];
|
||||
clearFrame(frame);
|
||||
return true;
|
||||
}
|
||||
void finishOOL() {
|
||||
if (!enabled())
|
||||
return;
|
||||
MOZ_ASSERT(!frames.empty());
|
||||
frames.shrinkBy(frames.length() - 1);
|
||||
}
|
||||
|
||||
/* Number of inline frames currently active (doesn't include original one) */
|
||||
unsigned inliningDepth() {
|
||||
return frames.length() - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* When debugging or with slow assertions, sometimes a C++ method will be
|
||||
* invoked to perform the pop operation from the SPS stack. When we leave
|
||||
* JIT code, we need to record the current PC, but upon reentering JIT
|
||||
* code, no update back to nullptr should happen. This method exists to
|
||||
* flag this behavior. The next leave() will emit instrumentation, but the
|
||||
* following reenter() will be a no-op.
|
||||
*/
|
||||
void skipNextReenter() {
|
||||
/* If we've left the frame, the reenter will be skipped anyway */
|
||||
if (!enabled() || frame->left != 0)
|
||||
return;
|
||||
MOZ_ASSERT(frame->script);
|
||||
MOZ_ASSERT(!frame->skipNext);
|
||||
frame->skipNext = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* In some cases, a frame needs to be flagged as having been pushed, but no
|
||||
* instrumentation should be emitted. This updates internal state to flag
|
||||
* that further instrumentation should actually be emitted.
|
||||
*/
|
||||
void setPushed(JSScript *script) {
|
||||
if (!enabled())
|
||||
return;
|
||||
MOZ_ASSERT(frame->left == 0);
|
||||
frame->script = script;
|
||||
}
|
||||
|
||||
JSScript *getPushed() {
|
||||
if (!enabled())
|
||||
return nullptr;
|
||||
return frame->script;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flags entry into a JS function for the first time. Before this is called,
|
||||
* no instrumentation is emitted, but after this instrumentation is emitted.
|
||||
*/
|
||||
bool push(JSScript *script, Assembler &masm, Register scratch, bool inlinedFunction = false) {
|
||||
if (!enabled())
|
||||
return true;
|
||||
if (!inlinedFunction) {
|
||||
const char *string = profiler_->profileString(script, script->functionNonDelazifying());
|
||||
if (string == nullptr)
|
||||
return false;
|
||||
masm.spsPushFrame(profiler_, string, script, scratch);
|
||||
}
|
||||
setPushed(script);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signifies that C++ performed the push() for this function. C++ always
|
||||
* sets the current PC to something non-null, however, so as soon as JIT
|
||||
* code is reentered this updates the current pc to nullptr.
|
||||
*/
|
||||
void pushManual(JSScript *script, Assembler &masm, Register scratch,
|
||||
bool inlinedFunction = false)
|
||||
{
|
||||
if (!enabled())
|
||||
return;
|
||||
|
||||
if (!inlinedFunction)
|
||||
masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCOffset, scratch);
|
||||
|
||||
setPushed(script);
|
||||
}
|
||||
|
||||
/*
|
||||
* Signals that the current function is leaving for a function call. This
|
||||
* can happen both on JS function calls and also calls to C++. This
|
||||
* internally manages how many leave() calls have been seen, and only the
|
||||
* first leave() emits instrumentation. Similarly, only the last
|
||||
* corresponding reenter() actually emits instrumentation.
|
||||
*/
|
||||
void leave(jsbytecode *pc, Assembler &masm, Register scratch, bool inlinedFunction = false) {
|
||||
if (enabled() && frame->script && frame->left++ == 0) {
|
||||
jsbytecode *updatePC = pc;
|
||||
JSScript *script = frame->script;
|
||||
if (!inlinedFunction) {
|
||||
// We may be leaving an inlined frame for entry into a C++ frame.
|
||||
// Use the top script's pc offset instead of the innermost script's.
|
||||
if (inliningDepth() > 0) {
|
||||
MOZ_ASSERT(frames[0].pc);
|
||||
updatePC = frames[0].pc;
|
||||
script = frames[0].script;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inlinedFunction)
|
||||
masm.spsUpdatePCIdx(profiler_, script->pcToOffset(updatePC), scratch);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Flags that the leaving of the current function has returned. This tracks
|
||||
* state with leave() to only emit instrumentation at proper times.
|
||||
*/
|
||||
void reenter(Assembler &masm, Register scratch, bool inlinedFunction = false) {
|
||||
if (!enabled() || !frame->script || frame->left-- != 1)
|
||||
return;
|
||||
if (frame->skipNext) {
|
||||
frame->skipNext = false;
|
||||
} else {
|
||||
if (!inlinedFunction)
|
||||
masm.spsUpdatePCIdx(profiler_, ProfileEntry::NullPCOffset, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Signifies exiting a JS frame, popping the SPS entry. Because there can be
|
||||
* multiple return sites of a function, this does not cease instrumentation
|
||||
* emission.
|
||||
*/
|
||||
void pop(Assembler &masm, Register scratch, bool inlinedFunction = false) {
|
||||
if (enabled()) {
|
||||
MOZ_ASSERT(frame->left == 0);
|
||||
MOZ_ASSERT(frame->script);
|
||||
if (!inlinedFunction)
|
||||
masm.spsPopFrame(profiler_, scratch);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1370,7 +1370,8 @@ AbstractFramePtr::hasPushedSPSFrame() const
|
|||
{
|
||||
if (isInterpreterFrame())
|
||||
return asInterpreterFrame()->hasPushedSPSFrame();
|
||||
return asBaselineFrame()->hasPushedSPSFrame();
|
||||
MOZ_ASSERT(isBaselineFrame());
|
||||
return false;
|
||||
}
|
||||
|
||||
jit::JitActivation::JitActivation(JSContext *cx, bool active)
|
||||
|
|
Загрузка…
Ссылка в новой задаче