зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1057082 - 3/7 - Modify jits to use lastProfilingFrame and lastProfilingCallSite fields. r=jandem
This commit is contained in:
Родитель
b3b9045b11
Коммит
45cbaa636c
|
@ -40,6 +40,7 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
|
|||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
JitFrameIterator iter(jitActivations);
|
||||
MOZ_ASSERT(!iter.ionScript()->invalidated());
|
||||
CommonFrameLayout *currentFramePtr = iter.current();
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger_Bailout);
|
||||
|
@ -89,6 +90,26 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
|
|||
if (iter.ionScript()->invalidated())
|
||||
iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
|
||||
// NB: Commentary on how |lastProfilingFrame| is set from bailouts.
|
||||
//
|
||||
// Once we return to jitcode, any following frames might get clobbered,
|
||||
// but the current frame will not (as it will be clobbered "in-place"
|
||||
// with a baseline frame that will share the same frame prefix).
|
||||
// However, there may be multiple baseline frames unpacked from this
|
||||
// single Ion frame, which means we will need to once again reset
|
||||
// |lastProfilingFrame| to point to the correct unpacked last frame
|
||||
// in |FinishBailoutToBaseline|.
|
||||
//
|
||||
// In the case of error, the jitcode will jump immediately to an
|
||||
// exception handler, which will unwind the frames and properly set
|
||||
// the |lastProfilingFrame| to point to the frame being resumed into
|
||||
// (see |AutoResetLastProfilerFrameOnReturnFromException|).
|
||||
//
|
||||
// In both cases, we want to temporarily set the |lastProfilingFrame|
|
||||
// to the current frame being bailed out, and then fix it up later.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -106,6 +127,7 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
|
|||
JitActivationIterator jitActivations(cx->runtime());
|
||||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
JitFrameIterator iter(jitActivations);
|
||||
CommonFrameLayout *currentFramePtr = iter.current();
|
||||
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
TraceLogTimestamp(logger, TraceLogger_Invalidation);
|
||||
|
@ -161,6 +183,10 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
|
|||
|
||||
iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
|
||||
// Make the frame being bailed out the top profiled frame.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -194,6 +220,7 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
|
|||
JitActivationIterator jitActivations(cx->runtime());
|
||||
BailoutFrameInfo bailoutData(jitActivations, frame.frame());
|
||||
JitFrameIterator iter(jitActivations);
|
||||
CommonFrameLayout *currentFramePtr = iter.current();
|
||||
|
||||
BaselineBailoutInfo *bailoutInfo = nullptr;
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true,
|
||||
|
@ -226,6 +253,10 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
|
|||
MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR);
|
||||
}
|
||||
|
||||
// Make the frame being bailed out the top profiled frame.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -1721,6 +1721,12 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
|
|||
JitFrameIterator iter(cx);
|
||||
uint8_t *outerFp = nullptr;
|
||||
|
||||
// Iter currently points at the exit frame. Get the previous frame
|
||||
// (which must be a baseline frame), and set it as the last profiling
|
||||
// frame.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
cx->mainThread().jitActivation->setLastProfilingFrame(iter.prevFp());
|
||||
|
||||
uint32_t frameno = 0;
|
||||
while (frameno < numFrames) {
|
||||
MOZ_ASSERT(!iter.isIonJS());
|
||||
|
|
|
@ -176,6 +176,8 @@ BaselineCompiler::compile()
|
|||
prologueOffset_.fixup(&masm);
|
||||
epilogueOffset_.fixup(&masm);
|
||||
spsPushToggleOffset_.fixup(&masm);
|
||||
profilerEnterFrameToggleOffset_.fixup(&masm);
|
||||
profilerExitFrameToggleOffset_.fixup(&masm);
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
traceLoggerEnterToggleOffset_.fixup(&masm);
|
||||
traceLoggerExitToggleOffset_.fixup(&masm);
|
||||
|
@ -189,6 +191,8 @@ BaselineCompiler::compile()
|
|||
BaselineScript::New(script, prologueOffset_.offset(),
|
||||
epilogueOffset_.offset(),
|
||||
spsPushToggleOffset_.offset(),
|
||||
profilerEnterFrameToggleOffset_.offset(),
|
||||
profilerExitFrameToggleOffset_.offset(),
|
||||
traceLoggerEnterToggleOffset_.offset(),
|
||||
traceLoggerExitToggleOffset_.offset(),
|
||||
postDebugPrologueOffset_.offset(),
|
||||
|
@ -263,8 +267,9 @@ BaselineCompiler::compile()
|
|||
if (compileDebugInstrumentation_)
|
||||
baselineScript->setHasDebugInstrumentation();
|
||||
|
||||
// Register a native => bytecode mapping entry for this script if needed.
|
||||
if (cx->runtime()->jitRuntime()->isNativeToBytecodeMapEnabled(cx->runtime())) {
|
||||
// If profiler instrumentation is enabled, register a native => bytecode mapping entry,
|
||||
// and toggle profiling on
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) {
|
||||
JitSpew(JitSpew_Profiling, "Added JitcodeGlobalEntry for baseline script %s:%d (%p)",
|
||||
script->filename(), script->lineno(), baselineScript.get());
|
||||
JitcodeGlobalEntry::BaselineEntry entry;
|
||||
|
@ -276,6 +281,9 @@ BaselineCompiler::compile()
|
|||
|
||||
// Mark the jitcode as having a bytecode map.
|
||||
code->setHasBytecodeMap();
|
||||
|
||||
// Toggle profiler instrumentation on in the jitcode.
|
||||
baselineScript->toggleProfilerInstrumentation(true);
|
||||
}
|
||||
|
||||
script->setBaselineScript(cx, baselineScript.release());
|
||||
|
@ -324,6 +332,8 @@ BaselineCompiler::emitPrologue()
|
|||
masm.pushReturnAddress();
|
||||
masm.checkStackAlignment();
|
||||
#endif
|
||||
emitProfilerEnterFrame();
|
||||
|
||||
masm.push(BaselineFrameReg);
|
||||
masm.mov(BaselineStackReg, BaselineFrameReg);
|
||||
|
||||
|
@ -438,6 +448,8 @@ BaselineCompiler::emitEpilogue()
|
|||
masm.mov(BaselineFrameReg, BaselineStackReg);
|
||||
masm.pop(BaselineFrameReg);
|
||||
|
||||
emitProfilerExitFrame();
|
||||
|
||||
masm.ret();
|
||||
return true;
|
||||
}
|
||||
|
@ -856,6 +868,36 @@ BaselineCompiler::emitSPSPop()
|
|||
masm.bind(&noPop);
|
||||
}
|
||||
|
||||
void
|
||||
BaselineCompiler::emitProfilerEnterFrame()
|
||||
{
|
||||
// Store stack position to lastProfilingFrame variable, guarded by a toggled jump.
|
||||
// Starts off initially disabled.
|
||||
Label noInstrument;
|
||||
CodeOffsetLabel toggleOffset = masm.toggledJump(&noInstrument);
|
||||
masm.profilerEnterFrame(BaselineStackReg, R0.scratchReg());
|
||||
masm.bind(&noInstrument);
|
||||
|
||||
// Store the start offset in the appropriate location.
|
||||
MOZ_ASSERT(profilerEnterFrameToggleOffset_.offset() == 0);
|
||||
profilerEnterFrameToggleOffset_ = toggleOffset;
|
||||
}
|
||||
|
||||
void
|
||||
BaselineCompiler::emitProfilerExitFrame()
|
||||
{
|
||||
// Store previous frame to lastProfilingFrame variable, guarded by a toggled jump.
|
||||
// Starts off initially disabled.
|
||||
Label noInstrument;
|
||||
CodeOffsetLabel toggleOffset = masm.toggledJump(&noInstrument);
|
||||
masm.profilerExitFrame();
|
||||
masm.bind(&noInstrument);
|
||||
|
||||
// Store the start offset in the appropriate location.
|
||||
MOZ_ASSERT(profilerExitFrameToggleOffset_.offset() == 0);
|
||||
profilerExitFrameToggleOffset_ = toggleOffset;
|
||||
}
|
||||
|
||||
MethodStatus
|
||||
BaselineCompiler::emitBody()
|
||||
{
|
||||
|
@ -3630,6 +3672,19 @@ BaselineCompiler::emit_JSOP_RESUME()
|
|||
masm.jump(&returnTarget);
|
||||
masm.bind(&genStart);
|
||||
|
||||
// If profiler instrumentation is on, update lastProfilingFrame on
|
||||
// current JitActivation
|
||||
{
|
||||
Register scratchReg = scratch2;
|
||||
Label skip;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skip);
|
||||
masm.loadPtr(AbsoluteAddress(cx->mainThread().addressOfProfilingActivation()), scratchReg);
|
||||
masm.storePtr(BaselineStackReg,
|
||||
Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()));
|
||||
masm.bind(&skip);
|
||||
}
|
||||
|
||||
// Construct BaselineFrame.
|
||||
masm.push(BaselineFrameReg);
|
||||
masm.mov(BaselineStackReg, BaselineFrameReg);
|
||||
|
|
|
@ -259,6 +259,9 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
|||
bool emitSPSPush();
|
||||
void emitSPSPop();
|
||||
|
||||
void emitProfilerEnterFrame();
|
||||
void emitProfilerExitFrame();
|
||||
|
||||
bool initScopeChain();
|
||||
|
||||
void storeValue(const StackValue *source, const Address &dest,
|
||||
|
|
|
@ -1078,6 +1078,21 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
// the stack.
|
||||
masm.pop(scratchReg);
|
||||
|
||||
#ifdef DEBUG
|
||||
// If profiler instrumentation is on, ensure that lastProfilingFrame is
|
||||
// the frame currently being OSR-ed
|
||||
{
|
||||
Label checkOk;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &checkOk);
|
||||
masm.loadPtr(AbsoluteAddress((void*)&cx->mainThread().jitActivation), scratchReg);
|
||||
masm.loadPtr(Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()), scratchReg);
|
||||
masm.branchPtr(Assembler::Equal, scratchReg, BaselineStackReg, &checkOk);
|
||||
masm.assumeUnreachable("Baseline OSR lastProfilingFrame mismatch.");
|
||||
masm.bind(&checkOk);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Jump into Ion.
|
||||
masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, jitcode)), scratchReg);
|
||||
masm.loadPtr(Address(osrDataReg, offsetof(IonOsrTempData, baselineFrame)), OsrFrameReg);
|
||||
|
|
|
@ -42,7 +42,10 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue *stackVal)
|
|||
}
|
||||
|
||||
BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset,
|
||||
uint32_t postDebugPrologueOffset)
|
||||
: method_(nullptr),
|
||||
|
@ -55,6 +58,8 @@ BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
|
|||
spsOn_(false),
|
||||
#endif
|
||||
spsPushToggleOffset_(spsPushToggleOffset),
|
||||
profilerEnterToggleOffset_(profilerEnterToggleOffset),
|
||||
profilerExitToggleOffset_(profilerExitToggleOffset),
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
# ifdef DEBUG
|
||||
traceLoggerScriptsEnabled_(false),
|
||||
|
@ -342,8 +347,10 @@ jit::CanEnterBaselineMethod(JSContext *cx, RunState &state)
|
|||
|
||||
BaselineScript *
|
||||
BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilogueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset, uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset, uint32_t traceLoggerExitToggleOffset,
|
||||
uint32_t postDebugPrologueOffset,
|
||||
size_t icEntries, size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries, size_t yieldEntries)
|
||||
{
|
||||
|
@ -370,8 +377,10 @@ BaselineScript::New(JSScript *jsscript, uint32_t prologueOffset, uint32_t epilog
|
|||
if (!script)
|
||||
return nullptr;
|
||||
new (script) BaselineScript(prologueOffset, epilogueOffset,
|
||||
spsPushToggleOffset, traceLoggerEnterToggleOffset,
|
||||
traceLoggerExitToggleOffset, postDebugPrologueOffset);
|
||||
spsPushToggleOffset,
|
||||
profilerEnterToggleOffset, profilerExitToggleOffset,
|
||||
traceLoggerEnterToggleOffset, traceLoggerExitToggleOffset,
|
||||
postDebugPrologueOffset);
|
||||
|
||||
size_t offsetCursor = sizeof(BaselineScript);
|
||||
MOZ_ASSERT(offsetCursor == AlignBytes(sizeof(BaselineScript), DataAlignment));
|
||||
|
@ -950,6 +959,29 @@ BaselineScript::toggleTraceLoggerEngine(bool enable)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
BaselineScript::toggleProfilerInstrumentation(bool enable)
|
||||
{
|
||||
if (enable == isProfilerInstrumentationOn())
|
||||
return;
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " toggling SPS %s for BaselineScript %p",
|
||||
enable ? "on" : "off", this);
|
||||
|
||||
// Toggle the jump
|
||||
CodeLocationLabel enterToggleLocation(method_, CodeOffsetLabel(profilerEnterToggleOffset_));
|
||||
CodeLocationLabel exitToggleLocation(method_, CodeOffsetLabel(profilerExitToggleOffset_));
|
||||
if (enable) {
|
||||
Assembler::ToggleToCmp(enterToggleLocation);
|
||||
Assembler::ToggleToCmp(exitToggleLocation);
|
||||
flags_ |= uint32_t(PROFILER_INSTRUMENTATION_ON);
|
||||
} else {
|
||||
Assembler::ToggleToJmp(enterToggleLocation);
|
||||
Assembler::ToggleToJmp(exitToggleLocation);
|
||||
flags_ &= ~uint32_t(PROFILER_INSTRUMENTATION_ON);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::purgeOptimizedStubs(Zone *zone)
|
||||
{
|
||||
|
@ -1053,6 +1085,7 @@ jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable)
|
|||
if (!script->hasBaselineScript())
|
||||
continue;
|
||||
script->baselineScript()->toggleSPS(enable);
|
||||
script->baselineScript()->toggleProfilerInstrumentation(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,8 @@ struct BaselineScript
|
|||
mozilla::DebugOnly<bool> spsOn_;
|
||||
#endif
|
||||
uint32_t spsPushToggleOffset_;
|
||||
uint32_t profilerEnterToggleOffset_;
|
||||
uint32_t profilerExitToggleOffset_;
|
||||
|
||||
// The offsets and event used for Tracelogger toggling.
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
|
@ -185,7 +187,10 @@ struct BaselineScript
|
|||
// Flag set if this script has ever been Ion compiled, either directly
|
||||
// or inlined into another script. This is cleared when the script's
|
||||
// type information or caches are cleared.
|
||||
ION_COMPILED_OR_INLINED = 1 << 4
|
||||
ION_COMPILED_OR_INLINED = 1 << 4,
|
||||
|
||||
// Flag is set if this script has profiling instrumentation turned on.
|
||||
PROFILER_INSTRUMENTATION_ON = 1 << 5
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -214,14 +219,22 @@ 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 traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, uint32_t postDebugPrologueOffset);
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset,
|
||||
uint32_t postDebugPrologueOffset);
|
||||
|
||||
static BaselineScript *New(JSScript *jsscript, uint32_t prologueOffset,
|
||||
uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
|
||||
uint32_t spsPushToggleOffset, uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset, size_t icEntries,
|
||||
size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
uint32_t spsPushToggleOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t traceLoggerEnterToggleOffset,
|
||||
uint32_t traceLoggerExitToggleOffset,
|
||||
size_t icEntries, size_t pcMappingIndexEntries,
|
||||
size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries, size_t yieldEntries);
|
||||
|
||||
static void Trace(JSTracer *trc, BaselineScript *script);
|
||||
|
@ -386,6 +399,10 @@ struct BaselineScript
|
|||
void toggleDebugTraps(JSScript *script, jsbytecode *pc);
|
||||
|
||||
void toggleSPS(bool enable);
|
||||
void toggleProfilerInstrumentation(bool enable);
|
||||
bool isProfilerInstrumentationOn() const {
|
||||
return flags_ & PROFILER_INSTRUMENTATION_ON;
|
||||
}
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
void initTraceLogger(JSRuntime *runtime, JSScript *script);
|
||||
|
|
|
@ -1981,6 +1981,8 @@ CodeGenerator::visitReturn(LReturn *lir)
|
|||
void
|
||||
CodeGenerator::visitOsrEntry(LOsrEntry *lir)
|
||||
{
|
||||
Register temp = ToRegister(lir->temp());
|
||||
|
||||
// Remember the OSR entry offset into the code buffer.
|
||||
masm.flushBuffer();
|
||||
setOsrEntryOffset(masm.size());
|
||||
|
@ -1990,6 +1992,10 @@ CodeGenerator::visitOsrEntry(LOsrEntry *lir)
|
|||
emitTracelogStartEvent(TraceLogger_IonMonkey);
|
||||
#endif
|
||||
|
||||
// If profiling, save the current frame pointer to a per-thread global field.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerEnterFrame(StackPointer, temp);
|
||||
|
||||
// Allocate the full frame for this function
|
||||
// Note we have a new entry here. So we reset MacroAssembler::framePushed()
|
||||
// to 0, before reserving the stack.
|
||||
|
@ -7154,7 +7160,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints)
|
|||
return false;
|
||||
|
||||
// Encode native to bytecode map if profiling is enabled.
|
||||
if (isNativeToBytecodeMapEnabled()) {
|
||||
if (isProfilerInstrumentationEnabled()) {
|
||||
// Generate native-to-bytecode main table.
|
||||
if (!generateCompactNativeToBytecodeMap(cx, code))
|
||||
return false;
|
||||
|
|
|
@ -429,7 +429,7 @@ IonCache::linkAndAttachStub(JSContext *cx, MacroAssembler &masm, StubAttacher &a
|
|||
attachStub(masm, attacher, code);
|
||||
|
||||
// Add entry to native => bytecode mapping for this stub if needed.
|
||||
if (cx->runtime()->jitRuntime()->isNativeToBytecodeMapEnabled(cx->runtime())) {
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) {
|
||||
JitcodeGlobalEntry::IonCacheEntry entry;
|
||||
entry.init(code->raw(), code->raw() + code->instructionsSize(), rejoinAddress());
|
||||
|
||||
|
|
|
@ -399,12 +399,8 @@ class JitRuntime
|
|||
return jitcodeGlobalTable_;
|
||||
}
|
||||
|
||||
bool isNativeToBytecodeMapEnabled(JSRuntime *rt) {
|
||||
#ifdef DEBUG
|
||||
return true;
|
||||
#else // DEBUG
|
||||
bool isProfilerInstrumentationEnabled(JSRuntime *rt) {
|
||||
return rt->spsProfiler.enabled();
|
||||
#endif // DEBUG
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/SPSProfiler.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsinferinlines.h"
|
||||
|
@ -682,12 +683,54 @@ struct AutoClearBaselineOverridePc
|
|||
~AutoClearBaselineOverridePc() { frame->clearOverridePc(); }
|
||||
};
|
||||
|
||||
struct AutoResetLastProfilerFrameOnReturnFromException
|
||||
{
|
||||
JSContext *cx;
|
||||
ResumeFromException *rfe;
|
||||
|
||||
AutoResetLastProfilerFrameOnReturnFromException(JSContext *cx, ResumeFromException *rfe)
|
||||
: cx(cx), rfe(rfe) {}
|
||||
|
||||
~AutoResetLastProfilerFrameOnReturnFromException() {
|
||||
if (!cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(cx->mainThread().jitActivation == cx->mainThread().profilingActivation());
|
||||
|
||||
void *lastProfilingFrame = getLastProfilingFrame();
|
||||
cx->mainThread().jitActivation->setLastProfilingFrame(lastProfilingFrame);
|
||||
}
|
||||
|
||||
void *getLastProfilingFrame() {
|
||||
switch (rfe->kind) {
|
||||
case ResumeFromException::RESUME_ENTRY_FRAME:
|
||||
return nullptr;
|
||||
|
||||
// The following all return into baseline frames.
|
||||
case ResumeFromException::RESUME_CATCH:
|
||||
case ResumeFromException::RESUME_FINALLY:
|
||||
case ResumeFromException::RESUME_FORCED_RETURN:
|
||||
return rfe->framePointer + BaselineFrame::FramePointerOffset;
|
||||
|
||||
// When resuming into a bailed-out ion frame, use the bailout info to
|
||||
// find the frame we are resuming into.
|
||||
case ResumeFromException::RESUME_BAILOUT:
|
||||
return rfe->bailoutInfo->incomingStack;
|
||||
}
|
||||
|
||||
MOZ_CRASH("Invalid ResumeFromException type!");
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
HandleException(ResumeFromException *rfe)
|
||||
{
|
||||
JSContext *cx = GetJSContextFromJitCode();
|
||||
TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
|
||||
|
||||
AutoResetLastProfilerFrameOnReturnFromException profFrameReset(cx, rfe);
|
||||
|
||||
rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
|
||||
|
||||
JitSpew(JitSpew_IonInvalidate, "handling exception");
|
||||
|
|
|
@ -331,6 +331,9 @@ class CommonFrameLayout
|
|||
static size_t offsetOfDescriptor() {
|
||||
return offsetof(CommonFrameLayout, descriptor_);
|
||||
}
|
||||
uintptr_t descriptor() const {
|
||||
return descriptor_;
|
||||
}
|
||||
static size_t offsetOfReturnAddress() {
|
||||
return offsetof(CommonFrameLayout, returnAddress_);
|
||||
}
|
||||
|
@ -823,6 +826,11 @@ class BaselineStubFrameLayout : public CommonFrameLayout
|
|||
return -int(2 * sizeof(void *));
|
||||
}
|
||||
|
||||
void *reverseSavedFramePtr() {
|
||||
uint8_t *addr = ((uint8_t *) this) + reverseOffsetOfSavedFramePtr();
|
||||
return *(void **)addr;
|
||||
}
|
||||
|
||||
inline ICStub *maybeStubPtr() {
|
||||
uint8_t *fp = reinterpret_cast<uint8_t *>(this);
|
||||
return *reinterpret_cast<ICStub **>(fp + reverseOffsetOfStubPtr());
|
||||
|
|
|
@ -3666,7 +3666,7 @@ class LStart : public LInstructionHelper<0, 0, 0>
|
|||
|
||||
// Passed the BaselineFrame address in the OsrFrameReg by SideCannon().
|
||||
// Forwards this object to the LOsrValues for Value materialization.
|
||||
class LOsrEntry : public LInstructionHelper<1, 0, 0>
|
||||
class LOsrEntry : public LInstructionHelper<1, 0, 1>
|
||||
{
|
||||
protected:
|
||||
Label label_;
|
||||
|
@ -3675,9 +3675,11 @@ class LOsrEntry : public LInstructionHelper<1, 0, 0>
|
|||
public:
|
||||
LIR_HEADER(OsrEntry)
|
||||
|
||||
LOsrEntry()
|
||||
LOsrEntry(const LDefinition &temp)
|
||||
: frameDepth_(0)
|
||||
{ }
|
||||
{
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
void setFrameDepth(uint32_t depth) {
|
||||
frameDepth_ = depth;
|
||||
|
@ -3688,7 +3690,9 @@ class LOsrEntry : public LInstructionHelper<1, 0, 0>
|
|||
Label *label() {
|
||||
return &label_;
|
||||
}
|
||||
|
||||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Materialize a Value stored in an interpreter frame for OSR.
|
||||
|
|
|
@ -1633,7 +1633,7 @@ LIRGenerator::visitLimitedTruncate(MLimitedTruncate *nop)
|
|||
void
|
||||
LIRGenerator::visitOsrEntry(MOsrEntry *entry)
|
||||
{
|
||||
LOsrEntry *lir = new(alloc()) LOsrEntry;
|
||||
LOsrEntry *lir = new(alloc()) LOsrEntry(temp());
|
||||
defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
|
||||
}
|
||||
|
||||
|
|
|
@ -83,14 +83,8 @@ class MIRGenerator
|
|||
return instrumentedProfiling_;
|
||||
}
|
||||
|
||||
bool isNativeToBytecodeMapEnabled() {
|
||||
if (compilingAsmJS())
|
||||
return false;
|
||||
#ifdef DEBUG
|
||||
return true;
|
||||
#else
|
||||
return instrumentedProfiling();
|
||||
#endif
|
||||
bool isProfilerInstrumentationEnabled() {
|
||||
return !compilingAsmJS() && instrumentedProfiling();
|
||||
}
|
||||
|
||||
// Whether the main thread is trying to cancel this build.
|
||||
|
|
|
@ -47,6 +47,11 @@ CodeGeneratorARM::generatePrologue()
|
|||
#ifdef JS_USE_LINK_REGISTER
|
||||
masm.pushReturnAddress();
|
||||
#endif
|
||||
|
||||
// If profiling, save the current frame pointer to a per-thread global field.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerEnterFrame(StackPointer, CallTempReg0);
|
||||
|
||||
// Note that this automatically sets MacroAssembler::framePushed().
|
||||
masm.reserveStack(frameSize());
|
||||
masm.checkStackAlignment();
|
||||
|
@ -66,6 +71,12 @@ CodeGeneratorARM::generateEpilogue()
|
|||
|
||||
masm.freeStack(frameSize());
|
||||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
// If profiling, reset the per-thread global lastJitFrame to point to
|
||||
// the previous frame.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerExitFrame();
|
||||
|
||||
masm.pop(pc);
|
||||
masm.flushBuffer();
|
||||
return true;
|
||||
|
|
|
@ -4294,6 +4294,18 @@ MacroAssemblerARMCompat::handleFailureWithHandlerTail(void *handler)
|
|||
loadValue(Address(r11, BaselineFrame::reverseOffsetOfReturnValue()), JSReturnOperand);
|
||||
ma_mov(r11, sp);
|
||||
pop(r11);
|
||||
|
||||
// If profiling is enabled, then update the lastProfilingFrame to refer to caller
|
||||
// frame before returning.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
// Test if profiler enabled.
|
||||
AbsoluteAddress addressOfEnabled(GetJitContext()->runtime->spsProfiler().addressOfEnabled());
|
||||
branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
profilerExitFrame();
|
||||
bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
ret();
|
||||
|
||||
// If we are bailing out to baseline to handle an exception, jump to the
|
||||
|
|
|
@ -283,6 +283,19 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
|
||||
masm.branchIfFalseBool(ReturnReg, &error);
|
||||
|
||||
// If OSR-ing, then emit instrumentation for setting lastProfilerFrame
|
||||
// if profiler instrumentation is enabled.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
Register realFramePtr = numStackValues;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0),
|
||||
&skipProfilingInstrumentation);
|
||||
masm.ma_add(framePtr, Imm32(sizeof(void*)), realFramePtr);
|
||||
masm.profilerEnterFrame(realFramePtr, scratch);
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.jump(jitcode);
|
||||
|
||||
// OOM: Load error value, discard return address and previous frame
|
||||
|
@ -949,6 +962,17 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx)
|
|||
JSReturnOperand);
|
||||
masm.mov(r11, sp);
|
||||
masm.pop(r11);
|
||||
|
||||
// Before returning, if profiling is turned on, make sure that lastProfilingFrame
|
||||
// is set to the correct caller frame.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
masm.profilerExitFrame();
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
|
|
|
@ -45,6 +45,10 @@ CodeGeneratorMIPS::generatePrologue()
|
|||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
MOZ_ASSERT(!gen->compilingAsmJS());
|
||||
|
||||
// If profiling, save the current frame pointer to a per-thread global field.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerEnterFrame(StackPointer, CallTempReg0);
|
||||
|
||||
// Note that this automatically sets MacroAssembler::framePushed().
|
||||
masm.reserveStack(frameSize());
|
||||
masm.checkStackAlignment();
|
||||
|
@ -64,6 +68,12 @@ CodeGeneratorMIPS::generateEpilogue()
|
|||
|
||||
masm.freeStack(frameSize());
|
||||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
// If profiling, reset the per-thread global lastJitFrame to point to
|
||||
// the previous frame.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerExitFrame();
|
||||
|
||||
masm.ret();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3604,6 +3604,18 @@ MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void *handler)
|
|||
JSReturnOperand);
|
||||
ma_move(StackPointer, BaselineFrameReg);
|
||||
pop(BaselineFrameReg);
|
||||
|
||||
// If profiling is enabled, then update the lastProfilingFrame to refer to caller
|
||||
// frame before returning.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
// Test if profiler enabled.
|
||||
AbsoluteAddress addressOfEnabled(GetJitContext()->runtime->spsProfiler().addressOfEnabled());
|
||||
branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
profilerExitFrame();
|
||||
bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
ret();
|
||||
|
||||
// If we are bailing out to baseline to handle an exception, jump to
|
||||
|
|
|
@ -209,10 +209,13 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
Register numStackValues = regs.takeAny();
|
||||
masm.load32(slotNumStackValues, numStackValues);
|
||||
|
||||
// Push return address, previous frame pointer.
|
||||
masm.subPtr(Imm32(2 * sizeof(uintptr_t)), StackPointer);
|
||||
// Push return address.
|
||||
masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
|
||||
masm.ma_li(scratch, returnLabel.dest());
|
||||
masm.storePtr(scratch, Address(StackPointer, sizeof(uintptr_t)));
|
||||
masm.storePtr(scratch, Address(StackPointer, 0));
|
||||
|
||||
// Push previous frame pointer.
|
||||
masm.subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
|
||||
masm.storePtr(BaselineFrameReg, Address(StackPointer, 0));
|
||||
|
||||
// Reserve frame.
|
||||
|
@ -261,6 +264,19 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
|
||||
masm.branchIfFalseBool(ReturnReg, &error);
|
||||
|
||||
// If OSR-ing, then emit instrumentation for setting lastProfilerFrame
|
||||
// if profiler instrumentation is enabled.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
Register realFramePtr = numStackValues;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0),
|
||||
&skipProfilingInstrumentation);
|
||||
masm.ma_add(realFramePtr, StackPointer, Imm32(sizeof(void*)));
|
||||
masm.profilerEnterFrame(realFramePtr, scratch);
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.jump(jitcode);
|
||||
|
||||
// OOM: load error value, discard return address and previous frame
|
||||
|
@ -952,6 +968,17 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx)
|
|||
JSReturnOperand);
|
||||
masm.movePtr(s5, StackPointer);
|
||||
masm.pop(s5);
|
||||
|
||||
// Before returning, if profiling is turned on, make sure that lastProfilingFrame
|
||||
// is set to the correct caller frame.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
masm.profilerExitFrame();
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
|
|
|
@ -31,6 +31,8 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, TempAllocator &all
|
|||
pushedBeforeCall_(0),
|
||||
inCall_(false),
|
||||
spsPushToggleOffset_(),
|
||||
profilerEnterFrameToggleOffset_(),
|
||||
profilerExitFrameToggleOffset_(),
|
||||
traceLoggerEnterToggleOffset_(),
|
||||
traceLoggerExitToggleOffset_(),
|
||||
traceLoggerScriptTextIdOffset_()
|
||||
|
|
|
@ -68,6 +68,8 @@ class BaselineCompilerShared
|
|||
mozilla::DebugOnly<bool> inCall_;
|
||||
|
||||
CodeOffsetLabel spsPushToggleOffset_;
|
||||
CodeOffsetLabel profilerEnterFrameToggleOffset_;
|
||||
CodeOffsetLabel profilerExitFrameToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerEnterToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerExitToggleOffset_;
|
||||
CodeOffsetLabel traceLoggerScriptTextIdOffset_;
|
||||
|
|
|
@ -158,7 +158,7 @@ bool
|
|||
CodeGeneratorShared::addNativeToBytecodeEntry(const BytecodeSite *site)
|
||||
{
|
||||
// Skip the table entirely if profiling is not enabled.
|
||||
if (!isNativeToBytecodeMapEnabled())
|
||||
if (!isProfilerInstrumentationEnabled())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(site);
|
||||
|
|
|
@ -118,8 +118,8 @@ class CodeGeneratorShared : public LElementVisitor
|
|||
// scripts) and when instrumentation needs to be emitted or skipped.
|
||||
IonInstrumentation sps_;
|
||||
|
||||
bool isNativeToBytecodeMapEnabled() {
|
||||
return gen->isNativeToBytecodeMapEnabled();
|
||||
bool isProfilerInstrumentationEnabled() {
|
||||
return gen->isProfilerInstrumentationEnabled();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -44,6 +44,10 @@ CodeGeneratorX86Shared::generatePrologue()
|
|||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
MOZ_ASSERT(!gen->compilingAsmJS());
|
||||
|
||||
// If profiling, save the current frame pointer to a per-thread global field.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerEnterFrame(StackPointer, CallTempReg0);
|
||||
|
||||
// Note that this automatically sets MacroAssembler::framePushed().
|
||||
masm.reserveStack(frameSize());
|
||||
|
||||
|
@ -65,6 +69,11 @@ CodeGeneratorX86Shared::generateEpilogue()
|
|||
masm.freeStack(frameSize());
|
||||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
// If profiling, reset the per-thread global lastJitFrame to point to
|
||||
// the previous frame.
|
||||
if (isProfilerInstrumentationEnabled())
|
||||
masm.profilerExitFrame();
|
||||
|
||||
masm.ret();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -441,6 +441,17 @@ MacroAssemblerX64::handleFailureWithHandlerTail(void *handler)
|
|||
loadValue(Address(rbp, BaselineFrame::reverseOffsetOfReturnValue()), JSReturnOperand);
|
||||
movq(rbp, rsp);
|
||||
pop(rbp);
|
||||
|
||||
// If profiling is enabled, then update the lastProfilingFrame to refer to caller
|
||||
// frame before returning.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
AbsoluteAddress addressOfEnabled(GetJitContext()->runtime->spsProfiler().addressOfEnabled());
|
||||
branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
profilerExitFrame();
|
||||
bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
ret();
|
||||
|
||||
// If we are bailing out to baseline to handle an exception, jump to
|
||||
|
|
|
@ -165,9 +165,11 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
Register numStackValues = regs.takeAny();
|
||||
masm.movq(numStackValuesAddr, numStackValues);
|
||||
|
||||
// Push return address, previous frame pointer.
|
||||
// Push return address
|
||||
masm.mov(returnLabel.dest(), scratch);
|
||||
masm.push(scratch);
|
||||
|
||||
// Push previous frame pointer.
|
||||
masm.push(rbp);
|
||||
|
||||
// Reserve frame.
|
||||
|
@ -231,6 +233,19 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
|
||||
masm.branchIfFalseBool(ReturnReg, &error);
|
||||
|
||||
// If OSR-ing, then emit instrumentation for setting lastProfilerFrame
|
||||
// if profiler instrumentation is enabled.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
Register realFramePtr = numStackValues;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0),
|
||||
&skipProfilingInstrumentation);
|
||||
masm.lea(Operand(framePtr, sizeof(void*)), realFramePtr);
|
||||
masm.profilerEnterFrame(realFramePtr, scratch);
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.jump(reg_code);
|
||||
|
||||
// OOM: load error value, discard return address and previous frame
|
||||
|
@ -775,6 +790,17 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx)
|
|||
JSReturnOperand);
|
||||
masm.mov(rbp, rsp);
|
||||
masm.pop(rbp);
|
||||
|
||||
// Before returning, if profiling is turned on, make sure that lastProfilingFrame
|
||||
// is set to the correct caller frame.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
masm.profilerExitFrame();
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
|
|
|
@ -421,6 +421,18 @@ MacroAssemblerX86::handleFailureWithHandlerTail(void *handler)
|
|||
loadValue(Address(ebp, BaselineFrame::reverseOffsetOfReturnValue()), JSReturnOperand);
|
||||
movl(ebp, esp);
|
||||
pop(ebp);
|
||||
|
||||
// If profiling is enabled, then update the lastProfilingFrame to refer to caller
|
||||
// frame before returning.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
// Test if profiler enabled.
|
||||
AbsoluteAddress addressOfEnabled(GetJitContext()->runtime->spsProfiler().addressOfEnabled());
|
||||
branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
profilerExitFrame();
|
||||
bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
ret();
|
||||
|
||||
// If we are bailing out to baseline to handle an exception, jump to
|
||||
|
|
|
@ -159,9 +159,11 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
Register jitcode = regs.takeAny();
|
||||
masm.loadPtr(Address(ebp, ARG_JITCODE), jitcode);
|
||||
|
||||
// Push return address, previous frame pointer.
|
||||
// Push return address.
|
||||
masm.mov(returnLabel.dest(), scratch);
|
||||
masm.push(scratch);
|
||||
|
||||
// Push previous frame pointer.
|
||||
masm.push(ebp);
|
||||
|
||||
// Reserve frame.
|
||||
|
@ -222,6 +224,19 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
|
||||
masm.branchIfFalseBool(ReturnReg, &error);
|
||||
|
||||
// If OSR-ing, then emit instrumentation for setting lastProfilerFrame
|
||||
// if profiler instrumentation is enabled.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
Register realFramePtr = numStackValues;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0),
|
||||
&skipProfilingInstrumentation);
|
||||
masm.lea(Operand(framePtr, sizeof(void*)), realFramePtr);
|
||||
masm.profilerEnterFrame(realFramePtr, scratch);
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.jump(jitcode);
|
||||
|
||||
// OOM: load error value, discard return address and previous frame
|
||||
|
@ -813,6 +828,17 @@ JitRuntime::generateDebugTrapHandler(JSContext *cx)
|
|||
JSReturnOperand);
|
||||
masm.mov(ebp, esp);
|
||||
masm.pop(ebp);
|
||||
|
||||
// Before returning, if profiling is turned on, make sure that lastProfilingFrame
|
||||
// is set to the correct caller frame.
|
||||
{
|
||||
Label skipProfilingInstrumentation;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
|
||||
masm.profilerExitFrame();
|
||||
masm.bind(&skipProfilingInstrumentation);
|
||||
}
|
||||
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
|
|
|
@ -594,6 +594,9 @@ class PerThreadData : public PerThreadDataFriendFields
|
|||
js::Activation *profilingActivation() const {
|
||||
return profilingActivation_;
|
||||
}
|
||||
void *addressOfProfilingActivation() {
|
||||
return (void*) &profilingActivation_;
|
||||
}
|
||||
|
||||
js::AsmJSActivation *asmJSActivationStack() const {
|
||||
return asmJSActivationStack_;
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include "jsprf.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jit/BaselineFrame.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -92,6 +94,14 @@ SPSProfiler::enable(bool enabled)
|
|||
* their profiler state toggled so they behave properly.
|
||||
*/
|
||||
jit::ToggleBaselineSPS(rt, enabled);
|
||||
|
||||
/* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
|
||||
* stack.
|
||||
*/
|
||||
if (rt->mainThread.jitActivation) {
|
||||
void *lastProfilingFrame = GetTopProfilingJitFrame(rt->mainThread.jitTop);
|
||||
rt->mainThread.jitActivation->setLastProfilingFrame(lastProfilingFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lookup the string for the function/script, creating one if necessary */
|
||||
|
@ -402,3 +412,36 @@ AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
|
|||
if (previouslyEnabled_)
|
||||
rt_->enableProfilerSampling();
|
||||
}
|
||||
|
||||
void *
|
||||
js::GetTopProfilingJitFrame(uint8_t *exitFramePtr)
|
||||
{
|
||||
// For null exitFrame, there is no previous exit frame, just return.
|
||||
if (!exitFramePtr)
|
||||
return nullptr;
|
||||
|
||||
jit::ExitFrameLayout *exitFrame = (jit::ExitFrameLayout *) exitFramePtr;
|
||||
size_t prevSize = exitFrame->prevFrameLocalSize();
|
||||
jit::FrameType prevType = exitFrame->prevType();
|
||||
|
||||
uint8_t *prev = exitFramePtr + (jit::ExitFrameLayout::Size() + prevSize);
|
||||
|
||||
// previous frame type must be one of IonJS, BaselineJS, or BaselineStub,
|
||||
// or unwound variants thereof.
|
||||
switch (prevType) {
|
||||
case jit::JitFrame_IonJS:
|
||||
case jit::JitFrame_Unwound_IonJS:
|
||||
case jit::JitFrame_BaselineJS:
|
||||
return prev;
|
||||
|
||||
case jit::JitFrame_BaselineStub:
|
||||
case jit::JitFrame_Unwound_BaselineStub: {
|
||||
void *framePtr = ((jit::BaselineStubFrameLayout *) prev)->reverseSavedFramePtr();
|
||||
return ((uint8_t *) framePtr) + jit::BaselineFrame::FramePointerOffset;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("unknown callee token type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -513,6 +513,10 @@ class SPSInstrumentation
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/* Get a pointer to the top-most profiling frame, given the exit frame pointer. */
|
||||
void *GetTopProfilingJitFrame(uint8_t *exitFramePtr);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_SPSProfiler_h */
|
||||
|
|
Загрузка…
Ссылка в новой задаче