mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
Bug 1384683: Implement an higher-level frame iterator that can handle JS jit and wasm frames interleaving; r=jandem, r=luke
MozReview-Commit-ID: DFJmBBHNSaa --HG-- extra : rebase_source : 62f1625a6c8615118713aa1345b272dccbda49da
This commit is contained in:
parent
ec1a805248
commit
7d316d6f96
@ -31,7 +31,6 @@
|
||||
#include "irregexp/RegExpParser.h"
|
||||
#endif
|
||||
#include "jit/InlinableNatives.h"
|
||||
#include "jit/JitFrameIterator.h"
|
||||
#include "js/Debug.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/StructuredClone.h"
|
||||
|
@ -329,7 +329,6 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
|
||||
// Trace active interpreter and JIT stack roots.
|
||||
TraceInterpreterActivations(cx, target, trc);
|
||||
jit::TraceJitActivations(cx, target, trc);
|
||||
wasm::TraceActivations(cx, target, trc);
|
||||
|
||||
// Trace legacy C stack roots.
|
||||
AutoGCRooter::traceAll(target, trc);
|
||||
|
@ -41,19 +41,19 @@ jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
|
||||
|
||||
JitActivationIterator jitActivations(cx);
|
||||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
JitFrameIterator iter(jitActivations);
|
||||
MOZ_ASSERT(!iter.ionScript()->invalidated());
|
||||
CommonFrameLayout* currentFramePtr = iter.current();
|
||||
JitFrameIterator frame(jitActivations->asJit());
|
||||
MOZ_ASSERT(!frame.ionScript()->invalidated());
|
||||
CommonFrameLayout* currentFramePtr = frame.current();
|
||||
|
||||
TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
|
||||
TraceLogTimestamp(logger, TraceLogger_Bailout);
|
||||
|
||||
JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
|
||||
JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", frame.snapshotOffset());
|
||||
|
||||
MOZ_ASSERT(IsBaselineEnabled(cx));
|
||||
|
||||
*bailoutInfo = nullptr;
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo,
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), frame, false, bailoutInfo,
|
||||
/* excInfo = */ nullptr);
|
||||
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
|
||||
retval == BAILOUT_RETURN_FATAL_ERROR ||
|
||||
@ -61,7 +61,7 @@ jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
|
||||
MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
|
||||
|
||||
if (retval != BAILOUT_RETURN_OK) {
|
||||
JSScript* script = iter.script();
|
||||
JSScript* script = frame.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
/* popProfilerFrame = */ false);
|
||||
}
|
||||
@ -74,8 +74,8 @@ jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
|
||||
// invalidated (see InvalidateActivation), we remove references to it and
|
||||
// increment the reference counter for each activation that appear on the
|
||||
// stack. As the bailed frame is one of them, we have to decrement it now.
|
||||
if (iter.ionScript()->invalidated())
|
||||
iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
if (frame.ionScript()->invalidated())
|
||||
frame.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
|
||||
// NB: Commentary on how |lastProfilingFrame| is set from bailouts.
|
||||
//
|
||||
@ -113,21 +113,22 @@ jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
|
||||
|
||||
JitActivationIterator jitActivations(cx);
|
||||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
JitFrameIterator iter(jitActivations);
|
||||
CommonFrameLayout* currentFramePtr = iter.current();
|
||||
JitFrameIterator frame(jitActivations->asJit());
|
||||
CommonFrameLayout* currentFramePtr = frame.current();
|
||||
|
||||
TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
|
||||
TraceLogTimestamp(logger, TraceLogger_Invalidation);
|
||||
|
||||
JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
|
||||
JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d",
|
||||
frame.snapshotOffset());
|
||||
|
||||
// Note: the frame size must be computed before we return from this function.
|
||||
*frameSizeOut = iter.frameSize();
|
||||
*frameSizeOut = frame.frameSize();
|
||||
|
||||
MOZ_ASSERT(IsBaselineEnabled(cx));
|
||||
|
||||
*bailoutInfo = nullptr;
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo,
|
||||
uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), frame, true, bailoutInfo,
|
||||
/* excInfo = */ nullptr);
|
||||
MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
|
||||
retval == BAILOUT_RETURN_FATAL_ERROR ||
|
||||
@ -146,21 +147,21 @@ jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
|
||||
// However, if the bailout was during argument check, then a
|
||||
// pseudostack frame would not have been pushed in the first
|
||||
// place, so don't pop anything in that case.
|
||||
JSScript* script = iter.script();
|
||||
JSScript* script = frame.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
/* popProfilerFrame = */ false);
|
||||
|
||||
#ifdef JS_JITSPEW
|
||||
JitFrameLayout* frame = iter.jsFrame();
|
||||
JitFrameLayout* layout = frame.jsFrame();
|
||||
JitSpew(JitSpew_IonInvalidate, "Bailout failed (%s)",
|
||||
(retval == BAILOUT_RETURN_FATAL_ERROR) ? "Fatal Error" : "Over Recursion");
|
||||
JitSpew(JitSpew_IonInvalidate, " calleeToken %p", (void*) frame->calleeToken());
|
||||
JitSpew(JitSpew_IonInvalidate, " frameSize %u", unsigned(frame->prevFrameLocalSize()));
|
||||
JitSpew(JitSpew_IonInvalidate, " ra %p", (void*) frame->returnAddress());
|
||||
JitSpew(JitSpew_IonInvalidate, " calleeToken %p", (void*) layout->calleeToken());
|
||||
JitSpew(JitSpew_IonInvalidate, " frameSize %u", unsigned(layout->prevFrameLocalSize()));
|
||||
JitSpew(JitSpew_IonInvalidate, " ra %p", (void*) layout->returnAddress());
|
||||
#endif
|
||||
}
|
||||
|
||||
iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
frame.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
|
||||
// Make the frame being bailed out the top profiled frame.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
|
||||
@ -202,8 +203,8 @@ jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame,
|
||||
|
||||
JitActivationIterator jitActivations(cx);
|
||||
BailoutFrameInfo bailoutData(jitActivations, frame.frame());
|
||||
JitFrameIterator iter(jitActivations);
|
||||
CommonFrameLayout* currentFramePtr = iter.current();
|
||||
JitFrameIterator frameView(jitActivations->asJit());
|
||||
CommonFrameLayout* currentFramePtr = frameView.current();
|
||||
|
||||
BaselineBailoutInfo* bailoutInfo = nullptr;
|
||||
uint32_t retval;
|
||||
@ -213,7 +214,7 @@ jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame,
|
||||
// exception handling code further.
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
|
||||
retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true,
|
||||
retval = BailoutIonToBaseline(cx, bailoutData.activation(), frameView, true,
|
||||
&bailoutInfo, &excInfo);
|
||||
if (retval == BAILOUT_RETURN_FATAL_ERROR && cx->isThrowingOutOfMemory())
|
||||
oomUnsafe.crash("ExceptionHandlerBailout");
|
||||
|
@ -85,7 +85,7 @@ class BufferPointer
|
||||
*/
|
||||
struct BaselineStackBuilder
|
||||
{
|
||||
JitFrameIterator& iter_;
|
||||
const JitFrameIterator& iter_;
|
||||
JitFrameLayout* frame_;
|
||||
|
||||
static size_t HeaderSize() {
|
||||
@ -99,7 +99,7 @@ struct BaselineStackBuilder
|
||||
|
||||
size_t framePushed_;
|
||||
|
||||
BaselineStackBuilder(JitFrameIterator& iter, size_t initialSize)
|
||||
BaselineStackBuilder(const JitFrameIterator& iter, size_t initialSize)
|
||||
: iter_(iter),
|
||||
frame_(static_cast<JitFrameLayout*>(iter.current())),
|
||||
bufferTotal_(initialSize),
|
||||
@ -428,10 +428,10 @@ struct BaselineStackBuilder
|
||||
class SnapshotIteratorForBailout : public SnapshotIterator
|
||||
{
|
||||
JitActivation* activation_;
|
||||
JitFrameIterator& iter_;
|
||||
const JitFrameIterator& iter_;
|
||||
|
||||
public:
|
||||
SnapshotIteratorForBailout(JitActivation* activation, JitFrameIterator& iter)
|
||||
SnapshotIteratorForBailout(JitActivation* activation, const JitFrameIterator& iter)
|
||||
: SnapshotIterator(iter, activation->bailoutData()->machineState()),
|
||||
activation_(activation),
|
||||
iter_(iter)
|
||||
@ -1493,8 +1493,9 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
||||
}
|
||||
|
||||
uint32_t
|
||||
jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIterator& iter,
|
||||
bool invalidate, BaselineBailoutInfo** bailoutInfo,
|
||||
jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation,
|
||||
const JitFrameIterator& iter, bool invalidate,
|
||||
BaselineBailoutInfo** bailoutInfo,
|
||||
const ExceptionBailoutInfo* excInfo)
|
||||
{
|
||||
MOZ_ASSERT(bailoutInfo != nullptr);
|
||||
|
@ -188,37 +188,38 @@ CollectJitStackScripts(JSContext* cx, const Debugger::ExecutionObservableSet& ob
|
||||
{
|
||||
ICStub* prevFrameStubPtr = nullptr;
|
||||
bool needsRecompileHandler = false;
|
||||
for (JitFrameIterator iter(activation); !iter.done(); ++iter) {
|
||||
switch (iter.type()) {
|
||||
for (OnlyJSJitFrameIter iter(activation); !iter.done(); ++iter) {
|
||||
const JitFrameIterator& frame = iter.frame();
|
||||
switch (frame.type()) {
|
||||
case JitFrame_BaselineJS: {
|
||||
JSScript* script = iter.script();
|
||||
JSScript* script = frame.script();
|
||||
|
||||
if (!obs.shouldRecompileOrInvalidate(script)) {
|
||||
prevFrameStubPtr = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
BaselineFrame* frame = iter.baselineFrame();
|
||||
BaselineFrame* baselineFrame = frame.baselineFrame();
|
||||
|
||||
if (BaselineDebugModeOSRInfo* info = frame->getDebugModeOSRInfo()) {
|
||||
if (BaselineDebugModeOSRInfo* info = baselineFrame->getDebugModeOSRInfo()) {
|
||||
// If patching a previously patched yet unpopped frame, we can
|
||||
// use the BaselineDebugModeOSRInfo on the frame directly to
|
||||
// patch. Indeed, we cannot use iter.returnAddressToFp(), as
|
||||
// patch. Indeed, we cannot use frame.returnAddressToFp(), as
|
||||
// it points into the debug mode OSR handler and cannot be
|
||||
// used to look up a corresponding ICEntry.
|
||||
//
|
||||
// See cases F and G in PatchBaselineFramesForDebugMode.
|
||||
if (!entries.append(DebugModeOSREntry(script, info)))
|
||||
return false;
|
||||
} else if (frame->isHandlingException()) {
|
||||
} else if (baselineFrame->isHandlingException()) {
|
||||
// We are in the middle of handling an exception and the frame
|
||||
// must have an override pc.
|
||||
uint32_t offset = script->pcToOffset(frame->overridePc());
|
||||
uint32_t offset = script->pcToOffset(baselineFrame->overridePc());
|
||||
if (!entries.append(DebugModeOSREntry(script, offset)))
|
||||
return false;
|
||||
} else {
|
||||
// The frame must be settled on a pc with an ICEntry.
|
||||
uint8_t* retAddr = iter.returnAddressToFp();
|
||||
uint8_t* retAddr = frame.returnAddressToFp();
|
||||
BaselineICEntry& icEntry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
|
||||
if (!entries.append(DebugModeOSREntry(script, icEntry)))
|
||||
return false;
|
||||
@ -237,11 +238,11 @@ CollectJitStackScripts(JSContext* cx, const Debugger::ExecutionObservableSet& ob
|
||||
|
||||
case JitFrame_BaselineStub:
|
||||
prevFrameStubPtr =
|
||||
reinterpret_cast<BaselineStubFrameLayout*>(iter.fp())->maybeStubPtr();
|
||||
reinterpret_cast<BaselineStubFrameLayout*>(frame.fp())->maybeStubPtr();
|
||||
break;
|
||||
|
||||
case JitFrame_IonJS: {
|
||||
InlineFrameIterator inlineIter(cx, &iter);
|
||||
InlineFrameIterator inlineIter(cx, &frame);
|
||||
while (true) {
|
||||
if (obs.shouldRecompileOrInvalidate(inlineIter.script())) {
|
||||
if (!entries.append(DebugModeOSREntry(inlineIter.script())))
|
||||
@ -383,12 +384,13 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
CommonFrameLayout* prev = nullptr;
|
||||
size_t entryIndex = *start;
|
||||
|
||||
for (JitFrameIterator iter(activation); !iter.done(); ++iter) {
|
||||
switch (iter.type()) {
|
||||
for (OnlyJSJitFrameIter iter(activation); !iter.done(); ++iter) {
|
||||
const JitFrameIterator& frame = iter.frame();
|
||||
switch (frame.type()) {
|
||||
case JitFrame_BaselineJS: {
|
||||
// If the script wasn't recompiled or is not observed, there's
|
||||
// nothing to patch.
|
||||
if (!obs.shouldRecompileOrInvalidate(iter.script()))
|
||||
if (!obs.shouldRecompileOrInvalidate(frame.script()))
|
||||
break;
|
||||
|
||||
DebugModeOSREntry& entry = entries[entryIndex];
|
||||
@ -402,7 +404,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
uint32_t pcOffset = entry.pcOffset;
|
||||
jsbytecode* pc = script->offsetToPC(pcOffset);
|
||||
|
||||
MOZ_ASSERT(script == iter.script());
|
||||
MOZ_ASSERT(script == frame.script());
|
||||
MOZ_ASSERT(pcOffset < script->length());
|
||||
|
||||
BaselineScript* bl = script->baselineScript();
|
||||
@ -420,7 +422,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
// directly to the IC resume address.
|
||||
uint8_t* retAddr = bl->returnAddressForIC(bl->icEntryFromPCOffset(pcOffset));
|
||||
SpewPatchBaselineFrame(prev->returnAddress(), retAddr, script, kind, pc);
|
||||
DebugModeOSRVolatileJitFrameIterator::forwardLiveIterators(
|
||||
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(
|
||||
target, prev->returnAddress(), retAddr);
|
||||
prev->setReturnAddress(retAddr);
|
||||
entryIndex++;
|
||||
@ -440,8 +442,8 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
//
|
||||
// If profiling is on, JitProfilingFrameIterator requires a
|
||||
// valid return address.
|
||||
MOZ_ASSERT(iter.baselineFrame()->isHandlingException());
|
||||
MOZ_ASSERT(iter.baselineFrame()->overridePc() == pc);
|
||||
MOZ_ASSERT(frame.baselineFrame()->isHandlingException());
|
||||
MOZ_ASSERT(frame.baselineFrame()->overridePc() == pc);
|
||||
uint8_t* retAddr;
|
||||
if (cx->runtime()->geckoProfiler().enabled())
|
||||
retAddr = bl->nativeCodeForPC(script, pc);
|
||||
@ -449,7 +451,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
retAddr = nullptr;
|
||||
SpewPatchBaselineFrameFromExceptionHandler(prev->returnAddress(), retAddr,
|
||||
script, pc);
|
||||
DebugModeOSRVolatileJitFrameIterator::forwardLiveIterators(
|
||||
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(
|
||||
target, prev->returnAddress(), retAddr);
|
||||
prev->setReturnAddress(retAddr);
|
||||
entryIndex++;
|
||||
@ -461,7 +463,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
// We undo a previous recompile by handling cases B, C, D, E, I or J
|
||||
// like normal, except that we retrieve the pc information via
|
||||
// the previous OSR debug info stashed on the frame.
|
||||
BaselineDebugModeOSRInfo* info = iter.baselineFrame()->getDebugModeOSRInfo();
|
||||
BaselineDebugModeOSRInfo* info = frame.baselineFrame()->getDebugModeOSRInfo();
|
||||
if (info) {
|
||||
MOZ_ASSERT(info->pc == pc);
|
||||
MOZ_ASSERT(info->frameKind == kind);
|
||||
@ -475,7 +477,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
|
||||
// We will have allocated a new recompile info, so delete the
|
||||
// existing one.
|
||||
iter.baselineFrame()->deleteDebugModeOSRInfo();
|
||||
frame.baselineFrame()->deleteDebugModeOSRInfo();
|
||||
}
|
||||
|
||||
// The RecompileInfo must already be allocated so that this
|
||||
@ -568,15 +570,15 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
MOZ_ASSERT(handlerAddr);
|
||||
|
||||
prev->setReturnAddress(reinterpret_cast<uint8_t*>(handlerAddr));
|
||||
iter.baselineFrame()->setDebugModeOSRInfo(recompInfo);
|
||||
iter.baselineFrame()->setOverridePc(recompInfo->pc);
|
||||
frame.baselineFrame()->setDebugModeOSRInfo(recompInfo);
|
||||
frame.baselineFrame()->setOverridePc(recompInfo->pc);
|
||||
|
||||
entryIndex++;
|
||||
break;
|
||||
}
|
||||
|
||||
case JitFrame_BaselineStub: {
|
||||
JitFrameIterator prev(iter);
|
||||
JitFrameIterator prev(iter.frame());
|
||||
++prev;
|
||||
BaselineFrame* prevFrame = prev.baselineFrame();
|
||||
if (!obs.shouldRecompileOrInvalidate(prevFrame->script()))
|
||||
@ -589,7 +591,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
break;
|
||||
|
||||
BaselineStubFrameLayout* layout =
|
||||
reinterpret_cast<BaselineStubFrameLayout*>(iter.fp());
|
||||
reinterpret_cast<BaselineStubFrameLayout*>(frame.fp());
|
||||
MOZ_ASSERT(layout->maybeStubPtr() == entry.oldStub);
|
||||
|
||||
// Patch baseline stub frames for case A above.
|
||||
@ -620,7 +622,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
|
||||
case JitFrame_IonJS: {
|
||||
// Nothing to patch.
|
||||
InlineFrameIterator inlineIter(cx, &iter);
|
||||
InlineFrameIterator inlineIter(cx, &frame);
|
||||
while (true) {
|
||||
if (obs.shouldRecompileOrInvalidate(inlineIter.script()))
|
||||
entryIndex++;
|
||||
@ -634,7 +636,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
|
||||
default:;
|
||||
}
|
||||
|
||||
prev = iter.current();
|
||||
prev = frame.current();
|
||||
}
|
||||
|
||||
*start = entryIndex;
|
||||
@ -1173,12 +1175,10 @@ JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrame
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
DebugModeOSRVolatileJitFrameIterator::forwardLiveIterators(const CooperatingContext& cx,
|
||||
uint8_t* oldAddr, uint8_t* newAddr)
|
||||
DebugModeOSRVolatileJitFrameIter::forwardLiveIterators(const CooperatingContext& cx,
|
||||
uint8_t* oldAddr, uint8_t* newAddr)
|
||||
{
|
||||
DebugModeOSRVolatileJitFrameIterator* iter;
|
||||
for (iter = cx.context()->liveVolatileJitFrameIterators_; iter; iter = iter->prev) {
|
||||
if (iter->returnAddressToFp_ == oldAddr)
|
||||
iter->returnAddressToFp_ = newAddr;
|
||||
}
|
||||
DebugModeOSRVolatileJitFrameIter* iter;
|
||||
for (iter = cx.context()->liveVolatileJitFrameIter_; iter; iter = iter->prev)
|
||||
iter->asJSJit().exchangeReturnAddressIfMatch(oldAddr, newAddr);
|
||||
}
|
||||
|
@ -82,24 +82,25 @@ class DebugModeOSRVolatileStub
|
||||
};
|
||||
|
||||
//
|
||||
// A JitFrameIterator that updates itself in case of recompilation of an
|
||||
// on-stack baseline script.
|
||||
// A JitFrameIter that updates internal JitFrameIterator in case of
|
||||
// recompilation of an on-stack baseline script.
|
||||
//
|
||||
class DebugModeOSRVolatileJitFrameIterator : public JitFrameIterator
|
||||
|
||||
class DebugModeOSRVolatileJitFrameIter : public JitFrameIter
|
||||
{
|
||||
DebugModeOSRVolatileJitFrameIterator** stack;
|
||||
DebugModeOSRVolatileJitFrameIterator* prev;
|
||||
DebugModeOSRVolatileJitFrameIter** stack;
|
||||
DebugModeOSRVolatileJitFrameIter* prev;
|
||||
|
||||
public:
|
||||
explicit DebugModeOSRVolatileJitFrameIterator(JSContext* cx)
|
||||
: JitFrameIterator(cx)
|
||||
explicit DebugModeOSRVolatileJitFrameIter(JSContext* cx)
|
||||
: JitFrameIter(cx->activation())
|
||||
{
|
||||
stack = &cx->liveVolatileJitFrameIterators_.ref();
|
||||
stack = &cx->liveVolatileJitFrameIter_.ref();
|
||||
prev = *stack;
|
||||
*stack = this;
|
||||
}
|
||||
|
||||
~DebugModeOSRVolatileJitFrameIterator() {
|
||||
~DebugModeOSRVolatileJitFrameIter() {
|
||||
MOZ_ASSERT(*stack == this);
|
||||
*stack = prev;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ TraceLocals(BaselineFrame* frame, JSTracer* trc, unsigned start, unsigned end)
|
||||
}
|
||||
|
||||
void
|
||||
BaselineFrame::trace(JSTracer* trc, JitFrameIterator& frameIterator)
|
||||
BaselineFrame::trace(JSTracer* trc, const JitFrameIterator& frameIterator)
|
||||
{
|
||||
replaceCalleeToken(TraceCalleeToken(trc, calleeToken()));
|
||||
|
||||
@ -142,10 +142,10 @@ BaselineFrame::initForOsr(InterpreterFrame* fp, uint32_t numStackValues)
|
||||
// debugger, wants a valid return address, but it's okay to just pick one.
|
||||
// In debug mode there's always at least 1 ICEntry (since there are always
|
||||
// debug prologue/epilogue calls).
|
||||
JitFrameIterator iter(cx);
|
||||
MOZ_ASSERT(iter.returnAddress() == nullptr);
|
||||
JitFrameIterator frame(cx);
|
||||
MOZ_ASSERT(frame.returnAddress() == nullptr);
|
||||
BaselineScript* baseline = fp->script()->baselineScript();
|
||||
iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));
|
||||
frame.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));
|
||||
|
||||
if (!Debugger::handleBaselineOsr(cx, fp, this))
|
||||
return false;
|
||||
|
@ -370,7 +370,7 @@ class BaselineFrame
|
||||
flags_ &= ~HAS_OVERRIDE_PC;
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc, JitFrameIterator& frame);
|
||||
void trace(JSTracer* trc, const JitFrameIterator& frame);
|
||||
|
||||
bool isGlobalFrame() const {
|
||||
return script()->isGlobalCode();
|
||||
|
@ -1229,14 +1229,15 @@ jit::ToggleBaselineTraceLoggerEngine(JSRuntime* runtime, bool enable)
|
||||
static void
|
||||
MarkActiveBaselineScripts(JSContext* cx, const JitActivationIterator& activation)
|
||||
{
|
||||
for (jit::JitFrameIterator iter(activation); !iter.done(); ++iter) {
|
||||
switch (iter.type()) {
|
||||
for (OnlyJSJitFrameIter iter(activation); !iter.done(); ++iter) {
|
||||
const JitFrameIterator& frame = iter.frame();
|
||||
switch (frame.type()) {
|
||||
case JitFrame_BaselineJS:
|
||||
iter.script()->baselineScript()->setActive();
|
||||
frame.script()->baselineScript()->setActive();
|
||||
break;
|
||||
case JitFrame_Exit:
|
||||
if (iter.exitFrame()->is<LazyLinkExitFrameLayout>()) {
|
||||
LazyLinkExitFrameLayout* ll = iter.exitFrame()->as<LazyLinkExitFrameLayout>();
|
||||
if (frame.exitFrame()->is<LazyLinkExitFrameLayout>()) {
|
||||
LazyLinkExitFrameLayout* ll = frame.exitFrame()->as<LazyLinkExitFrameLayout>();
|
||||
ScriptFromCalleeToken(ll->jsFrame()->calleeToken())->baselineScript()->setActive();
|
||||
}
|
||||
break;
|
||||
@ -1244,8 +1245,8 @@ MarkActiveBaselineScripts(JSContext* cx, const JitActivationIterator& activation
|
||||
case JitFrame_IonJS: {
|
||||
// Keep the baseline script around, since bailouts from the ion
|
||||
// jitcode might need to re-enter into the baseline jitcode.
|
||||
iter.script()->baselineScript()->setActive();
|
||||
for (InlineFrameIterator inlineIter(cx, &iter); inlineIter.more(); ++inlineIter)
|
||||
frame.script()->baselineScript()->setActive();
|
||||
for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more(); ++inlineIter)
|
||||
inlineIter.script()->baselineScript()->setActive();
|
||||
break;
|
||||
}
|
||||
|
@ -630,7 +630,7 @@ struct BaselineBailoutInfo
|
||||
};
|
||||
|
||||
uint32_t
|
||||
BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIterator& iter,
|
||||
BailoutIonToBaseline(JSContext* cx, JitActivation* activation, const JitFrameIterator& iter,
|
||||
bool invalidate, BaselineBailoutInfo** bailoutInfo,
|
||||
const ExceptionBailoutInfo* exceptionInfo);
|
||||
|
||||
|
@ -591,8 +591,8 @@ jit::LazyLinkTopActivation()
|
||||
{
|
||||
// First frame should be an exit frame.
|
||||
JSContext* cx = TlsContext.get();
|
||||
JitFrameIterator it(cx);
|
||||
LazyLinkExitFrameLayout* ll = it.exitFrame()->as<LazyLinkExitFrameLayout>();
|
||||
JitFrameIterator frame(cx);
|
||||
LazyLinkExitFrameLayout* ll = frame.exitFrame()->as<LazyLinkExitFrameLayout>();
|
||||
RootedScript calleeScript(cx, ScriptFromCalleeToken(ll->jsFrame()->calleeToken()));
|
||||
|
||||
LinkIonScript(cx, calleeScript);
|
||||
@ -2971,64 +2971,65 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
||||
|
||||
size_t frameno = 1;
|
||||
|
||||
for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) {
|
||||
MOZ_ASSERT_IF(frameno == 1, it.isExitFrame() || it.type() == JitFrame_Bailout);
|
||||
for (OnlyJSJitFrameIter iter(activations); !iter.done(); ++iter, ++frameno) {
|
||||
const JitFrameIterator& frame = iter.frame();
|
||||
MOZ_ASSERT_IF(frameno == 1, frame.isExitFrame() || frame.type() == JitFrame_Bailout);
|
||||
|
||||
#ifdef JS_JITSPEW
|
||||
switch (it.type()) {
|
||||
switch (frame.type()) {
|
||||
case JitFrame_Exit:
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu exit frame @ %p", frameno, it.fp());
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu exit frame @ %p", frameno, frame.fp());
|
||||
break;
|
||||
case JitFrame_BaselineJS:
|
||||
case JitFrame_IonJS:
|
||||
case JitFrame_Bailout:
|
||||
{
|
||||
MOZ_ASSERT(it.isScripted());
|
||||
MOZ_ASSERT(frame.isScripted());
|
||||
const char* type = "Unknown";
|
||||
if (it.isIonJS())
|
||||
if (frame.isIonJS())
|
||||
type = "Optimized";
|
||||
else if (it.isBaselineJS())
|
||||
else if (frame.isBaselineJS())
|
||||
type = "Baseline";
|
||||
else if (it.isBailoutJS())
|
||||
else if (frame.isBailoutJS())
|
||||
type = "Bailing";
|
||||
JitSpew(JitSpew_IonInvalidate,
|
||||
"#%zu %s JS frame @ %p, %s:%zu (fun: %p, script: %p, pc %p)",
|
||||
frameno, type, it.fp(), it.script()->maybeForwardedFilename(),
|
||||
it.script()->lineno(), it.maybeCallee(), (JSScript*)it.script(),
|
||||
it.returnAddressToFp());
|
||||
frameno, type, frame.fp(), frame.script()->maybeForwardedFilename(),
|
||||
frame.script()->lineno(), frame.maybeCallee(), (JSScript*)frame.script(),
|
||||
frame.returnAddressToFp());
|
||||
break;
|
||||
}
|
||||
case JitFrame_BaselineStub:
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu baseline stub frame @ %p", frameno, it.fp());
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu baseline stub frame @ %p", frameno, frame.fp());
|
||||
break;
|
||||
case JitFrame_Rectifier:
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu rectifier frame @ %p", frameno, it.fp());
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu rectifier frame @ %p", frameno, frame.fp());
|
||||
break;
|
||||
case JitFrame_IonICCall:
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu ion IC call frame @ %p", frameno, it.fp());
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu ion IC call frame @ %p", frameno, frame.fp());
|
||||
break;
|
||||
case JitFrame_Entry:
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu entry frame @ %p", frameno, it.fp());
|
||||
JitSpew(JitSpew_IonInvalidate, "#%zu entry frame @ %p", frameno, frame.fp());
|
||||
break;
|
||||
}
|
||||
#endif // JS_JITSPEW
|
||||
|
||||
if (!it.isIonScripted())
|
||||
if (!frame.isIonScripted())
|
||||
continue;
|
||||
|
||||
bool calledFromLinkStub = false;
|
||||
JitCode* lazyLinkStub = fop->runtime()->jitRuntime()->lazyLinkStub();
|
||||
if (it.returnAddressToFp() >= lazyLinkStub->raw() &&
|
||||
it.returnAddressToFp() < lazyLinkStub->rawEnd())
|
||||
if (frame.returnAddressToFp() >= lazyLinkStub->raw() &&
|
||||
frame.returnAddressToFp() < lazyLinkStub->rawEnd())
|
||||
{
|
||||
calledFromLinkStub = true;
|
||||
}
|
||||
|
||||
// See if the frame has already been invalidated.
|
||||
if (!calledFromLinkStub && it.checkInvalidation())
|
||||
if (!calledFromLinkStub && frame.checkInvalidation())
|
||||
continue;
|
||||
|
||||
JSScript* script = it.script();
|
||||
JSScript* script = frame.script();
|
||||
if (!script->hasIonScript())
|
||||
continue;
|
||||
|
||||
@ -3084,7 +3085,7 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
||||
|
||||
// Don't adjust OSI points in the linkStub (which don't exist), or in a
|
||||
// bailout path.
|
||||
if (calledFromLinkStub || it.isBailoutJS())
|
||||
if (calledFromLinkStub || frame.isBailoutJS())
|
||||
continue;
|
||||
|
||||
// Write the delta (from the return address offset to the
|
||||
@ -3094,10 +3095,10 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
||||
// a uint32, which is checked during safepoint index
|
||||
// construction.
|
||||
AutoWritableJitCode awjc(ionCode);
|
||||
const SafepointIndex* si = ionScript->getSafepointIndex(it.returnAddressToFp());
|
||||
CodeLocationLabel dataLabelToMunge(it.returnAddressToFp());
|
||||
const SafepointIndex* si = ionScript->getSafepointIndex(frame.returnAddressToFp());
|
||||
CodeLocationLabel dataLabelToMunge(frame.returnAddressToFp());
|
||||
ptrdiff_t delta = ionScript->invalidateEpilogueDataOffset() -
|
||||
(it.returnAddressToFp() - ionCode->raw());
|
||||
(frame.returnAddressToFp() - ionCode->raw());
|
||||
Assembler::PatchWrite_Imm32(dataLabelToMunge, Imm32(delta));
|
||||
|
||||
CodeLocationLabel osiPatchPoint = SafepointReader::InvalidationPatchPoint(ionScript, si);
|
||||
|
@ -89,14 +89,14 @@ CodeOffsetJump::fixup(MacroAssembler* masm)
|
||||
void*
|
||||
jit::GetReturnAddressToIonCode(JSContext* cx)
|
||||
{
|
||||
JitFrameIterator iter(cx);
|
||||
MOZ_ASSERT(iter.type() == JitFrame_Exit,
|
||||
JitFrameIterator frame(cx);
|
||||
MOZ_ASSERT(frame.type() == JitFrame_Exit,
|
||||
"An exit frame is expected as update functions are called with a VMFunction.");
|
||||
|
||||
void* returnAddr = iter.returnAddress();
|
||||
void* returnAddr = frame.returnAddress();
|
||||
#ifdef DEBUG
|
||||
++iter;
|
||||
MOZ_ASSERT(iter.isIonJS());
|
||||
++frame;
|
||||
MOZ_ASSERT(frame.isIonJS());
|
||||
#endif
|
||||
return returnAddr;
|
||||
}
|
||||
|
@ -14,16 +14,6 @@
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
JitFrameIterator::JitFrameIterator()
|
||||
: current_(nullptr),
|
||||
type_(JitFrame_Exit),
|
||||
returnAddressToFp_(nullptr),
|
||||
frameSize_(0),
|
||||
cachedSafepointIndex_(nullptr),
|
||||
activation_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
JitFrameIterator::JitFrameIterator(const JitActivation* activation)
|
||||
: current_(activation->exitFP()),
|
||||
type_(JitFrame_Exit),
|
||||
@ -44,11 +34,6 @@ JitFrameIterator::JitFrameIterator(JSContext* cx)
|
||||
{
|
||||
}
|
||||
|
||||
JitFrameIterator::JitFrameIterator(const ActivationIterator& activations)
|
||||
: JitFrameIterator(activations->asJit())
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
JitFrameIterator::checkInvalidation() const
|
||||
{
|
||||
@ -164,7 +149,7 @@ JitFrameIterator::prevFp() const
|
||||
return current_ + current()->prevFrameLocalSize() + current()->headerSize();
|
||||
}
|
||||
|
||||
JitFrameIterator&
|
||||
void
|
||||
JitFrameIterator::operator++()
|
||||
{
|
||||
MOZ_ASSERT(type_ != JitFrame_Entry);
|
||||
@ -176,14 +161,12 @@ JitFrameIterator::operator++()
|
||||
// since the entry and first frames overlap.
|
||||
if (current()->prevType() == JitFrame_Entry) {
|
||||
type_ = JitFrame_Entry;
|
||||
return *this;
|
||||
return;
|
||||
}
|
||||
|
||||
type_ = current()->prevType();
|
||||
returnAddressToFp_ = current()->returnAddress();
|
||||
current_ = prevFp();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
uintptr_t*
|
||||
|
@ -16,10 +16,6 @@
|
||||
|
||||
#include "js/ProfilingFrameIterator.h"
|
||||
|
||||
namespace js {
|
||||
class ActivationIterator;
|
||||
} // namespace js
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
@ -83,8 +79,17 @@ class JitActivation;
|
||||
// Iterate over the JIT stack to assert that all invariants are respected.
|
||||
// - Check that all entry frames are aligned on JitStackAlignment.
|
||||
// - Check that all rectifier frames keep the JitStackAlignment.
|
||||
|
||||
void AssertJitStackInvariants(JSContext* cx);
|
||||
|
||||
// A JitFrameIterator can iterate over a linear frame group of JS jit frames
|
||||
// only. It will stop at the first frame that is not of the same kind, or at
|
||||
// the end of an activation.
|
||||
//
|
||||
// If you want to handle every kind of frames (including wasm frames), use
|
||||
// JitFrameIter. If you want to skip interleaved frames of other kinds, use
|
||||
// OnlyJSJitFrameIter.
|
||||
|
||||
class JitFrameIterator
|
||||
{
|
||||
protected:
|
||||
@ -99,12 +104,16 @@ class JitFrameIterator
|
||||
|
||||
void dumpBaseline() const;
|
||||
|
||||
explicit JitFrameIterator(const JitActivation* activation);
|
||||
|
||||
public:
|
||||
explicit JitFrameIterator();
|
||||
// See comment above the class.
|
||||
explicit JitFrameIterator(const JitActivation* activation);
|
||||
explicit JitFrameIterator(JSContext* cx);
|
||||
explicit JitFrameIterator(const ActivationIterator& activations);
|
||||
|
||||
// Used only by DebugModeOSRVolatileJSJitFrameIter.
|
||||
void exchangeReturnAddressIfMatch(uint8_t* oldAddr, uint8_t* newAddr) {
|
||||
if (returnAddressToFp_ == oldAddr)
|
||||
returnAddressToFp_ = newAddr;
|
||||
}
|
||||
|
||||
// Current frame information.
|
||||
FrameType type() const {
|
||||
@ -199,10 +208,10 @@ class JitFrameIterator
|
||||
|
||||
// Functions used to iterate on frames. When prevType is JitFrame_Entry,
|
||||
// the current frame is the last frame.
|
||||
inline bool done() const {
|
||||
bool done() const {
|
||||
return type_ == JitFrame_Entry;
|
||||
}
|
||||
JitFrameIterator& operator++();
|
||||
void operator++();
|
||||
|
||||
// Returns the IonScript associated with this JS frame.
|
||||
IonScript* ionScript() const;
|
||||
@ -260,7 +269,7 @@ class JitFrameIterator
|
||||
#ifdef DEBUG
|
||||
bool verifyReturnAddressUsingNativeToBytecodeMap();
|
||||
#else
|
||||
inline bool verifyReturnAddressUsingNativeToBytecodeMap() { return true; }
|
||||
bool verifyReturnAddressUsingNativeToBytecodeMap() { return true; }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -29,13 +29,13 @@ SafepointIndex::resolve()
|
||||
inline BaselineFrame*
|
||||
GetTopBaselineFrame(JSContext* cx)
|
||||
{
|
||||
JitFrameIterator iter(cx);
|
||||
MOZ_ASSERT(iter.type() == JitFrame_Exit);
|
||||
++iter;
|
||||
if (iter.isBaselineStub())
|
||||
++iter;
|
||||
MOZ_ASSERT(iter.isBaselineJS());
|
||||
return iter.baselineFrame();
|
||||
JitFrameIterator frame(cx);
|
||||
MOZ_ASSERT(frame.type() == JitFrame_Exit);
|
||||
++frame;
|
||||
if (frame.isBaselineStub())
|
||||
++frame;
|
||||
MOZ_ASSERT(frame.isBaselineJS());
|
||||
return frame.baselineFrame();
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
|
@ -625,17 +625,21 @@ HandleException(ResumeFromException* rfe)
|
||||
// JitFrameIterators cache the previous frame's return address when
|
||||
// iterating, we need a variant here that is automatically updated should
|
||||
// on-stack recompilation occur.
|
||||
DebugModeOSRVolatileJitFrameIterator iter(cx);
|
||||
while (!iter.isEntry()) {
|
||||
DebugModeOSRVolatileJitFrameIter iter(cx);
|
||||
while (!iter.isJSJit() || !iter.asJSJit().isEntry()) {
|
||||
while (!iter.isJSJit())
|
||||
++iter;
|
||||
const JitFrameIterator& frame = iter.asJSJit();
|
||||
|
||||
bool overrecursed = false;
|
||||
if (iter.isIonJS()) {
|
||||
if (frame.isIonJS()) {
|
||||
// Search each inlined frame for live iterator objects, and close
|
||||
// them.
|
||||
InlineFrameIterator frames(cx, &iter);
|
||||
InlineFrameIterator frames(cx, &frame);
|
||||
|
||||
// Invalidation state will be the same for all inlined scripts in the frame.
|
||||
IonScript* ionScript = nullptr;
|
||||
bool invalidated = iter.checkInvalidation(&ionScript);
|
||||
bool invalidated = frame.checkInvalidation(&ionScript);
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
if (logger && cx->compartment()->isDebuggee() && logger->enabled()) {
|
||||
@ -672,11 +676,11 @@ HandleException(ResumeFromException* rfe)
|
||||
++frames;
|
||||
}
|
||||
|
||||
activation->removeIonFrameRecovery(iter.jsFrame());
|
||||
activation->removeIonFrameRecovery(frame.jsFrame());
|
||||
if (invalidated)
|
||||
ionScript->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
|
||||
|
||||
} else if (iter.isBaselineJS()) {
|
||||
} else if (frame.isBaselineJS()) {
|
||||
// Set a flag on the frame to signal to DebugModeOSR that we're
|
||||
// handling an exception. Also ensure the frame has an override
|
||||
// pc. We clear the frame's override pc when we leave this block,
|
||||
@ -690,16 +694,16 @@ HandleException(ResumeFromException* rfe)
|
||||
// FinishBailoutToBaseline will set the pc to the resume pc
|
||||
// and clear it before it returns to JIT code.
|
||||
jsbytecode* pc;
|
||||
iter.baselineScriptAndPc(nullptr, &pc);
|
||||
AutoBaselineHandlingException handlingException(iter.baselineFrame(), pc);
|
||||
frame.baselineScriptAndPc(nullptr, &pc);
|
||||
AutoBaselineHandlingException handlingException(frame.baselineFrame(), pc);
|
||||
|
||||
HandleExceptionBaseline(cx, iter, rfe, pc);
|
||||
HandleExceptionBaseline(cx, frame, rfe, pc);
|
||||
|
||||
// If we are propagating an exception through a frame with
|
||||
// on-stack recompile info, we should free the allocated
|
||||
// RecompileInfo struct before we leave this block, as we will not
|
||||
// be returning to the recompile handler.
|
||||
AutoDeleteDebugModeOSRInfo deleteDebugModeOSRInfo(iter.baselineFrame());
|
||||
AutoDeleteDebugModeOSRInfo deleteDebugModeOSRInfo(frame.baselineFrame());
|
||||
|
||||
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME &&
|
||||
rfe->kind != ResumeFromException::RESUME_FORCED_RETURN)
|
||||
@ -711,7 +715,7 @@ HandleException(ResumeFromException* rfe)
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
|
||||
// Unwind profiler pseudo-stack
|
||||
JSScript* script = iter.script();
|
||||
JSScript* script = frame.script();
|
||||
probes::ExitScript(cx, script, script->functionNonDelazifying(),
|
||||
/* popProfilerFrame = */ false);
|
||||
|
||||
@ -719,7 +723,7 @@ HandleException(ResumeFromException* rfe)
|
||||
return;
|
||||
}
|
||||
|
||||
JitFrameLayout* current = iter.isScripted() ? iter.jsFrame() : nullptr;
|
||||
JitFrameLayout* current = frame.isScripted() ? frame.jsFrame() : nullptr;
|
||||
|
||||
++iter;
|
||||
|
||||
@ -738,7 +742,7 @@ HandleException(ResumeFromException* rfe)
|
||||
}
|
||||
}
|
||||
|
||||
rfe->stackPointer = iter.fp();
|
||||
rfe->stackPointer = iter.asJSJit().fp();
|
||||
}
|
||||
|
||||
// Turns a JitFrameLayout into an ExitFrameLayout. Note that it has to be a
|
||||
@ -1257,10 +1261,8 @@ TraceRectifierFrame(JSTracer* trc, const JitFrameIterator& frame)
|
||||
}
|
||||
|
||||
static void
|
||||
TraceJitActivation(JSTracer* trc, const JitActivationIterator& activations)
|
||||
TraceJitActivation(JSTracer* trc, JitActivation* activation)
|
||||
{
|
||||
JitActivation* activation = activations->asJit();
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (JitOptions.checkOsiPointRegisters) {
|
||||
// GC can modify spilled registers, breaking our register checks.
|
||||
@ -1273,7 +1275,7 @@ TraceJitActivation(JSTracer* trc, const JitActivationIterator& activations)
|
||||
activation->traceRematerializedFrames(trc);
|
||||
activation->traceIonRecovery(trc);
|
||||
|
||||
for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
|
||||
for (JitFrameIterator frames(activation); !frames.done(); ++frames) {
|
||||
switch (frames.type()) {
|
||||
case JitFrame_Exit:
|
||||
TraceJitExitFrame(trc, frames);
|
||||
@ -1302,11 +1304,22 @@ TraceJitActivation(JSTracer* trc, const JitActivationIterator& activations)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TraceWasmActivation(JSTracer* trc, WasmActivation* act)
|
||||
{
|
||||
for (wasm::WasmFrameIter iter(act); !iter.done(); ++iter)
|
||||
iter.instance()->trace(trc);
|
||||
}
|
||||
|
||||
void
|
||||
TraceJitActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc)
|
||||
{
|
||||
for (JitActivationIterator activations(cx, target); !activations.done(); ++activations)
|
||||
TraceJitActivation(trc, activations);
|
||||
for (ActivationIterator activations(cx, target); !activations.done(); ++activations) {
|
||||
if (activations->isJit())
|
||||
TraceJitActivation(trc, activations->asJit());
|
||||
if (activations->isWasm())
|
||||
TraceWasmActivation(trc, activations->asWasm());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1316,9 +1329,9 @@ UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc)
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (const CooperatingContext& target : rt->cooperatingContexts()) {
|
||||
for (JitActivationIterator activations(cx, target); !activations.done(); ++activations) {
|
||||
for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
|
||||
if (frames.type() == JitFrame_IonJS)
|
||||
UpdateIonJSFrameForMinorGC(trc, frames);
|
||||
for (OnlyJSJitFrameIter iter(activations); !iter.done(); ++iter) {
|
||||
if (iter.frame().type() == JitFrame_IonJS)
|
||||
UpdateIonJSFrameForMinorGC(trc, iter.frame());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1331,28 +1344,30 @@ GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes)
|
||||
|
||||
// Recover the return address so that we can look it up in the
|
||||
// PcScriptCache, as script/pc computation is expensive.
|
||||
JitActivationIterator iter(cx);
|
||||
JitFrameIterator it(iter);
|
||||
JitActivationIterator actIter(cx);
|
||||
OnlyJSJitFrameIter it(actIter);
|
||||
uint8_t* retAddr;
|
||||
if (it.isExitFrame()) {
|
||||
if (it.frame().isExitFrame()) {
|
||||
++it;
|
||||
|
||||
// Skip rectifier frames.
|
||||
if (it.isRectifier()) {
|
||||
if (it.frame().isRectifier()) {
|
||||
++it;
|
||||
MOZ_ASSERT(it.isBaselineStub() || it.isBaselineJS() || it.isIonJS());
|
||||
MOZ_ASSERT(it.frame().isBaselineStub() ||
|
||||
it.frame().isBaselineJS() ||
|
||||
it.frame().isIonJS());
|
||||
}
|
||||
|
||||
// Skip Baseline/Ion stub and IC call frames.
|
||||
if (it.isBaselineStub()) {
|
||||
if (it.frame().isBaselineStub()) {
|
||||
++it;
|
||||
MOZ_ASSERT(it.isBaselineJS());
|
||||
} else if (it.isIonICCall()) {
|
||||
MOZ_ASSERT(it.frame().isBaselineJS());
|
||||
} else if (it.frame().isIonICCall()) {
|
||||
++it;
|
||||
MOZ_ASSERT(it.isIonJS());
|
||||
MOZ_ASSERT(it.frame().isIonJS());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(it.isBaselineJS() || it.isIonJS());
|
||||
MOZ_ASSERT(it.frame().isBaselineJS() || it.frame().isIonJS());
|
||||
|
||||
// Don't use the return address if the BaselineFrame has an override pc.
|
||||
// The override pc is cheap to get, so we won't benefit from the cache,
|
||||
@ -1360,15 +1375,15 @@ GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes)
|
||||
// Moreover, sometimes when an override pc is present during exception
|
||||
// handling, the return address is set to nullptr as a sanity check,
|
||||
// since we do not return to the frame that threw the exception.
|
||||
if (!it.isBaselineJS() || !it.baselineFrame()->hasOverridePc()) {
|
||||
retAddr = it.returnAddressToFp();
|
||||
if (!it.frame().isBaselineJS() || !it.frame().baselineFrame()->hasOverridePc()) {
|
||||
retAddr = it.frame().returnAddressToFp();
|
||||
MOZ_ASSERT(retAddr);
|
||||
} else {
|
||||
retAddr = nullptr;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(it.isBailoutJS());
|
||||
retAddr = it.returnAddress();
|
||||
MOZ_ASSERT(it.frame().isBailoutJS());
|
||||
retAddr = it.frame().returnAddress();
|
||||
}
|
||||
|
||||
uint32_t hash;
|
||||
@ -1388,13 +1403,13 @@ GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes)
|
||||
|
||||
// Lookup failed: undertake expensive process to recover the innermost inlined frame.
|
||||
jsbytecode* pc = nullptr;
|
||||
if (it.isIonJS() || it.isBailoutJS()) {
|
||||
InlineFrameIterator ifi(cx, &it);
|
||||
if (it.frame().isIonJS() || it.frame().isBailoutJS()) {
|
||||
InlineFrameIterator ifi(cx, &it.frame());
|
||||
*scriptRes = ifi.script();
|
||||
pc = ifi.pc();
|
||||
} else {
|
||||
MOZ_ASSERT(it.isBaselineJS());
|
||||
it.baselineScriptAndPc(scriptRes, &pc);
|
||||
MOZ_ASSERT(it.frame().isBaselineJS());
|
||||
it.frame().baselineScriptAndPc(scriptRes, &pc);
|
||||
}
|
||||
|
||||
if (pcRes)
|
||||
@ -2659,7 +2674,8 @@ JitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame)
|
||||
}
|
||||
|
||||
if (prevType == JitFrame_Entry) {
|
||||
// No previous frame, set to null to indicate that JitFrameIterator is done()
|
||||
// No previous frame, set to null to indicate that OnlyJSJitFrameIter is
|
||||
// done().
|
||||
returnAddressToFp_ = nullptr;
|
||||
fp_ = nullptr;
|
||||
type_ = JitFrame_Entry;
|
||||
@ -2694,11 +2710,12 @@ void
|
||||
AssertJitStackInvariants(JSContext* cx)
|
||||
{
|
||||
for (JitActivationIterator activations(cx); !activations.done(); ++activations) {
|
||||
JitFrameIterator frames(activations);
|
||||
JitFrameIter iter(activations.activation());
|
||||
size_t prevFrameSize = 0;
|
||||
size_t frameSize = 0;
|
||||
bool isScriptedCallee = false;
|
||||
for (; !frames.done(); ++frames) {
|
||||
for (; !iter.done(); ++iter) {
|
||||
const JitFrameIterator& frames = iter.asJSJit();
|
||||
size_t calleeFp = reinterpret_cast<size_t>(frames.fp());
|
||||
size_t callerFp = reinterpret_cast<size_t>(frames.prevFp());
|
||||
MOZ_ASSERT(callerFp >= calleeFp);
|
||||
@ -2751,14 +2768,12 @@ AssertJitStackInvariants(JSContext* cx)
|
||||
"The baseline stub restores the stack alignment");
|
||||
}
|
||||
|
||||
isScriptedCallee = false
|
||||
|| frames.isScripted()
|
||||
|| frames.type() == JitFrame_Rectifier;
|
||||
isScriptedCallee = frames.isScripted() || frames.type() == JitFrame_Rectifier;
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(frames.type() == JitFrame_Entry,
|
||||
MOZ_RELEASE_ASSERT(iter.asJSJit().type() == JitFrame_Entry,
|
||||
"The first frame of a Jit activation should be an entry frame");
|
||||
MOZ_RELEASE_ASSERT(reinterpret_cast<size_t>(frames.fp()) % JitStackAlignment == 0,
|
||||
MOZ_RELEASE_ASSERT(reinterpret_cast<size_t>(iter.asJSJit().fp()) % JitStackAlignment == 0,
|
||||
"The entry frame should be properly aligned");
|
||||
}
|
||||
}
|
||||
|
@ -311,17 +311,17 @@ MakeFrameDescriptor(uint32_t frameSize, FrameType type, uint32_t headerSize)
|
||||
inline JSScript*
|
||||
GetTopJitJSScript(JSContext* cx)
|
||||
{
|
||||
JitFrameIterator iter(cx);
|
||||
MOZ_ASSERT(iter.type() == JitFrame_Exit);
|
||||
++iter;
|
||||
JitFrameIterator frame(cx);
|
||||
MOZ_ASSERT(frame.type() == JitFrame_Exit);
|
||||
++frame;
|
||||
|
||||
if (iter.isBaselineStub()) {
|
||||
++iter;
|
||||
MOZ_ASSERT(iter.isBaselineJS());
|
||||
if (frame.isBaselineStub()) {
|
||||
++frame;
|
||||
MOZ_ASSERT(frame.isBaselineJS());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(iter.isScripted());
|
||||
return iter.script();
|
||||
MOZ_ASSERT(frame.isScripted());
|
||||
return frame.script();
|
||||
}
|
||||
|
||||
#ifdef JS_CODEGEN_MIPS32
|
||||
|
@ -664,8 +664,8 @@ HandleScript
|
||||
SharedStubInfo::outerScript(JSContext* cx)
|
||||
{
|
||||
if (!outerScript_) {
|
||||
js::jit::JitActivationIterator iter(cx);
|
||||
JitFrameIterator it(iter);
|
||||
js::jit::JitActivationIterator actIter(cx);
|
||||
JitFrameIterator it(actIter->asJit());
|
||||
MOZ_ASSERT(it.isExitFrame());
|
||||
++it;
|
||||
MOZ_ASSERT(it.isIonJS());
|
||||
|
@ -365,10 +365,10 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
|
||||
// possible the SetOrExtendAnyBoxedOrUnboxedDenseElements call already
|
||||
// invalidated the IonScript. JitFrameIterator::ionScript works when the
|
||||
// script is invalidated so we use that instead.
|
||||
JitFrameIterator it(cx);
|
||||
MOZ_ASSERT(it.type() == JitFrame_Exit);
|
||||
++it;
|
||||
IonScript* ionScript = it.ionScript();
|
||||
JitFrameIterator frame(cx);
|
||||
MOZ_ASSERT(frame.type() == JitFrame_Exit);
|
||||
++frame;
|
||||
IonScript* ionScript = frame.ionScript();
|
||||
|
||||
JS::AutoValueArray<3> argv(cx);
|
||||
AutoDetectInvalidation adi(cx, argv[0], ionScript);
|
||||
@ -1256,12 +1256,12 @@ RecompileImpl(JSContext* cx, bool force)
|
||||
{
|
||||
MOZ_ASSERT(cx->currentlyRunningInJit());
|
||||
JitActivationIterator activations(cx);
|
||||
JitFrameIterator iter(activations);
|
||||
JitFrameIterator frame(activations->asJit());
|
||||
|
||||
MOZ_ASSERT(iter.type() == JitFrame_Exit);
|
||||
++iter;
|
||||
MOZ_ASSERT(frame.type() == JitFrame_Exit);
|
||||
++frame;
|
||||
|
||||
RootedScript script(cx, iter.script());
|
||||
RootedScript script(cx, frame.script());
|
||||
MOZ_ASSERT(script->hasIonScript());
|
||||
|
||||
if (!IsIonEnabled(cx))
|
||||
|
@ -7402,8 +7402,8 @@ GetScriptedCallerActivationFast(JSContext* cx, Activation** activation)
|
||||
*activation = activationIter.activation();
|
||||
|
||||
if (activationIter->isJit()) {
|
||||
for (jit::JitFrameIterator iter(activationIter); !iter.done(); ++iter) {
|
||||
if (iter.isScripted() && !iter.script()->selfHosted())
|
||||
for (OnlyJSJitFrameIter iter(activationIter); !iter.done(); ++iter) {
|
||||
if (iter.frame().isScripted() && !iter.frame().script()->selfHosted())
|
||||
return true;
|
||||
}
|
||||
} else if (activationIter->isInterpreter()) {
|
||||
|
@ -1330,7 +1330,7 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
|
||||
throwing(false),
|
||||
overRecursed_(false),
|
||||
propagatingForcedReturn_(false),
|
||||
liveVolatileJitFrameIterators_(nullptr),
|
||||
liveVolatileJitFrameIter_(nullptr),
|
||||
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
|
||||
resolvingList(nullptr),
|
||||
#ifdef DEBUG
|
||||
|
@ -33,7 +33,7 @@ class AutoCompartment;
|
||||
|
||||
namespace jit {
|
||||
class JitContext;
|
||||
class DebugModeOSRVolatileJitFrameIterator;
|
||||
class DebugModeOSRVolatileJitFrameIter;
|
||||
} // namespace jit
|
||||
|
||||
typedef HashSet<Shape*> ShapeSet;
|
||||
@ -300,7 +300,7 @@ struct JSContext : public JS::RootingContext,
|
||||
}
|
||||
|
||||
friend class JS::AutoSaveExceptionState;
|
||||
friend class js::jit::DebugModeOSRVolatileJitFrameIterator;
|
||||
friend class js::jit::DebugModeOSRVolatileJitFrameIter;
|
||||
friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
|
||||
|
||||
// Returns to the embedding to allow other cooperative threads to run. We
|
||||
@ -636,7 +636,8 @@ struct JSContext : public JS::RootingContext,
|
||||
|
||||
// A stack of live iterators that need to be updated in case of debug mode
|
||||
// OSR.
|
||||
js::ThreadLocalData<js::jit::DebugModeOSRVolatileJitFrameIterator*> liveVolatileJitFrameIterators_;
|
||||
js::ThreadLocalData<js::jit::DebugModeOSRVolatileJitFrameIter*>
|
||||
liveVolatileJitFrameIter_;
|
||||
|
||||
public:
|
||||
js::ThreadLocalData<int32_t> reportGranularity; /* see vm/Probes.h */
|
||||
|
@ -3649,7 +3649,7 @@ js::DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start)
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
while (!i.done() && !i.isJit() && i.interpFrame() != start)
|
||||
while (!i.done() && !i.isJSJit() && i.interpFrame() != start)
|
||||
++i;
|
||||
|
||||
if (i.done()) {
|
||||
@ -3660,7 +3660,7 @@ js::DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start)
|
||||
}
|
||||
|
||||
for (; !i.done(); ++i) {
|
||||
if (i.isJit())
|
||||
if (i.isJSJit())
|
||||
fprintf(fp, "JIT frame\n");
|
||||
else
|
||||
fprintf(fp, "InterpreterFrame at %p\n", (void*) i.interpFrame());
|
||||
@ -3686,7 +3686,7 @@ js::DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start)
|
||||
}
|
||||
if (i.isFunctionFrame())
|
||||
MaybeDumpValue("this", i.thisArgument(cx), fp);
|
||||
if (!i.isJit()) {
|
||||
if (!i.isJSJit()) {
|
||||
fprintf(fp, " rval: ");
|
||||
dumpValue(i.interpFrame()->returnValue(), fp);
|
||||
fputc('\n', fp);
|
||||
@ -3695,7 +3695,7 @@ js::DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start)
|
||||
fprintf(fp, " flags:");
|
||||
if (i.isConstructing())
|
||||
fprintf(fp, " constructing");
|
||||
if (!i.isJit() && i.interpFrame()->isDebuggerEvalFrame())
|
||||
if (!i.isJSJit() && i.interpFrame()->isDebuggerEvalFrame())
|
||||
fprintf(fp, " debugger eval");
|
||||
if (i.isEvalFrame())
|
||||
fprintf(fp, " eval");
|
||||
|
@ -2630,14 +2630,15 @@ UpdateExecutionObservabilityOfScriptsInZone(JSContext* cx, Zone* zone,
|
||||
if (actIter->compartment()->zone() != zone)
|
||||
continue;
|
||||
|
||||
for (JitFrameIterator iter(actIter); !iter.done(); ++iter) {
|
||||
switch (iter.type()) {
|
||||
for (OnlyJSJitFrameIter iter(actIter); !iter.done(); ++iter) {
|
||||
const jit::JitFrameIterator& frame = iter.frame();
|
||||
switch (frame.type()) {
|
||||
case JitFrame_BaselineJS:
|
||||
MarkBaselineScriptActiveIfObservable(iter.script(), obs);
|
||||
MarkBaselineScriptActiveIfObservable(frame.script(), obs);
|
||||
break;
|
||||
case JitFrame_IonJS:
|
||||
MarkBaselineScriptActiveIfObservable(iter.script(), obs);
|
||||
for (InlineFrameIterator inlineIter(cx, &iter); inlineIter.more(); ++inlineIter)
|
||||
MarkBaselineScriptActiveIfObservable(frame.script(), obs);
|
||||
for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more(); ++inlineIter)
|
||||
MarkBaselineScriptActiveIfObservable(inlineIter.script(), obs);
|
||||
break;
|
||||
default:;
|
||||
@ -7642,11 +7643,11 @@ UpdateFrameIterPc(FrameIter& iter)
|
||||
while (activationIter.activation() != activation)
|
||||
++activationIter;
|
||||
|
||||
jit::JitFrameIterator jitIter(activationIter);
|
||||
while (!jitIter.isIonJS() || jitIter.jsFrame() != jsFrame)
|
||||
OnlyJSJitFrameIter jitIter(activationIter);
|
||||
while (!jitIter.frame().isIonJS() || jitIter.frame().jsFrame() != jsFrame)
|
||||
++jitIter;
|
||||
|
||||
jit::InlineFrameIterator ionInlineIter(cx, &jitIter);
|
||||
jit::InlineFrameIterator ionInlineIter(cx, &jitIter.frame());
|
||||
while (ionInlineIter.frameNo() != frame->frameNo())
|
||||
++ionInlineIter;
|
||||
|
||||
@ -8185,10 +8186,10 @@ static void
|
||||
DebuggerFrame_trace(JSTracer* trc, JSObject* obj)
|
||||
{
|
||||
OnStepHandler* onStepHandler = obj->as<DebuggerFrame>().onStepHandler();
|
||||
if (onStepHandler)
|
||||
if (onStepHandler)
|
||||
onStepHandler->trace(trc);
|
||||
OnPopHandler* onPopHandler = obj->as<DebuggerFrame>().onPopHandler();
|
||||
if (onPopHandler)
|
||||
if (onPopHandler)
|
||||
onPopHandler->trace(trc);
|
||||
}
|
||||
|
||||
|
@ -389,16 +389,16 @@ FrameIter::unaliasedForEachActual(JSContext* cx, Op op)
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case INTERP:
|
||||
interpFrame()->unaliasedForEachActual(op);
|
||||
return;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonJS()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
|
||||
MOZ_ASSERT(isJSJit());
|
||||
if (jsJitFrame().isIonJS()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
|
||||
ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover);
|
||||
} else if (data_.jitFrames_.isBailoutJS()) {
|
||||
} else if (jsJitFrame().isBailoutJS()) {
|
||||
// :TODO: (Bug 1070962) If we are introspecting the frame which is
|
||||
// being bailed, then we might be in the middle of recovering
|
||||
// instructions. Stacking computeInstructionResults implies that we
|
||||
@ -408,8 +408,8 @@ FrameIter::unaliasedForEachActual(JSContext* cx, Op op)
|
||||
jit::MaybeReadFallback fallback;
|
||||
ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback);
|
||||
} else {
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals);
|
||||
MOZ_ASSERT(jsJitFrame().isBaselineJS());
|
||||
jsJitFrame().unaliasedForEachActual(op, jit::ReadFrame_Actuals);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1034,11 +1034,11 @@ FrameIter::hasCachedSavedFrame() const
|
||||
if (hasUsableAbstractFramePtr())
|
||||
return abstractFramePtr().hasCachedSavedFrame();
|
||||
|
||||
MOZ_ASSERT(data_.jitFrames_.isIonScripted());
|
||||
MOZ_ASSERT(jsJitFrame().isIonScripted());
|
||||
// SavedFrame caching is done at the physical frame granularity (rather than
|
||||
// for each inlined frame) for ion. Therefore, it is impossible to have a
|
||||
// cached SavedFrame if this frame is not a physical frame.
|
||||
return isPhysicalIonFrame() && data_.jitFrames_.current()->hasCachedSavedFrame();
|
||||
return isPhysicalIonFrame() && jsJitFrame().current()->hasCachedSavedFrame();
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -1052,7 +1052,7 @@ FrameIter::setHasCachedSavedFrame()
|
||||
}
|
||||
|
||||
MOZ_ASSERT(isPhysicalIonFrame());
|
||||
data_.jitFrames_.current()->setHasCachedSavedFrame();
|
||||
jsJitFrame().current()->setHasCachedSavedFrame();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -490,6 +490,98 @@ InterpreterStack::pushExecuteFrame(JSContext* cx, HandleScript script, const Val
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
JitFrameIter::JitFrameIter(const JitFrameIter& another)
|
||||
{
|
||||
*this = another;
|
||||
}
|
||||
|
||||
JitFrameIter&
|
||||
JitFrameIter::operator=(const JitFrameIter& another)
|
||||
{
|
||||
MOZ_ASSERT(this != &another);
|
||||
|
||||
if (isSome())
|
||||
iter_.destroy();
|
||||
if (!another.isSome())
|
||||
return *this;
|
||||
|
||||
if (another.isJSJit()) {
|
||||
iter_.construct<jit::JitFrameIterator>(another.asJSJit());
|
||||
} else {
|
||||
MOZ_ASSERT(another.isWasm());
|
||||
iter_.construct<wasm::WasmFrameIter>(another.asWasm());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
JitFrameIter::JitFrameIter(Activation* act)
|
||||
{
|
||||
MOZ_ASSERT(act->isJit() || act->isWasm());
|
||||
if (act->isJit()) {
|
||||
iter_.construct<jit::JitFrameIterator>(act->asJit());
|
||||
} else {
|
||||
MOZ_ASSERT(act->isWasm());
|
||||
iter_.construct<wasm::WasmFrameIter>(act->asWasm());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JitFrameIter::skipNonScriptedJSFrames()
|
||||
{
|
||||
if (isJSJit()) {
|
||||
// Stop at the first scripted frame.
|
||||
jit::JitFrameIterator& frames = asJSJit();
|
||||
while (!frames.isScripted() && !frames.done())
|
||||
++frames;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JitFrameIter::done() const
|
||||
{
|
||||
if (!isSome())
|
||||
return true;
|
||||
if (isJSJit())
|
||||
return asJSJit().done();
|
||||
if (isWasm())
|
||||
return asWasm().done();
|
||||
MOZ_CRASH("unhandled case");
|
||||
}
|
||||
|
||||
void
|
||||
JitFrameIter::operator++()
|
||||
{
|
||||
MOZ_ASSERT(isSome());
|
||||
if (isJSJit()) {
|
||||
++asJSJit();
|
||||
return;
|
||||
}
|
||||
if (isWasm()) {
|
||||
++asWasm();
|
||||
return;
|
||||
}
|
||||
MOZ_CRASH("unhandled case");
|
||||
}
|
||||
|
||||
OnlyJSJitFrameIter::OnlyJSJitFrameIter(Activation* act)
|
||||
: JitFrameIter(act)
|
||||
{
|
||||
settle();
|
||||
}
|
||||
|
||||
OnlyJSJitFrameIter::OnlyJSJitFrameIter(JSContext* cx)
|
||||
: OnlyJSJitFrameIter(cx->activation())
|
||||
{
|
||||
}
|
||||
|
||||
OnlyJSJitFrameIter::OnlyJSJitFrameIter(const ActivationIterator& iter)
|
||||
: OnlyJSJitFrameIter(iter->asJit())
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
FrameIter::popActivation()
|
||||
{
|
||||
@ -533,35 +625,18 @@ FrameIter::settleOnActivation()
|
||||
}
|
||||
}
|
||||
|
||||
if (activation->isJit()) {
|
||||
data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
|
||||
|
||||
// Stop at the first scripted frame.
|
||||
while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done())
|
||||
++data_.jitFrames_;
|
||||
|
||||
// It's possible to have an JitActivation with no scripted frames,
|
||||
// for instance if we hit an over-recursion during bailout.
|
||||
if (activation->isJit() || activation->isWasm()) {
|
||||
data_.jitFrames_ = JitFrameIter(activation);
|
||||
data_.jitFrames_.skipNonScriptedJSFrames();
|
||||
if (data_.jitFrames_.done()) {
|
||||
// It's possible to have an JitActivation with no scripted
|
||||
// frames, for instance if we hit an over-recursion during
|
||||
// bailout.
|
||||
++data_.activations_;
|
||||
continue;
|
||||
}
|
||||
|
||||
nextJitFrame();
|
||||
data_.state_ = JIT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (activation->isWasm()) {
|
||||
data_.wasmFrames_ = wasm::WasmFrameIter(data_.activations_->asWasm());
|
||||
|
||||
if (data_.wasmFrames_.done()) {
|
||||
++data_.activations_;
|
||||
continue;
|
||||
}
|
||||
|
||||
data_.pc_ = nullptr;
|
||||
data_.state_ = WASM;
|
||||
nextJitFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -596,9 +671,7 @@ FrameIter::Data::Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
|
||||
pc_(nullptr),
|
||||
interpFrames_(nullptr),
|
||||
activations_(cx),
|
||||
jitFrames_(),
|
||||
ionInlineFrameNo_(0),
|
||||
wasmFrames_()
|
||||
ionInlineFrameNo_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -611,9 +684,7 @@ FrameIter::Data::Data(JSContext* cx, const CooperatingContext& target,
|
||||
pc_(nullptr),
|
||||
interpFrames_(nullptr),
|
||||
activations_(cx, target),
|
||||
jitFrames_(),
|
||||
ionInlineFrameNo_(0),
|
||||
wasmFrames_()
|
||||
ionInlineFrameNo_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -626,8 +697,7 @@ FrameIter::Data::Data(const FrameIter::Data& other)
|
||||
interpFrames_(other.interpFrames_),
|
||||
activations_(other.activations_),
|
||||
jitFrames_(other.jitFrames_),
|
||||
ionInlineFrameNo_(other.ionInlineFrameNo_),
|
||||
wasmFrames_(other.wasmFrames_)
|
||||
ionInlineFrameNo_(other.ionInlineFrameNo_)
|
||||
{
|
||||
}
|
||||
|
||||
@ -660,18 +730,16 @@ FrameIter::FrameIter(JSContext* cx, DebuggerEvalOption debuggerEvalOption,
|
||||
|
||||
FrameIter::FrameIter(const FrameIter& other)
|
||||
: data_(other.data_),
|
||||
ionInlineFrames_(other.data_.cx_,
|
||||
data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
|
||||
ionInlineFrames_(other.data_.cx_, isIonScripted() ? &other.ionInlineFrames_ : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
FrameIter::FrameIter(const Data& data)
|
||||
: data_(data),
|
||||
ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
|
||||
ionInlineFrames_(data.cx_, isIonScripted() ? &jsJitFrame() : nullptr)
|
||||
{
|
||||
MOZ_ASSERT(data.cx_);
|
||||
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
if (isIonScripted()) {
|
||||
while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
|
||||
++ionInlineFrames_;
|
||||
}
|
||||
@ -680,47 +748,44 @@ FrameIter::FrameIter(const Data& data)
|
||||
void
|
||||
FrameIter::nextJitFrame()
|
||||
{
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
ionInlineFrames_.resetOn(&data_.jitFrames_);
|
||||
data_.pc_ = ionInlineFrames_.pc();
|
||||
} else {
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
|
||||
MOZ_ASSERT(data_.jitFrames_.isSome());
|
||||
|
||||
if (isJSJit()) {
|
||||
if (jsJitFrame().isIonScripted()) {
|
||||
ionInlineFrames_.resetOn(&jsJitFrame());
|
||||
data_.pc_ = ionInlineFrames_.pc();
|
||||
} else {
|
||||
MOZ_ASSERT(jsJitFrame().isBaselineJS());
|
||||
jsJitFrame().baselineScriptAndPc(nullptr, &data_.pc_);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(isWasm());
|
||||
data_.pc_ = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FrameIter::popJitFrame()
|
||||
{
|
||||
MOZ_ASSERT(data_.state_ == JIT);
|
||||
MOZ_ASSERT(data_.jitFrames_.isSome());
|
||||
|
||||
if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
|
||||
if (isJSJit() && jsJitFrame().isIonScripted() && ionInlineFrames_.more()) {
|
||||
++ionInlineFrames_;
|
||||
data_.pc_ = ionInlineFrames_.pc();
|
||||
return;
|
||||
}
|
||||
|
||||
++data_.jitFrames_;
|
||||
while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
|
||||
++data_.jitFrames_;
|
||||
data_.jitFrames_.skipNonScriptedJSFrames();
|
||||
|
||||
if (!data_.jitFrames_.done()) {
|
||||
nextJitFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
popActivation();
|
||||
}
|
||||
|
||||
void
|
||||
FrameIter::popWasmFrame()
|
||||
{
|
||||
MOZ_ASSERT(data_.state_ == WASM);
|
||||
|
||||
++data_.wasmFrames_;
|
||||
data_.pc_ = nullptr;
|
||||
if (data_.wasmFrames_.done())
|
||||
} else {
|
||||
data_.jitFrames_.reset();
|
||||
popActivation();
|
||||
}
|
||||
}
|
||||
|
||||
FrameIter&
|
||||
@ -741,8 +806,6 @@ FrameIter::operator++()
|
||||
while (!hasUsableAbstractFramePtr() || abstractFramePtr() != eifPrev) {
|
||||
if (data_.state_ == JIT)
|
||||
popJitFrame();
|
||||
else if (data_.state_ == WASM)
|
||||
popWasmFrame();
|
||||
else
|
||||
popInterpreterFrame();
|
||||
}
|
||||
@ -754,9 +817,6 @@ FrameIter::operator++()
|
||||
case JIT:
|
||||
popJitFrame();
|
||||
break;
|
||||
case WASM:
|
||||
popWasmFrame();
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -768,7 +828,7 @@ FrameIter::copyData() const
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
if (data && data_.jitFrames_.isIonScripted())
|
||||
if (data && isIonScripted())
|
||||
data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
|
||||
return data;
|
||||
}
|
||||
@ -788,11 +848,12 @@ FrameIter::rawFramePtr() const
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
return nullptr;
|
||||
case JIT:
|
||||
return data_.jitFrames_.fp();
|
||||
case INTERP:
|
||||
return interpFrame();
|
||||
case WASM:
|
||||
case JIT:
|
||||
if (isJSJit())
|
||||
return jsJitFrame().fp();
|
||||
MOZ_ASSERT(isWasm());
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -806,7 +867,6 @@ FrameIter::compartment() const
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT:
|
||||
case WASM:
|
||||
return data_.activations_->compartment();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -821,11 +881,13 @@ FrameIter::isEvalFrame() const
|
||||
case INTERP:
|
||||
return interpFrame()->isEvalFrame();
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return data_.jitFrames_.baselineFrame()->isEvalFrame();
|
||||
MOZ_ASSERT(!script()->isForEval());
|
||||
return false;
|
||||
case WASM:
|
||||
if (isJSJit()) {
|
||||
if (jsJitFrame().isBaselineJS())
|
||||
return jsJitFrame().baselineFrame()->isEvalFrame();
|
||||
MOZ_ASSERT(!script()->isForEval());
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(isWasm());
|
||||
return false;
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -841,10 +903,12 @@ FrameIter::isFunctionFrame() const
|
||||
case INTERP:
|
||||
return interpFrame()->isFunctionFrame();
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return data_.jitFrames_.baselineFrame()->isFunctionFrame();
|
||||
return script()->functionNonDelazifying();
|
||||
case WASM:
|
||||
if (isJSJit()) {
|
||||
if (jsJitFrame().isBaselineJS())
|
||||
return jsJitFrame().baselineFrame()->isFunctionFrame();
|
||||
return script()->functionNonDelazifying();
|
||||
}
|
||||
MOZ_ASSERT(isWasm());
|
||||
return false;
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -858,11 +922,10 @@ FrameIter::functionDisplayAtom() const
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT:
|
||||
if (isWasm())
|
||||
return wasmFrame().functionDisplayAtom();
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
return calleeTemplate()->displayAtom();
|
||||
case WASM:
|
||||
MOZ_ASSERT(isWasm());
|
||||
return data_.wasmFrames_.functionDisplayAtom();
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -873,7 +936,6 @@ FrameIter::scriptSource() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT:
|
||||
@ -891,9 +953,9 @@ FrameIter::filename() const
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT:
|
||||
if (isWasm())
|
||||
return wasmFrame().filename();
|
||||
return script()->filename();
|
||||
case WASM:
|
||||
return data_.wasmFrames_.filename();
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -906,12 +968,11 @@ FrameIter::displayURL() const
|
||||
case DONE:
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT: {
|
||||
case JIT:
|
||||
if (isWasm())
|
||||
return wasmFrame().displayURL();
|
||||
ScriptSource* ss = script()->scriptSource();
|
||||
return ss->hasDisplayURL() ? ss->displayURL() : nullptr;
|
||||
}
|
||||
case WASM:
|
||||
return data_.wasmFrames_.displayURL();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -924,11 +985,12 @@ FrameIter::computeLine(uint32_t* column) const
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT:
|
||||
if (isWasm()) {
|
||||
if (column)
|
||||
*column = 0;
|
||||
return wasmFrame().lineOrBytecode();
|
||||
}
|
||||
return PCToLineNumber(script(), pc(), column);
|
||||
case WASM:
|
||||
if (column)
|
||||
*column = 0;
|
||||
return data_.wasmFrames_.lineOrBytecode();
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -942,9 +1004,9 @@ FrameIter::mutedErrors() const
|
||||
break;
|
||||
case INTERP:
|
||||
case JIT:
|
||||
if (isWasm())
|
||||
return wasmFrame().mutedErrors();
|
||||
return script()->mutedErrors();
|
||||
case WASM:
|
||||
return data_.wasmFrames_.mutedErrors();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -954,13 +1016,13 @@ FrameIter::isConstructing() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted())
|
||||
MOZ_ASSERT(isJSJit());
|
||||
if (jsJitFrame().isIonScripted())
|
||||
return ionInlineFrames_.isConstructing();
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
return data_.jitFrames_.isConstructing();
|
||||
MOZ_ASSERT(jsJitFrame().isBaselineJS());
|
||||
return jsJitFrame().isConstructing();
|
||||
case INTERP:
|
||||
return interpFrame()->isConstructing();
|
||||
}
|
||||
@ -972,7 +1034,7 @@ bool
|
||||
FrameIter::ensureHasRematerializedFrame(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(isIon());
|
||||
return !!activation()->asJit()->getRematerializedFrame(cx, data_.jitFrames_);
|
||||
return !!activation()->asJit()->getRematerializedFrame(cx, jsJitFrame());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -982,17 +1044,18 @@ FrameIter::hasUsableAbstractFramePtr() const
|
||||
case DONE:
|
||||
return false;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return true;
|
||||
if (isJSJit()) {
|
||||
if (jsJitFrame().isBaselineJS())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(data_.jitFrames_.isIonScripted());
|
||||
return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
|
||||
ionInlineFrames_.frameNo());
|
||||
break;
|
||||
MOZ_ASSERT(jsJitFrame().isIonScripted());
|
||||
return !!activation()->asJit()->lookupRematerializedFrame(jsJitFrame().fp(),
|
||||
ionInlineFrames_.frameNo());
|
||||
}
|
||||
MOZ_ASSERT(isWasm());
|
||||
return wasmFrame().debugEnabled();
|
||||
case INTERP:
|
||||
return true;
|
||||
case WASM:
|
||||
return data_.wasmFrames_.debugEnabled();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -1005,20 +1068,20 @@ FrameIter::abstractFramePtr() const
|
||||
case DONE:
|
||||
break;
|
||||
case JIT: {
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return data_.jitFrames_.baselineFrame();
|
||||
|
||||
MOZ_ASSERT(data_.jitFrames_.isIonScripted());
|
||||
return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
|
||||
ionInlineFrames_.frameNo());
|
||||
break;
|
||||
if (isJSJit()) {
|
||||
if (jsJitFrame().isBaselineJS())
|
||||
return jsJitFrame().baselineFrame();
|
||||
MOZ_ASSERT(isIonScripted());
|
||||
return activation()->asJit()->lookupRematerializedFrame(jsJitFrame().fp(),
|
||||
ionInlineFrames_.frameNo());
|
||||
}
|
||||
MOZ_ASSERT(isWasm());
|
||||
MOZ_ASSERT(wasmFrame().debugEnabled());
|
||||
return wasmFrame().debugFrame();
|
||||
}
|
||||
case INTERP:
|
||||
MOZ_ASSERT(interpFrame());
|
||||
return AbstractFramePtr(interpFrame());
|
||||
case WASM:
|
||||
MOZ_ASSERT(data_.wasmFrames_.debugEnabled());
|
||||
return data_.wasmFrames_.debugFrame();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -1027,7 +1090,6 @@ void
|
||||
FrameIter::updatePcQuadratic()
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case WASM:
|
||||
case DONE:
|
||||
break;
|
||||
case INTERP: {
|
||||
@ -1045,8 +1107,8 @@ FrameIter::updatePcQuadratic()
|
||||
return;
|
||||
}
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS()) {
|
||||
jit::BaselineFrame* frame = data_.jitFrames_.baselineFrame();
|
||||
if (jsJitFrame().isBaselineJS()) {
|
||||
jit::BaselineFrame* frame = jsJitFrame().baselineFrame();
|
||||
jit::JitActivation* activation = data_.activations_->asJit();
|
||||
|
||||
// activation's exitFP may be invalid, so create a new
|
||||
@ -1056,13 +1118,13 @@ FrameIter::updatePcQuadratic()
|
||||
++data_.activations_;
|
||||
|
||||
// Look for the current frame.
|
||||
data_.jitFrames_ = jit::JitFrameIterator(data_.activations_);
|
||||
while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame)
|
||||
data_.jitFrames_ = JitFrameIter(data_.activations_->asJit());
|
||||
while (!jsJitFrame().isBaselineJS() || jsJitFrame().baselineFrame() != frame)
|
||||
++data_.jitFrames_;
|
||||
|
||||
// Update the pc.
|
||||
MOZ_ASSERT(data_.jitFrames_.baselineFrame() == frame);
|
||||
data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
|
||||
MOZ_ASSERT(jsJitFrame().baselineFrame() == frame);
|
||||
jsJitFrame().baselineScriptAndPc(nullptr, &data_.pc_);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -1073,17 +1135,16 @@ FrameIter::updatePcQuadratic()
|
||||
void
|
||||
FrameIter::wasmUpdateBytecodeOffset()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(data_.state_ == WASM, "Unexpected state");
|
||||
MOZ_RELEASE_ASSERT(isWasm(), "Unexpected state");
|
||||
|
||||
wasm::DebugFrame* frame = data_.wasmFrames_.debugFrame();
|
||||
WasmActivation* activation = data_.activations_->asWasm();
|
||||
wasm::DebugFrame* frame = wasmFrame().debugFrame();
|
||||
|
||||
// Relookup the current frame, updating the bytecode offset in the process.
|
||||
data_.wasmFrames_ = wasm::WasmFrameIter(activation);
|
||||
while (data_.wasmFrames_.debugFrame() != frame)
|
||||
++data_.wasmFrames_;
|
||||
data_.jitFrames_ = JitFrameIter(data_.activations_->asWasm());
|
||||
while (wasmFrame().debugFrame() != frame)
|
||||
++data_.jitFrames_;
|
||||
|
||||
MOZ_ASSERT(data_.wasmFrames_.debugFrame() == frame);
|
||||
MOZ_ASSERT(wasmFrame().debugFrame() == frame);
|
||||
}
|
||||
|
||||
JSFunction*
|
||||
@ -1091,15 +1152,14 @@ FrameIter::calleeTemplate() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case INTERP:
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
return &interpFrame()->callee();
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return data_.jitFrames_.callee();
|
||||
MOZ_ASSERT(data_.jitFrames_.isIonScripted());
|
||||
if (jsJitFrame().isBaselineJS())
|
||||
return jsJitFrame().callee();
|
||||
MOZ_ASSERT(jsJitFrame().isIonScripted());
|
||||
return ionInlineFrames_.calleeTemplate();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -1110,16 +1170,15 @@ FrameIter::callee(JSContext* cx) const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case INTERP:
|
||||
return calleeTemplate();
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
|
||||
if (isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
|
||||
return ionInlineFrames_.callee(recover);
|
||||
}
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
MOZ_ASSERT(jsJitFrame().isBaselineJS());
|
||||
return calleeTemplate();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
@ -1161,17 +1220,15 @@ FrameIter::numActualArgs() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case INTERP:
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
return interpFrame()->numActualArgs();
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted())
|
||||
if (isIonScripted())
|
||||
return ionInlineFrames_.numActualArgs();
|
||||
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
return data_.jitFrames_.numActualArgs();
|
||||
MOZ_ASSERT(jsJitFrame().isBaselineJS());
|
||||
return jsJitFrame().numActualArgs();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -1195,15 +1252,17 @@ FrameIter::environmentChain(JSContext* cx) const
|
||||
case DONE:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
|
||||
return ionInlineFrames_.environmentChain(recover);
|
||||
if (isJSJit()) {
|
||||
if (isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
|
||||
return ionInlineFrames_.environmentChain(recover);
|
||||
}
|
||||
return jsJitFrame().baselineFrame()->environmentChain();
|
||||
}
|
||||
return data_.jitFrames_.baselineFrame()->environmentChain();
|
||||
MOZ_ASSERT(isWasm());
|
||||
return wasmFrame().debugFrame()->environmentChain();
|
||||
case INTERP:
|
||||
return interpFrame()->environmentChain();
|
||||
case WASM:
|
||||
return data_.wasmFrames_.debugFrame()->environmentChain();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -1239,14 +1298,13 @@ FrameIter::thisArgument(JSContext* cx) const
|
||||
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
|
||||
if (isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &jsJitFrame());
|
||||
return ionInlineFrames_.thisArgument(recover);
|
||||
}
|
||||
return data_.jitFrames_.baselineFrame()->thisArgument();
|
||||
return jsJitFrame().baselineFrame()->thisArgument();
|
||||
case INTERP:
|
||||
return interpFrame()->thisArgument();
|
||||
}
|
||||
@ -1258,13 +1316,12 @@ FrameIter::newTarget() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case INTERP:
|
||||
return interpFrame()->newTarget();
|
||||
case JIT:
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
return data_.jitFrames_.baselineFrame()->newTarget();
|
||||
MOZ_ASSERT(jsJitFrame().isBaselineJS());
|
||||
return jsJitFrame().baselineFrame()->newTarget();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
@ -1274,11 +1331,10 @@ FrameIter::returnValue() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return data_.jitFrames_.baselineFrame()->returnValue();
|
||||
if (jsJitFrame().isBaselineJS())
|
||||
return jsJitFrame().baselineFrame()->returnValue();
|
||||
break;
|
||||
case INTERP:
|
||||
return interpFrame()->returnValue();
|
||||
@ -1291,11 +1347,10 @@ FrameIter::setReturnValue(const Value& v)
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isBaselineJS()) {
|
||||
data_.jitFrames_.baselineFrame()->setReturnValue(v);
|
||||
if (jsJitFrame().isBaselineJS()) {
|
||||
jsJitFrame().baselineFrame()->setReturnValue(v);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -1311,15 +1366,14 @@ FrameIter::numFrameSlots() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT: {
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
if (isIonScripted()) {
|
||||
return ionInlineFrames_.snapshotIterator().numAllocations() -
|
||||
ionInlineFrames_.script()->nfixed();
|
||||
ionInlineFrames_.script()->nfixed();
|
||||
}
|
||||
jit::BaselineFrame* frame = data_.jitFrames_.baselineFrame();
|
||||
return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
|
||||
jit::BaselineFrame* frame = jsJitFrame().baselineFrame();
|
||||
return frame->numValueSlots() - jsJitFrame().script()->nfixed();
|
||||
}
|
||||
case INTERP:
|
||||
MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
|
||||
@ -1333,17 +1387,15 @@ FrameIter::frameSlotValue(size_t index) const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
if (isIonScripted()) {
|
||||
jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
|
||||
index += ionInlineFrames_.script()->nfixed();
|
||||
return si.maybeReadAllocByIndex(index);
|
||||
}
|
||||
|
||||
index += data_.jitFrames_.script()->nfixed();
|
||||
return *data_.jitFrames_.baselineFrame()->valueSlot(index);
|
||||
index += jsJitFrame().script()->nfixed();
|
||||
return *jsJitFrame().baselineFrame()->valueSlot(index);
|
||||
case INTERP:
|
||||
return interpFrame()->base()[index];
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MaybeOneOf.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
@ -1771,6 +1772,86 @@ class WasmActivation : public Activation
|
||||
void unwindExitFP(wasm::Frame* exitFP);
|
||||
};
|
||||
|
||||
// A JitFrameIter can iterate over all kind of frames emitted by our code
|
||||
// generators, be they composed of JS jit frames or wasm frames, interleaved or
|
||||
// not, in any order.
|
||||
//
|
||||
// In the following class:
|
||||
// - code generated for JS is referred to as JSJit.
|
||||
// - code generated for wasm is referred to as Wasm.
|
||||
// Also, Jit refers to any one of them.
|
||||
//
|
||||
// JitFrameIter uses JitFrameIterator to iterate over JSJit code or a
|
||||
// WasmFrameIter to iterate over wasm code; only one of them is active at the
|
||||
// time. When a sub-iterator is done, the JitFrameIter knows how to stop, move
|
||||
// onto the next activation or move onto another kind of Jit code.
|
||||
//
|
||||
// For ease of use, there is also OnlyJSJitFrameIter, which skips all the
|
||||
// non-JSJit frames.
|
||||
//
|
||||
// Note it is allowed to get a handle to the internal frame iterator via
|
||||
// asJSJit() and asWasm(), but the user has to be careful not to have those be
|
||||
// used after JitFrameIter leaves the scope or the operator++ is called.
|
||||
//
|
||||
// TODO(bug 1360211) In particular, this can handle the transition from wasm to
|
||||
// ion and from ion to wasm, since these will be interleaved in the same
|
||||
// JitActivation.
|
||||
class JitFrameIter
|
||||
{
|
||||
protected:
|
||||
mozilla::MaybeOneOf<jit::JitFrameIterator, wasm::WasmFrameIter> iter_;
|
||||
|
||||
public:
|
||||
JitFrameIter() : iter_() {}
|
||||
explicit JitFrameIter(Activation* activation);
|
||||
|
||||
explicit JitFrameIter(const JitFrameIter& another);
|
||||
JitFrameIter& operator=(const JitFrameIter& another);
|
||||
|
||||
bool isSome() const { return !iter_.empty(); }
|
||||
void reset() { MOZ_ASSERT(isSome()); iter_.destroy(); }
|
||||
|
||||
bool isJSJit() const { return isSome() && iter_.constructed<jit::JitFrameIterator>(); }
|
||||
jit::JitFrameIterator& asJSJit() { return iter_.ref<jit::JitFrameIterator>(); }
|
||||
const jit::JitFrameIterator& asJSJit() const { return iter_.ref<jit::JitFrameIterator>(); }
|
||||
|
||||
bool isWasm() const { return isSome() && iter_.constructed<wasm::WasmFrameIter>(); }
|
||||
wasm::WasmFrameIter& asWasm() { return iter_.ref<wasm::WasmFrameIter>(); }
|
||||
const wasm::WasmFrameIter& asWasm() const { return iter_.ref<wasm::WasmFrameIter>(); }
|
||||
|
||||
// Operations common to all frame iterators.
|
||||
bool done() const;
|
||||
void operator++();
|
||||
|
||||
// Operations which have an effect only on JIT frames.
|
||||
void skipNonScriptedJSFrames();
|
||||
};
|
||||
|
||||
// A JitFrameIter that skips all the non-JSJit frames, skipping interleaved
|
||||
// frames of any another kind.
|
||||
|
||||
class OnlyJSJitFrameIter : public JitFrameIter
|
||||
{
|
||||
void settle() {
|
||||
while (!done() && !isJSJit())
|
||||
++(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit OnlyJSJitFrameIter(Activation* act);
|
||||
explicit OnlyJSJitFrameIter(JSContext* cx);
|
||||
explicit OnlyJSJitFrameIter(const ActivationIterator& cx);
|
||||
|
||||
void operator++() {
|
||||
JitFrameIter::operator++();
|
||||
settle();
|
||||
}
|
||||
|
||||
const jit::JitFrameIterator& frame() const {
|
||||
return asJSJit();
|
||||
}
|
||||
};
|
||||
|
||||
// A FrameIter walks over a context's stack of JS script activations,
|
||||
// abstracting over whether the JS scripts were running in the interpreter or
|
||||
// different modes of compiled code.
|
||||
@ -1793,7 +1874,12 @@ class FrameIter
|
||||
public:
|
||||
enum DebuggerEvalOption { FOLLOW_DEBUGGER_EVAL_PREV_LINK,
|
||||
IGNORE_DEBUGGER_EVAL_PREV_LINK };
|
||||
enum State { DONE, INTERP, JIT, WASM };
|
||||
|
||||
enum State {
|
||||
DONE, // when there are no more frames nor activations to unwind.
|
||||
INTERP, // interpreter activation on the stack
|
||||
JIT // jit or wasm activations on the stack
|
||||
};
|
||||
|
||||
// Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
|
||||
// the heap, so this structure should not contain any GC things.
|
||||
@ -1810,9 +1896,8 @@ class FrameIter
|
||||
InterpreterFrameIterator interpFrames_;
|
||||
ActivationIterator activations_;
|
||||
|
||||
jit::JitFrameIterator jitFrames_;
|
||||
JitFrameIter jitFrames_;
|
||||
unsigned ionInlineFrameNo_;
|
||||
wasm::WasmFrameIter wasmFrames_;
|
||||
|
||||
Data(JSContext* cx, DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
|
||||
Data(JSContext* cx, const CooperatingContext& target, DebuggerEvalOption debuggerEvalOption);
|
||||
@ -1838,9 +1923,19 @@ class FrameIter
|
||||
JSCompartment* compartment() const;
|
||||
Activation* activation() const { return data_.activations_.activation(); }
|
||||
|
||||
bool isInterp() const { MOZ_ASSERT(!done()); return data_.state_ == INTERP; }
|
||||
bool isJit() const { MOZ_ASSERT(!done()); return data_.state_ == JIT; }
|
||||
bool isWasm() const { MOZ_ASSERT(!done()); return data_.state_ == WASM; }
|
||||
bool isInterp() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return data_.state_ == INTERP;
|
||||
}
|
||||
bool isJSJit() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return data_.state_ == JIT && data_.jitFrames_.isJSJit();
|
||||
}
|
||||
bool isWasm() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return data_.state_ == JIT && data_.jitFrames_.isWasm();
|
||||
}
|
||||
|
||||
inline bool isIon() const;
|
||||
inline bool isBaseline() const;
|
||||
inline bool isPhysicalIonFrame() const;
|
||||
@ -1953,11 +2048,18 @@ class FrameIter
|
||||
Data data_;
|
||||
jit::InlineFrameIterator ionInlineFrames_;
|
||||
|
||||
const jit::JitFrameIterator& jsJitFrame() const { return data_.jitFrames_.asJSJit(); }
|
||||
const wasm::WasmFrameIter& wasmFrame() const { return data_.jitFrames_.asWasm(); }
|
||||
|
||||
jit::JitFrameIterator& jsJitFrame() { return data_.jitFrames_.asJSJit(); }
|
||||
wasm::WasmFrameIter& wasmFrame() { return data_.jitFrames_.asWasm(); }
|
||||
|
||||
bool isIonScripted() const { return isJSJit() && jsJitFrame().isIonScripted(); }
|
||||
|
||||
void popActivation();
|
||||
void popInterpreterFrame();
|
||||
void nextJitFrame();
|
||||
void popJitFrame();
|
||||
void popWasmFrame();
|
||||
void settleOnActivation();
|
||||
};
|
||||
|
||||
@ -2118,48 +2220,48 @@ inline JSScript*
|
||||
FrameIter::script() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(hasScript());
|
||||
if (data_.state_ == INTERP)
|
||||
return interpFrame()->script();
|
||||
MOZ_ASSERT(data_.state_ == JIT);
|
||||
if (data_.jitFrames_.isIonJS())
|
||||
if (jsJitFrame().isIonJS())
|
||||
return ionInlineFrames_.script();
|
||||
return data_.jitFrames_.script();
|
||||
return jsJitFrame().script();
|
||||
}
|
||||
|
||||
inline bool
|
||||
FrameIter::wasmDebugEnabled() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(data_.state_ == WASM);
|
||||
return data_.wasmFrames_.debugEnabled();
|
||||
MOZ_ASSERT(isWasm());
|
||||
return wasmFrame().debugEnabled();
|
||||
}
|
||||
|
||||
inline wasm::Instance*
|
||||
FrameIter::wasmInstance() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(data_.state_ == WASM && wasmDebugEnabled());
|
||||
return data_.wasmFrames_.instance();
|
||||
MOZ_ASSERT(isWasm() && wasmDebugEnabled());
|
||||
return wasmFrame().instance();
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
FrameIter::wasmBytecodeOffset() const
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(data_.state_ == WASM);
|
||||
return data_.wasmFrames_.lineOrBytecode();
|
||||
MOZ_ASSERT(isWasm());
|
||||
return wasmFrame().lineOrBytecode();
|
||||
}
|
||||
|
||||
inline bool
|
||||
FrameIter::isIon() const
|
||||
{
|
||||
return isJit() && data_.jitFrames_.isIonJS();
|
||||
return isJSJit() && jsJitFrame().isIonJS();
|
||||
}
|
||||
|
||||
inline bool
|
||||
FrameIter::isBaseline() const
|
||||
{
|
||||
return isJit() && data_.jitFrames_.isBaselineJS();
|
||||
return isJSJit() && jsJitFrame().isBaselineJS();
|
||||
}
|
||||
|
||||
inline InterpreterFrame*
|
||||
@ -2172,8 +2274,8 @@ FrameIter::interpFrame() const
|
||||
inline bool
|
||||
FrameIter::isPhysicalIonFrame() const
|
||||
{
|
||||
return isJit() &&
|
||||
data_.jitFrames_.isIonScripted() &&
|
||||
return isJSJit() &&
|
||||
jsJitFrame().isIonScripted() &&
|
||||
ionInlineFrames_.frameNo() == 0;
|
||||
}
|
||||
|
||||
@ -2181,7 +2283,7 @@ inline jit::CommonFrameLayout*
|
||||
FrameIter::physicalIonFrame() const
|
||||
{
|
||||
MOZ_ASSERT(isPhysicalIonFrame());
|
||||
return data_.jitFrames_.current();
|
||||
return jsJitFrame().current();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -260,16 +260,16 @@ TraceLoggerThread::enable(JSContext* cx)
|
||||
int32_t engine = 0;
|
||||
|
||||
if (act->isJit()) {
|
||||
JitFrameIterator it(iter);
|
||||
JitFrameIterator frame(iter->asJit());
|
||||
|
||||
while (!it.isScripted() && !it.done())
|
||||
++it;
|
||||
while (!frame.isScripted() && !frame.done())
|
||||
++frame;
|
||||
|
||||
MOZ_ASSERT(!it.done());
|
||||
MOZ_ASSERT(it.isIonJS() || it.isBaselineJS());
|
||||
MOZ_ASSERT(!frame.done());
|
||||
MOZ_ASSERT(frame.isIonJS() || frame.isBaselineJS());
|
||||
|
||||
script = it.script();
|
||||
engine = it.isIonJS() ? TraceLogger_IonMonkey : TraceLogger_Baseline;
|
||||
script = frame.script();
|
||||
engine = frame.isIonJS() ? TraceLogger_IonMonkey : TraceLogger_Baseline;
|
||||
} else if (act->isWasm()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TRACELOGGER_ENABLE_FAIL,
|
||||
"not yet supported in wasm code");
|
||||
|
@ -102,18 +102,18 @@ WasmHandleDebugTrap()
|
||||
MOZ_ASSERT(activation);
|
||||
JSContext* cx = activation->cx();
|
||||
|
||||
WasmFrameIter iter(activation);
|
||||
MOZ_ASSERT(iter.debugEnabled());
|
||||
const CallSite* site = iter.debugTrapCallsite();
|
||||
WasmFrameIter frame(activation);
|
||||
MOZ_ASSERT(frame.debugEnabled());
|
||||
const CallSite* site = frame.debugTrapCallsite();
|
||||
MOZ_ASSERT(site);
|
||||
if (site->kind() == CallSite::EnterFrame) {
|
||||
if (!iter.instance()->enterFrameTrapsEnabled())
|
||||
if (!frame.instance()->enterFrameTrapsEnabled())
|
||||
return true;
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
frame->setIsDebuggee();
|
||||
frame->observe(cx);
|
||||
DebugFrame* debugFrame = frame.debugFrame();
|
||||
debugFrame->setIsDebuggee();
|
||||
debugFrame->observe(cx);
|
||||
// TODO call onEnterFrame
|
||||
JSTrapStatus status = Debugger::onEnterFrame(cx, frame);
|
||||
JSTrapStatus status = Debugger::onEnterFrame(cx, debugFrame);
|
||||
if (status == JSTRAP_RETURN) {
|
||||
// Ignoring forced return (JSTRAP_RETURN) -- changing code execution
|
||||
// order is not yet implemented in the wasm baseline.
|
||||
@ -124,17 +124,17 @@ WasmHandleDebugTrap()
|
||||
return status == JSTRAP_CONTINUE;
|
||||
}
|
||||
if (site->kind() == CallSite::LeaveFrame) {
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
frame->updateReturnJSValue();
|
||||
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
|
||||
frame->leave(cx);
|
||||
DebugFrame* debugFrame = frame.debugFrame();
|
||||
debugFrame->updateReturnJSValue();
|
||||
bool ok = Debugger::onLeaveFrame(cx, debugFrame, nullptr, true);
|
||||
debugFrame->leave(cx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
DebugFrame* frame = iter.debugFrame();
|
||||
DebugState& debug = iter.instance()->debug();
|
||||
DebugFrame* debugFrame = frame.debugFrame();
|
||||
DebugState& debug = frame.instance()->debug();
|
||||
MOZ_ASSERT(debug.hasBreakpointTrapAtOffset(site->lineOrBytecode()));
|
||||
if (debug.stepModeEnabled(frame->funcIndex())) {
|
||||
if (debug.stepModeEnabled(debugFrame->funcIndex())) {
|
||||
RootedValue result(cx, UndefinedValue());
|
||||
JSTrapStatus status = Debugger::onSingleStep(cx, &result);
|
||||
if (status == JSTRAP_RETURN) {
|
||||
@ -176,6 +176,11 @@ WasmHandleThrow()
|
||||
// DebugFrame from being observed again after we just called onLeaveFrame
|
||||
// (which would lead to the frame being re-added to the map of live frames,
|
||||
// right as it becomes trash).
|
||||
//
|
||||
// TODO(bug 1360211): when JitActivation and WasmActivation get merged,
|
||||
// we'll be able to switch to ion / other wasm state from here, and we'll
|
||||
// need to do things differently.
|
||||
|
||||
WasmFrameIter iter(activation, WasmFrameIter::Unwind::True);
|
||||
MOZ_ASSERT(!iter.done());
|
||||
|
||||
|
@ -32,18 +32,6 @@ using mozilla::Swap;
|
||||
/*****************************************************************************/
|
||||
// WasmFrameIter implementation
|
||||
|
||||
WasmFrameIter::WasmFrameIter()
|
||||
: activation_(nullptr),
|
||||
code_(nullptr),
|
||||
callsite_(nullptr),
|
||||
codeRange_(nullptr),
|
||||
fp_(nullptr),
|
||||
unwind_(Unwind::False),
|
||||
unwoundAddressOfReturnAddress_(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(done());
|
||||
}
|
||||
|
||||
WasmFrameIter::WasmFrameIter(WasmActivation* activation, Unwind unwind)
|
||||
: activation_(activation),
|
||||
code_(nullptr),
|
||||
@ -95,7 +83,7 @@ WasmFrameIter::operator++()
|
||||
{
|
||||
MOZ_ASSERT(!done());
|
||||
|
||||
// When the iterator is set to Unwind::True, each time the iterator pops a
|
||||
// When the iterator is set to unwind, each time the iterator pops a
|
||||
// frame, the WasmActivation is updated so that the just-popped frame
|
||||
// is no longer visible. This is necessary since Debugger::onLeaveFrame is
|
||||
// called before popping each frame and, once onLeaveFrame is called for a
|
||||
@ -1004,17 +992,6 @@ ProfilingFrameIterator::label() const
|
||||
MOZ_CRASH("bad code range kind");
|
||||
}
|
||||
|
||||
void
|
||||
wasm::TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc)
|
||||
{
|
||||
for (ActivationIterator iter(cx, target); !iter.done(); ++iter) {
|
||||
if (iter.activation()->isWasm()) {
|
||||
for (WasmFrameIter fi(iter.activation()->asWasm()); !fi.done(); ++fi)
|
||||
fi.instance()->trace(trc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Instance*
|
||||
wasm::LookupFaultingInstance(WasmActivation* activation, void* pc, void* fp)
|
||||
{
|
||||
|
@ -41,14 +41,19 @@ struct Frame;
|
||||
struct FuncOffsets;
|
||||
struct CallableOffsets;
|
||||
|
||||
// Iterates over the frames of a single WasmActivation, called synchronously
|
||||
// from C++ in the thread of the asm.js.
|
||||
// Iterates over a linear group of wasm frames of a single WasmActivation,
|
||||
// called synchronously from C++ in the wasm thread. It will stop at the first
|
||||
// frame that is not of the same kind, or at the end of an activation.
|
||||
//
|
||||
// If you want to handle every kind of frames (including JS jit frames), use
|
||||
// JitFrameIter.
|
||||
//
|
||||
// The one exception is that this iterator may be called from the interrupt
|
||||
// callback which may be called asynchronously from asm.js code; in this case,
|
||||
// the backtrace may not be correct. That being said, we try our best printing
|
||||
// an informative message to the user and at least the name of the innermost
|
||||
// function stack frame.
|
||||
|
||||
class WasmFrameIter
|
||||
{
|
||||
public:
|
||||
@ -66,7 +71,7 @@ class WasmFrameIter
|
||||
void popFrame();
|
||||
|
||||
public:
|
||||
explicit WasmFrameIter();
|
||||
// See comment above this class definition.
|
||||
explicit WasmFrameIter(WasmActivation* activation, Unwind unwind = Unwind::False);
|
||||
void operator++();
|
||||
bool done() const;
|
||||
@ -184,11 +189,6 @@ GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const
|
||||
void
|
||||
GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
|
||||
|
||||
// Mark all instance objects live on the stack.
|
||||
|
||||
void
|
||||
TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
|
||||
|
||||
// Given a fault at pc with register fp, return the faulting instance if there
|
||||
// is such a plausible instance, and otherwise null.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user