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:
Jan de Mooij 2019-06-21 16:13:48 +00:00
Родитель 6dc75498cf
Коммит a261b8dc01
15 изменённых файлов: 269 добавлений и 33 удалений

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

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