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:
Benjamin Bouvier 2017-08-16 16:37:31 +02:00
Родитель ec1a805248
Коммит 7d316d6f96
31 изменённых файлов: 647 добавлений и 499 удалений

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

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