зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1551499 - Support Baseline Interpreter code in the profiler. r=djvj
Because the return address cannot be used to uniquely identify script/pc, this is unfortunately quite different from what we do for Baseline/Ion code. The strategy is as follows: * When the profiler is enabled, ensure each JitScript has a pointer to the profile string (released when the script is finalized). * The BaselineInterpreter code is registered with the JitcodeMap. * The profiler code treats interpreter frames like C++ Interpreter frames, instead of doing the return address based mapping. Differential Revision: https://phabricator.services.mozilla.com/D31052 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
6dc75498cf
Коммит
a261b8dc01
|
@ -105,15 +105,34 @@ class MOZ_NON_PARAM JS_PUBLIC_API ProfilingFrameIterator {
|
|||
// and less than older native and psuedo-stack frame addresses
|
||||
void* stackAddress() const;
|
||||
|
||||
enum FrameKind { Frame_Baseline, Frame_Ion, Frame_Wasm };
|
||||
enum FrameKind {
|
||||
Frame_BaselineInterpreter,
|
||||
Frame_Baseline,
|
||||
Frame_Ion,
|
||||
Frame_Wasm
|
||||
};
|
||||
|
||||
struct Frame {
|
||||
FrameKind kind;
|
||||
void* stackAddress;
|
||||
void* returnAddress;
|
||||
union {
|
||||
void* returnAddress_;
|
||||
jsbytecode* interpreterPC_;
|
||||
};
|
||||
void* activation;
|
||||
void* endStackAddress;
|
||||
const char* label;
|
||||
JSScript* interpreterScript;
|
||||
|
||||
public:
|
||||
void* returnAddress() const {
|
||||
MOZ_ASSERT(kind != Frame_BaselineInterpreter);
|
||||
return returnAddress_;
|
||||
}
|
||||
jsbytecode* interpreterPC() const {
|
||||
MOZ_ASSERT(kind == Frame_BaselineInterpreter);
|
||||
return interpreterPC_;
|
||||
}
|
||||
} JS_HAZ_GC_INVALIDATED;
|
||||
|
||||
bool isWasm() const;
|
||||
|
|
|
@ -2586,8 +2586,11 @@ static bool ReadGeckoProfilingStack(JSContext* cx, unsigned argc, Value* vp) {
|
|||
for (uint32_t i = 0; i < nframes; i++) {
|
||||
const char* frameKindStr = nullptr;
|
||||
switch (frames[i].kind) {
|
||||
case JS::ProfilingFrameIterator::Frame_BaselineInterpreter:
|
||||
frameKindStr = "baseline-interpreter";
|
||||
break;
|
||||
case JS::ProfilingFrameIterator::Frame_Baseline:
|
||||
frameKindStr = "baseline";
|
||||
frameKindStr = "baseline-jit";
|
||||
break;
|
||||
case JS::ProfilingFrameIterator::Frame_Ion:
|
||||
frameKindStr = "ion";
|
||||
|
|
|
@ -6923,6 +6923,21 @@ bool BaselineInterpreterGenerator::generate(BaselineInterpreter& interpreter) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Register BaselineInterpreter code with the profiler's JitCode table.
|
||||
{
|
||||
JitcodeGlobalEntry::BaselineInterpreterEntry entry;
|
||||
entry.init(code, code->raw(), code->rawEnd());
|
||||
|
||||
JitcodeGlobalTable* globalTable =
|
||||
cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
|
||||
if (!globalTable->addEntry(entry)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
code->setHasBytecodeMap();
|
||||
}
|
||||
|
||||
// Patch loads now that we know the tableswitch base address.
|
||||
for (CodeOffset off : tableLabels_) {
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, off),
|
||||
|
@ -6945,6 +6960,10 @@ bool BaselineInterpreterGenerator::generate(BaselineInterpreter& interpreter) {
|
|||
std::move(handler.codeCoverageOffsets()));
|
||||
}
|
||||
|
||||
if (cx->runtime()->geckoProfiler().enabled()) {
|
||||
interpreter.toggleProfilerInstrumentation(true);
|
||||
}
|
||||
|
||||
if (coverage::IsLCovEnabled()) {
|
||||
interpreter.toggleCodeCoverageInstrumentationUnchecked(true);
|
||||
}
|
||||
|
|
|
@ -1049,17 +1049,22 @@ void jit::AddSizeOfBaselineData(JSScript* script,
|
|||
}
|
||||
}
|
||||
|
||||
void jit::ToggleBaselineProfiling(JSRuntime* runtime, bool enable) {
|
||||
JitRuntime* jrt = runtime->jitRuntime();
|
||||
void jit::ToggleBaselineProfiling(JSContext* cx, bool enable) {
|
||||
JitRuntime* jrt = cx->runtime()->jitRuntime();
|
||||
if (!jrt) {
|
||||
return;
|
||||
}
|
||||
|
||||
jrt->baselineInterpreter().toggleProfilerInstrumentation(enable);
|
||||
|
||||
for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (auto script = zone->cellIter<JSScript>(); !script.done();
|
||||
script.next()) {
|
||||
if (enable) {
|
||||
if (JitScript* jitScript = script->jitScript()) {
|
||||
jitScript->ensureProfileString(cx, script);
|
||||
}
|
||||
}
|
||||
if (!script->hasBaselineScript()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -557,7 +557,7 @@ void FinishDiscardBaselineScript(FreeOp* fop, JSScript* script);
|
|||
void AddSizeOfBaselineData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t* data);
|
||||
|
||||
void ToggleBaselineProfiling(JSRuntime* runtime, bool enable);
|
||||
void ToggleBaselineProfiling(JSContext* cx, bool enable);
|
||||
|
||||
void ToggleBaselineTraceLoggerScripts(JSRuntime* runtime, bool enable);
|
||||
void ToggleBaselineTraceLoggerEngine(JSRuntime* runtime, bool enable);
|
||||
|
|
|
@ -36,12 +36,12 @@ inline size_t JSJitFrameIter::prevFrameLocalSize() const {
|
|||
return current->prevFrameLocalSize();
|
||||
}
|
||||
|
||||
inline JitFrameLayout* JSJitProfilingFrameIterator::framePtr() {
|
||||
inline JitFrameLayout* JSJitProfilingFrameIterator::framePtr() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return (JitFrameLayout*)fp_;
|
||||
}
|
||||
|
||||
inline JSScript* JSJitProfilingFrameIterator::frameScript() {
|
||||
inline JSScript* JSJitProfilingFrameIterator::frameScript() const {
|
||||
return ScriptFromCalleeToken(framePtr()->calleeToken());
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "jit/BaselineIC.h"
|
||||
#include "jit/JitcodeMap.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "jit/JitScript.h"
|
||||
#include "jit/Safepoints.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -509,12 +510,16 @@ JSJitProfilingFrameIterator::JSJitProfilingFrameIterator(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(frameScript()->hasBaselineScript());
|
||||
|
||||
// If nothing matches, for now just assume we are at the start of the last
|
||||
// frame's baseline jit code.
|
||||
// frame's baseline jit code or interpreter code.
|
||||
type_ = FrameType::BaselineJS;
|
||||
resumePCinCurrentFrame_ = frameScript()->baselineScript()->method()->raw();
|
||||
if (frameScript()->hasBaselineScript()) {
|
||||
resumePCinCurrentFrame_ = frameScript()->baselineScript()->method()->raw();
|
||||
} else {
|
||||
MOZ_ASSERT(JitOptions.baselineInterpreter);
|
||||
resumePCinCurrentFrame_ =
|
||||
cx->runtime()->jitRuntime()->baselineInterpreter().codeRaw();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReturnType = CommonFrameLayout*>
|
||||
|
@ -565,7 +570,7 @@ bool JSJitProfilingFrameIterator::tryInitWithTable(JitcodeGlobalTable* table,
|
|||
JSScript* callee = frameScript();
|
||||
|
||||
MOZ_ASSERT(entry->isIon() || entry->isBaseline() || entry->isIonCache() ||
|
||||
entry->isDummy());
|
||||
entry->isBaselineInterpreter() || entry->isDummy());
|
||||
|
||||
// Treat dummy lookups as an empty frame sequence.
|
||||
if (entry->isDummy()) {
|
||||
|
@ -599,6 +604,12 @@ bool JSJitProfilingFrameIterator::tryInitWithTable(JitcodeGlobalTable* table,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (entry->isBaselineInterpreter()) {
|
||||
type_ = FrameType::BaselineJS;
|
||||
resumePCinCurrentFrame_ = pc;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry->isIonCache()) {
|
||||
void* ptr = entry->ionCacheEntry().rejoinAddr();
|
||||
const JitcodeGlobalEntry& ionEntry = table->lookupInfallible(ptr);
|
||||
|
@ -631,12 +642,15 @@ void JSJitProfilingFrameIterator::fixBaselineReturnAddress() {
|
|||
// Certain exception handling cases such as debug OSR or resuming a generator
|
||||
// with .throw() will use BaselineFrame::setOverridePc() to indicate the
|
||||
// effective |pc|. We translate the effective-pc into a Baseline code
|
||||
// address.
|
||||
if (jsbytecode* override = bl->maybeOverridePc()) {
|
||||
// address. Don't do this for frames running in the Baseline Interpreter,
|
||||
// because we don't use the return address in that case.
|
||||
jsbytecode* overridePC = bl->maybeOverridePc();
|
||||
if (overridePC && !bl->runningInInterpreter()) {
|
||||
PCMappingSlotInfo slotInfo;
|
||||
JSScript* script = bl->script();
|
||||
BaselineScript* blScript = script->baselineScript();
|
||||
resumePCinCurrentFrame_ =
|
||||
script->baselineScript()->nativeCodeForPC(script, override, &slotInfo);
|
||||
blScript->nativeCodeForPC(script, overridePC, &slotInfo);
|
||||
|
||||
// NOTE: The stack may not be synced at this PC. For the purpose of
|
||||
// profiler sampling this is fine.
|
||||
|
@ -644,6 +658,29 @@ void JSJitProfilingFrameIterator::fixBaselineReturnAddress() {
|
|||
}
|
||||
}
|
||||
|
||||
const char* JSJitProfilingFrameIterator::baselineInterpreterLabel() const {
|
||||
MOZ_ASSERT(type_ == FrameType::BaselineJS);
|
||||
return frameScript()->jitScript()->profileString();
|
||||
}
|
||||
|
||||
void JSJitProfilingFrameIterator::baselineInterpreterScriptPC(
|
||||
JSScript** script, jsbytecode** pc) const {
|
||||
MOZ_ASSERT(type_ == FrameType::BaselineJS);
|
||||
BaselineFrame* blFrame =
|
||||
(BaselineFrame*)(fp_ - BaselineFrame::FramePointerOffset -
|
||||
BaselineFrame::Size());
|
||||
*script = frameScript();
|
||||
*pc = (*script)->code();
|
||||
|
||||
if (blFrame->runningInInterpreter() &&
|
||||
blFrame->interpreterScript() == *script) {
|
||||
jsbytecode* interpPC = blFrame->interpreterPC();
|
||||
if ((*script)->containsPC(interpPC)) {
|
||||
*pc = interpPC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JSJitProfilingFrameIterator::operator++() {
|
||||
JitFrameLayout* frame = framePtr();
|
||||
moveToNextFrame(frame);
|
||||
|
|
|
@ -275,8 +275,8 @@ class JSJitProfilingFrameIterator {
|
|||
FrameType type_;
|
||||
void* resumePCinCurrentFrame_;
|
||||
|
||||
inline JitFrameLayout* framePtr();
|
||||
inline JSScript* frameScript();
|
||||
inline JitFrameLayout* framePtr() const;
|
||||
inline JSScript* frameScript() const;
|
||||
MOZ_MUST_USE bool tryInitWithPC(void* pc);
|
||||
MOZ_MUST_USE bool tryInitWithTable(JitcodeGlobalTable* table, void* pc,
|
||||
bool forLastCallSite);
|
||||
|
@ -293,6 +293,9 @@ class JSJitProfilingFrameIterator {
|
|||
void operator++();
|
||||
bool done() const { return fp_ == nullptr; }
|
||||
|
||||
const char* baselineInterpreterLabel() const;
|
||||
void baselineInterpreterScriptPC(JSScript** script, jsbytecode** pc) const;
|
||||
|
||||
void* fp() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return fp_;
|
||||
|
|
|
@ -40,8 +40,10 @@ static size_t NumTypeSets(JSScript* script) {
|
|||
}
|
||||
|
||||
JitScript::JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes)
|
||||
: typeSetOffset_(typeSetOffset),
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes,
|
||||
const char* profileString)
|
||||
: profileString_(profileString),
|
||||
typeSetOffset_(typeSetOffset),
|
||||
bytecodeTypeMapOffset_(bytecodeTypeMapOffset),
|
||||
allocBytes_(allocBytes) {
|
||||
setTypesGeneration(script->zone()->types.generation);
|
||||
|
@ -71,6 +73,15 @@ bool JSScript::createJitScript(JSContext* cx) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Store the profile string in the JitScript if the profiler is enabled.
|
||||
const char* profileString = nullptr;
|
||||
if (cx->runtime()->geckoProfiler().enabled()) {
|
||||
profileString = cx->runtime()->geckoProfiler().profileString(cx, this);
|
||||
if (!profileString) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t numTypeSets = NumTypeSets(this);
|
||||
|
||||
static_assert(sizeof(JitScript) % sizeof(uintptr_t) == 0,
|
||||
|
@ -99,8 +110,9 @@ bool JSScript::createJitScript(JSContext* cx) {
|
|||
uint32_t typeSetOffset = sizeof(JitScript) + numICEntries() * sizeof(ICEntry);
|
||||
uint32_t bytecodeTypeMapOffset =
|
||||
typeSetOffset + numTypeSets * sizeof(StackTypeSet);
|
||||
UniquePtr<JitScript> jitScript(new (raw) JitScript(
|
||||
this, typeSetOffset, bytecodeTypeMapOffset, allocSize.value()));
|
||||
UniquePtr<JitScript> jitScript(
|
||||
new (raw) JitScript(this, typeSetOffset, bytecodeTypeMapOffset,
|
||||
allocSize.value(), profileString));
|
||||
|
||||
// Sanity check the length computations.
|
||||
MOZ_ASSERT(jitScript->numICEntries() == numICEntries());
|
||||
|
@ -173,6 +185,19 @@ void JitScript::trace(JSTracer* trc) {
|
|||
}
|
||||
}
|
||||
|
||||
void JitScript::ensureProfileString(JSContext* cx, JSScript* script) {
|
||||
MOZ_ASSERT(cx->runtime()->geckoProfiler().enabled());
|
||||
|
||||
if (profileString_) {
|
||||
return;
|
||||
}
|
||||
|
||||
profileString_ = cx->runtime()->geckoProfiler().profileString(cx, script);
|
||||
if (!profileString_) {
|
||||
MOZ_CRASH("Failed to allocate profile string");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void JitScript::printTypes(JSContext* cx, HandleScript script) {
|
||||
AutoSweepJitScript sweep(script);
|
||||
|
|
|
@ -105,6 +105,9 @@ class alignas(uintptr_t) JitScript final {
|
|||
// directly to this script.
|
||||
js::UniquePtr<Vector<DependentWasmImport>> dependentWasmImports_;
|
||||
|
||||
// Profile string used by the profiler for Baseline Interpreter frames.
|
||||
const char* profileString_ = nullptr;
|
||||
|
||||
// Offset of the StackTypeSet array.
|
||||
uint32_t typeSetOffset_ = 0;
|
||||
|
||||
|
@ -150,7 +153,8 @@ class alignas(uintptr_t) JitScript final {
|
|||
|
||||
public:
|
||||
JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes);
|
||||
uint32_t bytecodeTypeMapOffset, uint32_t allocBytes,
|
||||
const char* profileString);
|
||||
|
||||
#ifdef DEBUG
|
||||
~JitScript() {
|
||||
|
@ -202,6 +206,13 @@ class alignas(uintptr_t) JitScript final {
|
|||
void setActive() { flags_.active = true; }
|
||||
void resetActive() { flags_.active = false; }
|
||||
|
||||
void ensureProfileString(JSContext* cx, JSScript* script);
|
||||
|
||||
const char* profileString() const {
|
||||
MOZ_ASSERT(profileString_);
|
||||
return profileString_;
|
||||
}
|
||||
|
||||
/* Array of type sets for variables and JOF_TYPESET ops. */
|
||||
StackTypeSet* typeArray(const js::AutoSweepJitScript& sweep) {
|
||||
MOZ_ASSERT(sweep.jitScript() == this);
|
||||
|
|
|
@ -198,6 +198,26 @@ void JitcodeGlobalEntry::BaselineEntry::destroy() {
|
|||
str_ = nullptr;
|
||||
}
|
||||
|
||||
void* JitcodeGlobalEntry::BaselineInterpreterEntry::canonicalNativeAddrFor(
|
||||
void* ptr) const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool JitcodeGlobalEntry::BaselineInterpreterEntry::callStackAtAddr(
|
||||
void* ptr, BytecodeLocationVector& results, uint32_t* depth) const {
|
||||
MOZ_CRASH("shouldn't be called for BaselineInterpreter entries");
|
||||
}
|
||||
|
||||
uint32_t JitcodeGlobalEntry::BaselineInterpreterEntry::callStackAtAddr(
|
||||
void* ptr, const char** results, uint32_t maxResults) const {
|
||||
MOZ_CRASH("shouldn't be called for BaselineInterpreter entries");
|
||||
}
|
||||
|
||||
void JitcodeGlobalEntry::BaselineInterpreterEntry::youngestFrameLocationAtAddr(
|
||||
void* ptr, JSScript** script, jsbytecode** pc) const {
|
||||
MOZ_CRASH("shouldn't be called for BaselineInterpreter entries");
|
||||
}
|
||||
|
||||
static inline JitcodeGlobalEntry& RejoinEntry(
|
||||
JSRuntime* rt, const JitcodeGlobalEntry::IonCacheEntry& cache, void* ptr) {
|
||||
MOZ_ASSERT(cache.containsPointer(ptr));
|
||||
|
@ -367,7 +387,7 @@ JitcodeGlobalEntry* JitcodeGlobalTable::lookupInternal(void* ptr) {
|
|||
|
||||
bool JitcodeGlobalTable::addEntry(const JitcodeGlobalEntry& entry) {
|
||||
MOZ_ASSERT(entry.isIon() || entry.isBaseline() || entry.isIonCache() ||
|
||||
entry.isDummy());
|
||||
entry.isBaselineInterpreter() || entry.isDummy());
|
||||
|
||||
JitcodeGlobalEntry* searchTower[JitcodeSkiplistTower::MAX_HEIGHT];
|
||||
searchInternal(entry, searchTower);
|
||||
|
@ -1523,6 +1543,9 @@ JS::ProfiledFrameHandle::ProfiledFrameHandle(JSRuntime* rt,
|
|||
|
||||
JS_PUBLIC_API JS::ProfilingFrameIterator::FrameKind
|
||||
JS::ProfiledFrameHandle::frameKind() const {
|
||||
if (entry_.isBaselineInterpreter()) {
|
||||
return JS::ProfilingFrameIterator::Frame_BaselineInterpreter;
|
||||
}
|
||||
if (entry_.isBaseline()) {
|
||||
return JS::ProfilingFrameIterator::Frame_Baseline;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,16 @@ class JitcodeGlobalEntry {
|
|||
friend class JitcodeGlobalTable;
|
||||
|
||||
public:
|
||||
enum Kind { INVALID = 0, Ion, Baseline, IonCache, Dummy, Query, LIMIT };
|
||||
enum Kind {
|
||||
INVALID = 0,
|
||||
Ion,
|
||||
Baseline,
|
||||
BaselineInterpreter,
|
||||
IonCache,
|
||||
Dummy,
|
||||
Query,
|
||||
LIMIT
|
||||
};
|
||||
JS_STATIC_ASSERT(LIMIT <= 8);
|
||||
|
||||
struct BytecodeLocation {
|
||||
|
@ -414,6 +423,27 @@ class JitcodeGlobalEntry {
|
|||
bool isMarkedFromAnyThread(JSRuntime* rt);
|
||||
};
|
||||
|
||||
struct BaselineInterpreterEntry : public BaseEntry {
|
||||
void init(JitCode* code, void* nativeStartAddr, void* nativeEndAddr) {
|
||||
BaseEntry::init(BaselineInterpreter, code, nativeStartAddr,
|
||||
nativeEndAddr);
|
||||
}
|
||||
|
||||
void destroy() {}
|
||||
|
||||
void* canonicalNativeAddrFor(void* ptr) const;
|
||||
|
||||
MOZ_MUST_USE bool callStackAtAddr(void* ptr,
|
||||
BytecodeLocationVector& results,
|
||||
uint32_t* depth) const;
|
||||
|
||||
uint32_t callStackAtAddr(void* ptr, const char** results,
|
||||
uint32_t maxResults) const;
|
||||
|
||||
void youngestFrameLocationAtAddr(void* ptr, JSScript** script,
|
||||
jsbytecode** pc) const;
|
||||
};
|
||||
|
||||
struct IonCacheEntry : public BaseEntry {
|
||||
void* rejoinAddr_;
|
||||
JS::TrackedOutcome trackedOutcome_;
|
||||
|
@ -517,6 +547,9 @@ class JitcodeGlobalEntry {
|
|||
// Baseline jitcode.
|
||||
BaselineEntry baseline_;
|
||||
|
||||
// BaselineInterpreter code.
|
||||
BaselineInterpreterEntry baselineInterpreter_;
|
||||
|
||||
// IonCache stubs.
|
||||
IonCacheEntry ionCache_;
|
||||
|
||||
|
@ -540,6 +573,11 @@ class JitcodeGlobalEntry {
|
|||
baseline_ = baseline;
|
||||
}
|
||||
|
||||
explicit JitcodeGlobalEntry(const BaselineInterpreterEntry& baselineInterp)
|
||||
: JitcodeGlobalEntry() {
|
||||
baselineInterpreter_ = baselineInterp;
|
||||
}
|
||||
|
||||
explicit JitcodeGlobalEntry(const IonCacheEntry& ionCache)
|
||||
: JitcodeGlobalEntry() {
|
||||
ionCache_ = ionCache;
|
||||
|
@ -567,6 +605,9 @@ class JitcodeGlobalEntry {
|
|||
case Baseline:
|
||||
baselineEntry().destroy();
|
||||
break;
|
||||
case BaselineInterpreter:
|
||||
baselineInterpreterEntry().destroy();
|
||||
break;
|
||||
case IonCache:
|
||||
ionCacheEntry().destroy();
|
||||
break;
|
||||
|
@ -620,6 +661,7 @@ class JitcodeGlobalEntry {
|
|||
bool isValid() const { return (kind() > INVALID) && (kind() < LIMIT); }
|
||||
bool isIon() const { return kind() == Ion; }
|
||||
bool isBaseline() const { return kind() == Baseline; }
|
||||
bool isBaselineInterpreter() const { return kind() == BaselineInterpreter; }
|
||||
bool isIonCache() const { return kind() == IonCache; }
|
||||
bool isDummy() const { return kind() == Dummy; }
|
||||
bool isQuery() const { return kind() == Query; }
|
||||
|
@ -636,6 +678,10 @@ class JitcodeGlobalEntry {
|
|||
MOZ_ASSERT(isBaseline());
|
||||
return baseline_;
|
||||
}
|
||||
BaselineInterpreterEntry& baselineInterpreterEntry() {
|
||||
MOZ_ASSERT(isBaselineInterpreter());
|
||||
return baselineInterpreter_;
|
||||
}
|
||||
IonCacheEntry& ionCacheEntry() {
|
||||
MOZ_ASSERT(isIonCache());
|
||||
return ionCache_;
|
||||
|
@ -661,6 +707,10 @@ class JitcodeGlobalEntry {
|
|||
MOZ_ASSERT(isBaseline());
|
||||
return baseline_;
|
||||
}
|
||||
const BaselineInterpreterEntry& baselineInterpreterEntry() const {
|
||||
MOZ_ASSERT(isBaselineInterpreter());
|
||||
return baselineInterpreter_;
|
||||
}
|
||||
const IonCacheEntry& ionCacheEntry() const {
|
||||
MOZ_ASSERT(isIonCache());
|
||||
return ionCache_;
|
||||
|
@ -703,6 +753,8 @@ class JitcodeGlobalEntry {
|
|||
return ionEntry().callStackAtAddr(ptr, results, depth);
|
||||
case Baseline:
|
||||
return baselineEntry().callStackAtAddr(ptr, results, depth);
|
||||
case BaselineInterpreter:
|
||||
return baselineInterpreterEntry().callStackAtAddr(ptr, results, depth);
|
||||
case IonCache:
|
||||
return ionCacheEntry().callStackAtAddr(rt, ptr, results, depth);
|
||||
case Dummy:
|
||||
|
@ -720,6 +772,9 @@ class JitcodeGlobalEntry {
|
|||
return ionEntry().callStackAtAddr(ptr, results, maxResults);
|
||||
case Baseline:
|
||||
return baselineEntry().callStackAtAddr(ptr, results, maxResults);
|
||||
case BaselineInterpreter:
|
||||
return baselineInterpreterEntry().callStackAtAddr(ptr, results,
|
||||
maxResults);
|
||||
case IonCache:
|
||||
return ionCacheEntry().callStackAtAddr(rt, ptr, results, maxResults);
|
||||
case Dummy:
|
||||
|
@ -855,6 +910,7 @@ class JitcodeGlobalEntry {
|
|||
case IonCache:
|
||||
tracedAny |= ionCacheEntry().trace<ShouldTraceProvider>(trc);
|
||||
break;
|
||||
case BaselineInterpreter:
|
||||
case Dummy:
|
||||
break;
|
||||
default:
|
||||
|
@ -874,6 +930,7 @@ class JitcodeGlobalEntry {
|
|||
case IonCache:
|
||||
ionCacheEntry().sweepChildren(rt);
|
||||
break;
|
||||
case BaselineInterpreter:
|
||||
case Dummy:
|
||||
break;
|
||||
default:
|
||||
|
@ -982,6 +1039,10 @@ class JitcodeGlobalTable {
|
|||
MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry::BaselineEntry& entry) {
|
||||
return addEntry(JitcodeGlobalEntry(entry));
|
||||
}
|
||||
MOZ_MUST_USE bool addEntry(
|
||||
const JitcodeGlobalEntry::BaselineInterpreterEntry& entry) {
|
||||
return addEntry(JitcodeGlobalEntry(entry));
|
||||
}
|
||||
MOZ_MUST_USE bool addEntry(const JitcodeGlobalEntry::IonCacheEntry& entry) {
|
||||
return addEntry(JitcodeGlobalEntry(entry));
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ void GeckoProfilerRuntime::enable(bool enabled) {
|
|||
* but not jitcode for scripts with active frames on the stack. These scripts
|
||||
* need to have their profiler state toggled so they behave properly.
|
||||
*/
|
||||
jit::ToggleBaselineProfiling(rt, enabled);
|
||||
jit::ToggleBaselineProfiling(cx, enabled);
|
||||
|
||||
// Update lastProfilingFrame to point to the top-most JS jit-frame currently
|
||||
// on stack.
|
||||
|
|
|
@ -1934,10 +1934,11 @@ JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(
|
|||
Frame frame;
|
||||
frame.kind = Frame_Wasm;
|
||||
frame.stackAddress = stackAddr;
|
||||
frame.returnAddress = nullptr;
|
||||
frame.returnAddress_ = nullptr;
|
||||
frame.activation = activation_;
|
||||
frame.label = nullptr;
|
||||
frame.endStackAddress = activation_->asJit()->jsOrWasmExitFP();
|
||||
frame.interpreterScript = nullptr;
|
||||
return mozilla::Some(frame);
|
||||
}
|
||||
|
||||
|
@ -1955,7 +1956,7 @@ JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(
|
|||
}
|
||||
|
||||
MOZ_ASSERT(entry->isIon() || entry->isIonCache() || entry->isBaseline() ||
|
||||
entry->isDummy());
|
||||
entry->isBaselineInterpreter() || entry->isDummy());
|
||||
|
||||
// Dummy frames produce no stack frames.
|
||||
if (entry->isDummy()) {
|
||||
|
@ -1963,11 +1964,26 @@ JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(
|
|||
}
|
||||
|
||||
Frame frame;
|
||||
frame.kind = entry->isBaseline() ? Frame_Baseline : Frame_Ion;
|
||||
if (entry->isBaselineInterpreter()) {
|
||||
frame.kind = Frame_BaselineInterpreter;
|
||||
} else if (entry->isBaseline()) {
|
||||
frame.kind = Frame_Baseline;
|
||||
} else {
|
||||
frame.kind = Frame_Ion;
|
||||
}
|
||||
frame.stackAddress = stackAddr;
|
||||
frame.returnAddress = returnAddr;
|
||||
if (entry->isBaselineInterpreter()) {
|
||||
frame.label = jsJitIter().baselineInterpreterLabel();
|
||||
jsJitIter().baselineInterpreterScriptPC(&frame.interpreterScript,
|
||||
&frame.interpreterPC_);
|
||||
MOZ_ASSERT(frame.interpreterScript);
|
||||
MOZ_ASSERT(frame.interpreterPC_);
|
||||
} else {
|
||||
frame.interpreterScript = nullptr;
|
||||
frame.returnAddress_ = returnAddr;
|
||||
frame.label = nullptr;
|
||||
}
|
||||
frame.activation = activation_;
|
||||
frame.label = nullptr;
|
||||
frame.endStackAddress = activation_->asJit()->jsOrWasmExitFP();
|
||||
return mozilla::Some(frame);
|
||||
}
|
||||
|
@ -1993,6 +2009,11 @@ uint32_t JS::ProfilingFrameIterator::extractStack(Frame* frames,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (physicalFrame->kind == Frame_BaselineInterpreter) {
|
||||
frames[offset] = physicalFrame.value();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Extract the stack for the entry. Assume maximum inlining depth is <64
|
||||
const char* labels[64];
|
||||
uint32_t depth = entry.callStackAtAddr(cx_->runtime(),
|
||||
|
|
|
@ -1302,10 +1302,19 @@ static void MergeStacks(uint32_t aFeatures, bool aIsSynchronous,
|
|||
if (aIsSynchronous ||
|
||||
jsFrame.kind == JS::ProfilingFrameIterator::Frame_Wasm) {
|
||||
aCollector.CollectWasmFrame(jsFrame.label);
|
||||
} else if (jsFrame.kind ==
|
||||
JS::ProfilingFrameIterator::Frame_BaselineInterpreter) {
|
||||
// For now treat this as a C++ Interpreter frame by materializing a
|
||||
// ProfilingStackFrame.
|
||||
JSScript* script = jsFrame.interpreterScript;
|
||||
jsbytecode* pc = jsFrame.interpreterPC();
|
||||
js::ProfilingStackFrame stackFrame;
|
||||
stackFrame.initJsFrame("", jsFrame.label, script, pc);
|
||||
aCollector.CollectProfilingStackFrame(stackFrame);
|
||||
} else {
|
||||
MOZ_ASSERT(jsFrame.kind == JS::ProfilingFrameIterator::Frame_Ion ||
|
||||
jsFrame.kind == JS::ProfilingFrameIterator::Frame_Baseline);
|
||||
aCollector.CollectJitReturnAddr(jsFrame.returnAddress);
|
||||
aCollector.CollectJitReturnAddr(jsFrame.returnAddress());
|
||||
}
|
||||
|
||||
jsIndex--;
|
||||
|
|
Загрузка…
Ссылка в новой задаче