mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1073033 part 2.1 - InlineFrameIterator: Recover the non-default value of a function. r=shu
This commit is contained in:
parent
0de4913caf
commit
600518974a
@ -498,26 +498,20 @@ class SnapshotIterator
|
||||
// provides a |Default| value. This is useful to avoid invalidations of the
|
||||
// frame while we are only interested in a few properties which are provided
|
||||
// by the |Default| value.
|
||||
Value readWithDefault() {
|
||||
return allocationValue(readAllocation(), RM_NormalOrDefault);
|
||||
}
|
||||
|
||||
Value maybeRead(MaybeReadFallback &fallback) {
|
||||
Value readWithDefault(RValueAllocation *alloc) {
|
||||
*alloc = RValueAllocation();
|
||||
RValueAllocation a = readAllocation();
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
|
||||
if (fallback.canRecoverResults()) {
|
||||
if (!initInstructionResults(fallback))
|
||||
js::CrashAtUnhandlableOOM("Unable to recover allocations.");
|
||||
*alloc = a;
|
||||
return allocationValue(a, RM_AlwaysDefault);
|
||||
}
|
||||
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("All allocations should be readable.");
|
||||
}
|
||||
|
||||
return fallback.unreadablePlaceholder();
|
||||
Value maybeRead(const RValueAllocation &a, MaybeReadFallback &fallback);
|
||||
Value maybeRead(MaybeReadFallback &fallback) {
|
||||
RValueAllocation a = readAllocation();
|
||||
return maybeRead(a, fallback);
|
||||
}
|
||||
|
||||
void traceAllocation(JSTracer *trc);
|
||||
@ -596,7 +590,16 @@ class InlineFrameIterator
|
||||
// frames contained in the recover buffer.
|
||||
uint32_t frameCount_;
|
||||
|
||||
RootedFunction callee_;
|
||||
// The |calleeTemplate_| fields contains either the JSFunction or the
|
||||
// template from which it is supposed to be cloned. The |calleeRVA_| is an
|
||||
// Invalid value allocation, if the |calleeTemplate_| field is the effective
|
||||
// JSFunction, and not its template. On the other hand, any other value
|
||||
// allocation implies that the |calleeTemplate_| is the template JSFunction
|
||||
// from which the effective one would be derived and cached by the Recover
|
||||
// instruction result.
|
||||
RootedFunction calleeTemplate_;
|
||||
RValueAllocation calleeRVA_;
|
||||
|
||||
RootedScript script_;
|
||||
jsbytecode *pc_;
|
||||
uint32_t numActualArgs_;
|
||||
@ -617,14 +620,24 @@ class InlineFrameIterator
|
||||
bool more() const {
|
||||
return frame_ && framesRead_ < frameCount_;
|
||||
}
|
||||
JSFunction *callee() const {
|
||||
MOZ_ASSERT(callee_);
|
||||
return callee_;
|
||||
|
||||
// Due to optimizations, we are not always capable of reading the callee of
|
||||
// inlined frames without invalidating the IonCode. This function might
|
||||
// return either the effective callee of the JSFunction which might be used
|
||||
// to create it.
|
||||
//
|
||||
// As such, the |calleeTemplate()| can be used to read most of the metadata
|
||||
// which are conserved across clones.
|
||||
JSFunction *calleeTemplate() const {
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
return calleeTemplate_;
|
||||
}
|
||||
JSFunction *maybeCallee() const {
|
||||
return callee_;
|
||||
JSFunction *maybeCalleeTemplate() const {
|
||||
return calleeTemplate_;
|
||||
}
|
||||
|
||||
JSFunction *callee(MaybeReadFallback &fallback) const;
|
||||
|
||||
unsigned numActualArgs() const {
|
||||
// The number of actual arguments of inline frames is recovered by the
|
||||
// iteration process. It is recovered from the bytecode because this
|
||||
|
@ -1900,6 +1900,25 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc, ReadMethod rm)
|
||||
}
|
||||
}
|
||||
|
||||
Value
|
||||
SnapshotIterator::maybeRead(const RValueAllocation &a, MaybeReadFallback &fallback)
|
||||
{
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
|
||||
if (fallback.canRecoverResults()) {
|
||||
if (!initInstructionResults(fallback))
|
||||
js::CrashAtUnhandlableOOM("Unable to recover allocations.");
|
||||
|
||||
if (allocationReadable(a))
|
||||
return allocationValue(a);
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("All allocations should be readable.");
|
||||
}
|
||||
|
||||
return fallback.unreadablePlaceholder();
|
||||
}
|
||||
|
||||
void
|
||||
SnapshotIterator::writeAllocationValuePayload(const RValueAllocation &alloc, Value v)
|
||||
{
|
||||
@ -2232,14 +2251,16 @@ JitFrameIterator::osiIndex() const
|
||||
}
|
||||
|
||||
InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter)
|
||||
: callee_(cx),
|
||||
: calleeTemplate_(cx),
|
||||
calleeRVA_(),
|
||||
script_(cx)
|
||||
{
|
||||
resetOn(iter);
|
||||
}
|
||||
|
||||
InlineFrameIterator::InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter)
|
||||
: callee_(rt),
|
||||
: calleeTemplate_(rt),
|
||||
calleeRVA_(),
|
||||
script_(rt)
|
||||
{
|
||||
resetOn(iter);
|
||||
@ -2249,7 +2270,8 @@ InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const InlineFram
|
||||
: frame_(iter ? iter->frame_ : nullptr),
|
||||
framesRead_(0),
|
||||
frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
|
||||
callee_(cx),
|
||||
calleeTemplate_(cx),
|
||||
calleeRVA_(),
|
||||
script_(cx)
|
||||
{
|
||||
if (frame_) {
|
||||
@ -2283,7 +2305,8 @@ InlineFrameIterator::findNextFrame()
|
||||
si_ = start_;
|
||||
|
||||
// Read the initial frame out of the C stack.
|
||||
callee_ = frame_->maybeCallee();
|
||||
calleeTemplate_ = frame_->maybeCallee();
|
||||
calleeRVA_ = RValueAllocation();
|
||||
script_ = frame_->script();
|
||||
MOZ_ASSERT(script_->hasBaselineScript());
|
||||
|
||||
@ -2332,7 +2355,7 @@ InlineFrameIterator::findNextFrame()
|
||||
// the time, these functions are stored as JSFunction constants,
|
||||
// register which are holding the JSFunction pointer, or recover
|
||||
// instruction with Default value.
|
||||
Value funval = si_.readWithDefault();
|
||||
Value funval = si_.readWithDefault(&calleeRVA_);
|
||||
|
||||
// Skip extra value allocations.
|
||||
while (si_.moreAllocations())
|
||||
@ -2340,12 +2363,12 @@ InlineFrameIterator::findNextFrame()
|
||||
|
||||
si_.nextFrame();
|
||||
|
||||
callee_ = &funval.toObject().as<JSFunction>();
|
||||
calleeTemplate_ = &funval.toObject().as<JSFunction>();
|
||||
|
||||
// Inlined functions may be clones that still point to the lazy script
|
||||
// for the executed script, if they are clones. The actual script
|
||||
// exists though, just make sure the function points to it.
|
||||
script_ = callee_->existingScriptForInlinedFunction();
|
||||
script_ = calleeTemplate_->existingScriptForInlinedFunction();
|
||||
MOZ_ASSERT(script_->hasBaselineScript());
|
||||
|
||||
pc_ = script_->offsetToPC(si_.pcOffset());
|
||||
@ -2362,6 +2385,19 @@ InlineFrameIterator::findNextFrame()
|
||||
framesRead_++;
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
InlineFrameIterator::callee(MaybeReadFallback &fallback) const
|
||||
{
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
if (calleeRVA_.mode() == RValueAllocation::INVALID || !fallback.canRecoverResults())
|
||||
return calleeTemplate_;
|
||||
|
||||
SnapshotIterator s(si_);
|
||||
// :TODO: Handle allocation failures from recover instruction.
|
||||
Value funval = s.maybeRead(calleeRVA_, fallback);
|
||||
return &funval.toObject().as<JSFunction>();
|
||||
}
|
||||
|
||||
JSObject *
|
||||
InlineFrameIterator::computeScopeChain(Value scopeChainValue, bool *hasCallObj) const
|
||||
{
|
||||
@ -2386,7 +2422,7 @@ InlineFrameIterator::computeScopeChain(Value scopeChainValue, bool *hasCallObj)
|
||||
bool
|
||||
InlineFrameIterator::isFunctionFrame() const
|
||||
{
|
||||
return !!callee_;
|
||||
return !!calleeTemplate_;
|
||||
}
|
||||
|
||||
MachineState
|
||||
|
@ -1999,6 +1999,14 @@ js::NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobjArg, Native na
|
||||
return fun;
|
||||
}
|
||||
|
||||
bool
|
||||
js::CloneFunctionObjectUseSameScript(JSCompartment *compartment, HandleFunction fun)
|
||||
{
|
||||
return compartment == fun->compartment() &&
|
||||
!fun->hasSingletonType() &&
|
||||
!types::UseNewTypeForClone(fun);
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
js::CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, gc::AllocKind allocKind,
|
||||
NewObjectKind newKindArg /* = GenericObject */)
|
||||
@ -2006,9 +2014,7 @@ js::CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
|
||||
MOZ_ASSERT(parent);
|
||||
MOZ_ASSERT(!fun->isBoundFunction());
|
||||
|
||||
bool useSameScript = cx->compartment() == fun->compartment() &&
|
||||
!fun->hasSingletonType() &&
|
||||
!types::UseNewTypeForClone(fun);
|
||||
bool useSameScript = CloneFunctionObjectUseSameScript(cx->compartment(), fun);
|
||||
|
||||
if (!useSameScript && fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
|
||||
return nullptr;
|
||||
|
@ -55,7 +55,9 @@ class JSFunction : public js::NativeObject
|
||||
ASMJS_CTOR = ASMJS | NATIVE_CTOR,
|
||||
ASMJS_LAMBDA_CTOR = ASMJS | NATIVE_CTOR | LAMBDA,
|
||||
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
|
||||
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW
|
||||
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW,
|
||||
STABLE_ACROSS_CLONES = NATIVE_CTOR | IS_FUN_PROTO | EXPR_CLOSURE | HAS_GUESSED_ATOM |
|
||||
LAMBDA | SELF_HOSTED | SELF_HOSTED_CTOR | HAS_REST | ASMJS | ARROW
|
||||
};
|
||||
|
||||
static_assert(INTERPRETED == JS_FUNCTION_INTERPRETED_BIT,
|
||||
@ -578,6 +580,9 @@ class FunctionExtended : public JSFunction
|
||||
HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
|
||||
};
|
||||
|
||||
extern bool
|
||||
CloneFunctionObjectUseSameScript(JSCompartment *compartment, HandleFunction fun);
|
||||
|
||||
extern JSFunction *
|
||||
CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
|
||||
gc::AllocKind kind = JSFunction::FinalizeKind,
|
||||
|
@ -1062,7 +1062,7 @@ FrameIter::updatePcQuadratic()
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
FrameIter::callee() const
|
||||
FrameIter::calleeTemplate() const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
@ -1075,27 +1075,63 @@ FrameIter::callee() const
|
||||
if (data_.jitFrames_.isBaselineJS())
|
||||
return data_.jitFrames_.callee();
|
||||
MOZ_ASSERT(data_.jitFrames_.isIonScripted());
|
||||
return ionInlineFrames_.callee();
|
||||
return ionInlineFrames_.calleeTemplate();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
|
||||
Value
|
||||
FrameIter::calleev() const
|
||||
JSFunction *
|
||||
FrameIter::callee(JSContext *cx) const
|
||||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case ASMJS:
|
||||
break;
|
||||
case INTERP:
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
return interpFrame()->calleev();
|
||||
return calleeTemplate();
|
||||
case JIT:
|
||||
return ObjectValue(*callee());
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
|
||||
return ionInlineFrames_.callee(recover);
|
||||
}
|
||||
MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
|
||||
return calleeTemplate();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
|
||||
bool
|
||||
FrameIter::matchCallee(JSContext *cx, HandleFunction fun) const
|
||||
{
|
||||
RootedFunction currentCallee(cx, calleeTemplate());
|
||||
|
||||
// As we do not know if the calleeTemplate is the real function, or the
|
||||
// template from which it would be cloned, we compare properties which are
|
||||
// stable across the cloning of JSFunctions.
|
||||
if (((currentCallee->flags() ^ fun->flags()) & JSFunction::STABLE_ACROSS_CLONES) != 0 ||
|
||||
currentCallee->nargs() != fun->nargs())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only some lambdas are optimized in a way which cannot be recovered without
|
||||
// invalidating the frame. Thus, if one of the function is not a lambda we can just
|
||||
// compare it against the calleeTemplate.
|
||||
if (!fun->isLambda() || !currentCallee->isLambda())
|
||||
return currentCallee == fun;
|
||||
|
||||
// Use the same condition as |js::CloneFunctionObject|, to know if we should
|
||||
// expect both functions to have the same JSScript. If so, and if they are
|
||||
// different, then they cannot be equal.
|
||||
bool useSameScript = CloneFunctionObjectUseSameScript(fun->compartment(), currentCallee);
|
||||
if (useSameScript && currentCallee->nonLazyScript() != fun->nonLazyScript())
|
||||
return false;
|
||||
|
||||
// If none of the previous filters worked, then take the risk of
|
||||
// invalidating the frame to identify the JSFunction.
|
||||
return callee(cx) == fun;
|
||||
}
|
||||
|
||||
unsigned
|
||||
FrameIter::numActualArgs() const
|
||||
{
|
||||
|
@ -1598,8 +1598,22 @@ class FrameIter
|
||||
bool isConstructing() const;
|
||||
jsbytecode *pc() const { MOZ_ASSERT(!done()); return data_.pc_; }
|
||||
void updatePcQuadratic();
|
||||
JSFunction *callee() const;
|
||||
Value calleev() const;
|
||||
|
||||
// The function |calleeTemplate()| returns either the function from which
|
||||
// the current |callee| was cloned or the |callee| if it can be read. As
|
||||
// long as we do not have to investigate the scope chain or build a new
|
||||
// frame, we should prefer to use |calleeTemplate| instead of |callee|, as
|
||||
// requesting the |callee| might cause the invalidation of the frame. (see
|
||||
// js::Lambda)
|
||||
JSFunction *calleeTemplate() const;
|
||||
JSFunction *callee(JSContext *cx) const;
|
||||
|
||||
JSFunction *maybeCallee(JSContext *cx) const {
|
||||
return isFunctionFrame() ? callee(cx) : nullptr;
|
||||
}
|
||||
|
||||
bool matchCallee(JSContext *cx, HandleFunction fun) const;
|
||||
|
||||
unsigned numActualArgs() const;
|
||||
unsigned numFormalArgs() const;
|
||||
Value unaliasedActual(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
|
||||
@ -1626,10 +1640,6 @@ class FrameIter
|
||||
Value returnValue() const;
|
||||
void setReturnValue(const Value &v);
|
||||
|
||||
JSFunction *maybeCallee() const {
|
||||
return isFunctionFrame() ? callee() : nullptr;
|
||||
}
|
||||
|
||||
// These are only valid for the top frame.
|
||||
size_t numFrameSlots() const;
|
||||
Value frameSlotValue(size_t index) const;
|
||||
|
Loading…
Reference in New Issue
Block a user