Bug 1057082 - 5/7 - Remove SPS instrumentation and replace with exitaddr instrumentation. r=jandem

This commit is contained in:
Kannan Vijayan 2015-01-15 20:11:22 -05:00
parent 0d3847e5c8
commit c43a292ceb
36 changed files with 94 additions and 1298 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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()) {

View File

@ -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()
{

View File

@ -256,8 +256,6 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool emitDebugTrap();
bool emitTraceLoggerEnter();
bool emitTraceLoggerExit();
bool emitSPSPush();
void emitSPSPop();
void emitProfilerEnterFrame();
void emitProfilerExitFrame();

View File

@ -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.

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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);
}
}

View File

@ -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.

View File

@ -3653,7 +3653,7 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mi
MOZ_CRASH();
}
masm.callWithABINoProfiling(callee);
masm.callWithABI(callee);
restoreVolatile();
masm.bind(&done);
@ -3719,7 +3719,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();
@ -6932,9 +6932,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();
@ -7210,8 +7207,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();
script->setIonScript(cx, ionScript);
@ -8897,49 +8894,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_;

View File

@ -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);

View File

@ -705,7 +705,7 @@ IonScript::IonScript()
invalidateEpilogueOffset_(0),
invalidateEpilogueDataOffset_(0),
numBailouts_(0),
hasSPSInstrumentation_(false),
hasProfilingInstrumentation_(false),
recompiling_(false),
runtimeData_(0),
runtimeSize_(0),

View File

@ -705,8 +705,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
@ -4072,9 +4070,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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -305,7 +305,6 @@
_(InterruptCheck) \
_(AsmJSInterruptCheck) \
_(InterruptCheckImplicit) \
_(ProfilerStackOp) \
_(GetDOMProperty) \
_(GetDOMMemberV) \
_(GetDOMMemberT) \

View File

@ -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)
{

View File

@ -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);

View File

@ -11449,48 +11449,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
{

View File

@ -226,7 +226,6 @@ namespace jit {
_(CallInstanceOf) \
_(InterruptCheck) \
_(AsmJSInterruptCheck) \
_(ProfilerStackOp) \
_(GetDOMProperty) \
_(GetDOMMember) \
_(SetDOMProperty) \

View File

@ -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()
{

View File

@ -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);

View File

@ -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.

View File

@ -679,9 +679,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);

View File

@ -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);

View File

@ -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;

View File

@ -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();
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
}
};

View File

@ -1373,7 +1373,8 @@ AbstractFramePtr::hasPushedSPSFrame() const
{
if (isInterpreterFrame())
return asInterpreterFrame()->hasPushedSPSFrame();
return asBaselineFrame()->hasPushedSPSFrame();
MOZ_ASSERT(isBaselineFrame());
return false;
}
jit::JitActivation::JitActivation(JSContext *cx, bool active)