mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1150783 - Use a special JitFrame to record when LazyLink stubs are on the stack. r=h4writer
This commit is contained in:
parent
d6c76e96a1
commit
5432be44a0
34
js/src/jit-test/tests/ion/lazyLink-bug1150783.js
Normal file
34
js/src/jit-test/tests/ion/lazyLink-bug1150783.js
Normal file
@ -0,0 +1,34 @@
|
||||
var path = '';
|
||||
|
||||
// trigger off-main-thread compilation
|
||||
for (var i = 0; i < 11; i++)
|
||||
path.substr(-1);
|
||||
|
||||
// maybe link to the the result of the off-main-thread compilation.
|
||||
function load(unsigned) {
|
||||
if (unsigned)
|
||||
path.substr(-1);
|
||||
}
|
||||
|
||||
(function(global, env) {
|
||||
'use asm';
|
||||
var load = env.load;
|
||||
function _main() {
|
||||
var $l1 = 0, $l2 = 0, $l3 = 0;
|
||||
do {
|
||||
load();
|
||||
$l1 = $l1 + 1 | 0;
|
||||
} while (($l1 | 0) != 10);
|
||||
load(1);
|
||||
load(1);
|
||||
do {
|
||||
load();
|
||||
$l2 = $l2 + 1 | 0;
|
||||
} while (($l2 | 0) != 1024);
|
||||
while (($l3 | 0) < 10000) {
|
||||
load(1);
|
||||
$l3 = $l3 + 1 | 0;
|
||||
}
|
||||
}
|
||||
return _main;
|
||||
})({}, { 'load':load })();
|
@ -436,10 +436,32 @@ FinishAllOffThreadCompilations(JSCompartment* comp)
|
||||
}
|
||||
}
|
||||
|
||||
class AutoLazyLinkExitFrame
|
||||
{
|
||||
JitActivation* jitActivation_;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
||||
public:
|
||||
explicit AutoLazyLinkExitFrame(JitActivation* jitActivation
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: jitActivation_(jitActivation)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
MOZ_ASSERT(!jitActivation_->isLazyLinkExitFrame(),
|
||||
"Cannot stack multiple lazy-link frames.");
|
||||
jitActivation_->setLazyLinkExitFrame(true);
|
||||
}
|
||||
|
||||
~AutoLazyLinkExitFrame() {
|
||||
jitActivation_->setLazyLinkExitFrame(false);
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t*
|
||||
jit::LazyLinkTopActivation(JSContext* cx)
|
||||
{
|
||||
JitActivationIterator iter(cx->runtime());
|
||||
AutoLazyLinkExitFrame lazyLinkExitFrame(iter->asJit());
|
||||
|
||||
// First frame should be an exit frame.
|
||||
JitFrameIterator it(iter);
|
||||
@ -2499,11 +2521,12 @@ 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.type() == JitFrame_Exit || it.type() == JitFrame_Bailout);
|
||||
MOZ_ASSERT_IF(frameno == 1, it.isExitFrame() || it.type() == JitFrame_Bailout);
|
||||
|
||||
#ifdef DEBUG
|
||||
switch (it.type()) {
|
||||
case JitFrame_Exit:
|
||||
case JitFrame_LazyLink:
|
||||
JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp());
|
||||
break;
|
||||
case JitFrame_BaselineJS:
|
||||
|
@ -476,7 +476,8 @@ static void*
|
||||
GetReturnAddressToIonCode(JSContext* cx)
|
||||
{
|
||||
JitFrameIterator iter(cx);
|
||||
MOZ_ASSERT(iter.type() == JitFrame_Exit);
|
||||
MOZ_ASSERT(iter.type() == JitFrame_Exit,
|
||||
"An exit frame is expected as update functions are called with a VMFunction.");
|
||||
|
||||
void* returnAddr = iter.returnAddress();
|
||||
#ifdef DEBUG
|
||||
|
@ -40,7 +40,7 @@ template <typename T>
|
||||
bool
|
||||
JitFrameIterator::isExitFrameLayout() const
|
||||
{
|
||||
if (type_ != JitFrame_Exit || isFakeExitFrame())
|
||||
if (!isExitFrame() || isFakeExitFrame())
|
||||
return false;
|
||||
return exitFrame()->is<T>();
|
||||
}
|
||||
|
@ -65,7 +65,14 @@ enum FrameType
|
||||
// the reconstruction of the BaselineJS frame. From within C++, a bailout
|
||||
// frame is always the last frame in a JitActivation iff the bailout frame
|
||||
// information is recorded on the JitActivation.
|
||||
JitFrame_Bailout
|
||||
JitFrame_Bailout,
|
||||
|
||||
// A lazy link frame is a special exit frame where a IonJS frame is reused
|
||||
// for linking the newly compiled code. A special frame is needed to
|
||||
// work-around the fact that we can make stack patterns which are similar to
|
||||
// unwound frames. As opposed to unwound frames, we still have to mark all
|
||||
// the arguments of the original IonJS frame.
|
||||
JitFrame_LazyLink
|
||||
};
|
||||
|
||||
enum ReadFrameArgsBehavior {
|
||||
@ -142,6 +149,9 @@ class JitFrameIterator
|
||||
bool checkInvalidation(IonScript** ionScript) const;
|
||||
bool checkInvalidation() const;
|
||||
|
||||
bool isExitFrame() const {
|
||||
return type_ == JitFrame_Exit || type_ == JitFrame_LazyLink;
|
||||
}
|
||||
bool isScripted() const {
|
||||
return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
|
||||
}
|
||||
@ -198,7 +208,7 @@ class JitFrameIterator
|
||||
// Returns the stack space used by the current frame, in bytes. This does
|
||||
// not include the size of its fixed header.
|
||||
size_t frameSize() const {
|
||||
MOZ_ASSERT(type_ != JitFrame_Exit);
|
||||
MOZ_ASSERT(!isExitFrame());
|
||||
return frameSize_;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,8 @@ JitFrameIterator::prevType() const
|
||||
inline bool
|
||||
JitFrameIterator::isFakeExitFrame() const
|
||||
{
|
||||
if (type() == JitFrame_LazyLink)
|
||||
return false;
|
||||
bool res = (prevType() == JitFrame_Unwound_Rectifier ||
|
||||
prevType() == JitFrame_Unwound_IonJS ||
|
||||
prevType() == JitFrame_Unwound_BaselineJS ||
|
||||
@ -64,7 +66,7 @@ JitFrameIterator::isFakeExitFrame() const
|
||||
inline ExitFrameLayout*
|
||||
JitFrameIterator::exitFrame() const
|
||||
{
|
||||
MOZ_ASSERT(type() == JitFrame_Exit);
|
||||
MOZ_ASSERT(isExitFrame());
|
||||
MOZ_ASSERT(!isFakeExitFrame());
|
||||
return (ExitFrameLayout*) fp();
|
||||
}
|
||||
|
@ -117,6 +117,9 @@ JitFrameIterator::JitFrameIterator(JSContext* cx)
|
||||
current_ = activation_->bailoutData()->fp();
|
||||
frameSize_ = activation_->bailoutData()->topFrameSize();
|
||||
type_ = JitFrame_Bailout;
|
||||
} else if (activation_->isLazyLinkExitFrame()) {
|
||||
type_ = JitFrame_LazyLink;
|
||||
MOZ_ASSERT(isExitFrameLayout<LazyLinkExitFrameLayout>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +135,9 @@ JitFrameIterator::JitFrameIterator(const ActivationIterator& activations)
|
||||
current_ = activation_->bailoutData()->fp();
|
||||
frameSize_ = activation_->bailoutData()->topFrameSize();
|
||||
type_ = JitFrame_Bailout;
|
||||
} else if (activation_->isLazyLinkExitFrame()) {
|
||||
type_ = JitFrame_LazyLink;
|
||||
MOZ_ASSERT(isExitFrameLayout<LazyLinkExitFrameLayout>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,6 +270,7 @@ SizeOfFramePrefix(FrameType type)
|
||||
case JitFrame_Unwound_Rectifier:
|
||||
return IonUnwoundRectifierFrameLayout::Size();
|
||||
case JitFrame_Exit:
|
||||
case JitFrame_LazyLink:
|
||||
return ExitFrameLayout::Size();
|
||||
case JitFrame_IonAccessorIC:
|
||||
case JitFrame_Unwound_IonAccessorIC:
|
||||
@ -957,6 +964,7 @@ EnsureExitFrame(CommonFrameLayout* frame)
|
||||
|
||||
case JitFrame_Exit:
|
||||
case JitFrame_Bailout:
|
||||
case JitFrame_LazyLink:
|
||||
// Fall-through to MOZ_CRASH below.
|
||||
break;
|
||||
}
|
||||
@ -1495,6 +1503,7 @@ MarkJitActivation(JSTracer* trc, const JitActivationIterator& activations)
|
||||
for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
|
||||
switch (frames.type()) {
|
||||
case JitFrame_Exit:
|
||||
case JitFrame_LazyLink:
|
||||
MarkJitExitFrame(trc, frames);
|
||||
break;
|
||||
case JitFrame_BaselineJS:
|
||||
@ -1569,7 +1578,7 @@ GetPcScript(JSContext* cx, JSScript** scriptRes, jsbytecode** pcRes)
|
||||
JitActivationIterator iter(rt);
|
||||
JitFrameIterator it(iter);
|
||||
uint8_t* retAddr;
|
||||
if (it.type() == JitFrame_Exit) {
|
||||
if (it.isExitFrame()) {
|
||||
++it;
|
||||
|
||||
// Skip rectifier frames.
|
||||
@ -2771,6 +2780,7 @@ JitFrameIterator::dump() const
|
||||
fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
|
||||
break;
|
||||
case JitFrame_Exit:
|
||||
case JitFrame_LazyLink:
|
||||
break;
|
||||
};
|
||||
fputc('\n', stderr);
|
||||
@ -3219,7 +3229,7 @@ AssertJitStackInvariants(JSContext* cx)
|
||||
"The frame size is optimal");
|
||||
}
|
||||
|
||||
if (frames.type() == JitFrame_Exit) {
|
||||
if (frames.isExitFrame()) {
|
||||
// For the moment, we do not keep the JitStackAlignment
|
||||
// alignment for exit frames.
|
||||
frameSize -= ExitFrameLayout::Size();
|
||||
|
@ -1391,6 +1391,7 @@ AbstractFramePtr::hasPushedSPSFrame() const
|
||||
jit::JitActivation::JitActivation(JSContext* cx, bool active)
|
||||
: Activation(cx, Jit),
|
||||
active_(active),
|
||||
isLazyLinkExitFrame_(false),
|
||||
rematerializedFrames_(nullptr),
|
||||
ionRecovery_(cx),
|
||||
bailoutData_(nullptr),
|
||||
|
@ -1286,6 +1286,15 @@ class JitActivation : public Activation
|
||||
JSContext* prevJitJSContext_;
|
||||
bool active_;
|
||||
|
||||
// The lazy link stub reuse the frame pushed for calling a function as an
|
||||
// exit frame. In a few cases, such as after calls from asm.js, we might
|
||||
// have an entry frame followed by an exit frame. This pattern can be
|
||||
// assimilated as a fake exit frame (unwound frame), in which case we skip
|
||||
// marking during a GC. To ensure that we do mark the stack as expected we
|
||||
// have to keep a flag set by the LazyLink VM function to safely mark the
|
||||
// stack if a GC happens during the link phase.
|
||||
bool isLazyLinkExitFrame_;
|
||||
|
||||
// Rematerialized Ion frames which has info copied out of snapshots. Maps
|
||||
// frame pointers (i.e. jitTop) to a vector of rematerializations of all
|
||||
// inline frames associated with that frame.
|
||||
@ -1417,6 +1426,14 @@ class JitActivation : public Activation
|
||||
// Unregister the bailout data when the frame is reconstructed.
|
||||
void cleanBailoutData();
|
||||
|
||||
// Return the bailout information if it is registered.
|
||||
bool isLazyLinkExitFrame() const { return isLazyLinkExitFrame_; }
|
||||
|
||||
// Register the bailout data when it is constructed.
|
||||
void setLazyLinkExitFrame(bool isExitFrame) {
|
||||
isLazyLinkExitFrame_ = isExitFrame;
|
||||
}
|
||||
|
||||
static size_t offsetOfLastProfilingFrame() {
|
||||
return offsetof(JitActivation, lastProfilingFrame_);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user