Bug 1057082 - 3/7 - Modify jits to use lastProfilingFrame and lastProfilingCallSite fields. r=jandem

This commit is contained in:
Kannan Vijayan 2015-01-15 20:11:21 -05:00
Родитель b3b9045b11
Коммит 45cbaa636c
33 изменённых файлов: 486 добавлений и 41 удалений

Просмотреть файл

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