mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1157231 - Optimize calls to own property setters. r=efaust
This commit is contained in:
parent
a7aa64cbed
commit
2e4d61a916
@ -493,7 +493,7 @@ ICStub::trace(JSTracer* trc)
|
||||
}
|
||||
case ICStub::SetProp_CallScripted: {
|
||||
ICSetProp_CallScripted* callStub = toSetProp_CallScripted();
|
||||
callStub->guard().trace(trc);
|
||||
callStub->receiverGuard().trace(trc);
|
||||
TraceEdge(trc, &callStub->holder(), "baseline-setpropcallscripted-stub-holder");
|
||||
TraceEdge(trc, &callStub->holderShape(), "baseline-setpropcallscripted-stub-holdershape");
|
||||
TraceEdge(trc, &callStub->setter(), "baseline-setpropcallscripted-stub-setter");
|
||||
@ -501,7 +501,7 @@ ICStub::trace(JSTracer* trc)
|
||||
}
|
||||
case ICStub::SetProp_CallNative: {
|
||||
ICSetProp_CallNative* callStub = toSetProp_CallNative();
|
||||
callStub->guard().trace(trc);
|
||||
callStub->receiverGuard().trace(trc);
|
||||
TraceEdge(trc, &callStub->holder(), "baseline-setpropcallnative-stub-holder");
|
||||
TraceEdge(trc, &callStub->holderShape(), "baseline-setpropcallnative-stub-holdershape");
|
||||
TraceEdge(trc, &callStub->setter(), "baseline-setpropcallnative-stub-setter");
|
||||
@ -3580,10 +3580,6 @@ IsCacheableSetPropCall(JSContext* cx, JSObject* obj, JSObject* holder, Shape* sh
|
||||
{
|
||||
MOZ_ASSERT(isScripted);
|
||||
|
||||
// Currently we only optimize setter calls for setters bound on prototypes.
|
||||
if (obj == holder)
|
||||
return false;
|
||||
|
||||
if (!shape || !IsCacheableProtoChain(obj, holder))
|
||||
return false;
|
||||
|
||||
@ -6414,26 +6410,40 @@ static bool
|
||||
UpdateExistingSetPropCallStubs(ICSetProp_Fallback* fallbackStub,
|
||||
ICStub::Kind kind,
|
||||
NativeObject* holder,
|
||||
ReceiverGuard receiverGuard,
|
||||
JSObject* receiver,
|
||||
JSFunction* setter)
|
||||
{
|
||||
MOZ_ASSERT(kind == ICStub::SetProp_CallScripted ||
|
||||
kind == ICStub::SetProp_CallNative);
|
||||
MOZ_ASSERT(holder);
|
||||
MOZ_ASSERT(receiver);
|
||||
|
||||
bool isOwnSetter = (holder == receiver);
|
||||
bool foundMatchingStub = false;
|
||||
ReceiverGuard receiverGuard(receiver);
|
||||
for (ICStubConstIterator iter = fallbackStub->beginChainConst(); !iter.atEnd(); iter++) {
|
||||
if (iter->kind() == kind) {
|
||||
ICSetPropCallSetter* setPropStub = static_cast<ICSetPropCallSetter*>(*iter);
|
||||
if (setPropStub->holder() == holder) {
|
||||
if (setPropStub->holder() == holder && setPropStub->isOwnSetter() == isOwnSetter) {
|
||||
// If this is an own setter, update the receiver guard as well,
|
||||
// since that's the shape we'll be guarding on. Furthermore,
|
||||
// isOwnSetter() relies on holderShape_ and receiverGuard_ being
|
||||
// the same shape.
|
||||
if (isOwnSetter)
|
||||
setPropStub->receiverGuard().update(receiverGuard);
|
||||
|
||||
MOZ_ASSERT(setPropStub->holderShape() != holder->lastProperty() ||
|
||||
!setPropStub->receiverGuard().matches(receiverGuard),
|
||||
"Why didn't we end up using this stub?");
|
||||
|
||||
// We want to update the holder shape to match the new one no
|
||||
// matter what, even if the receiver shape is different.
|
||||
MOZ_ASSERT(setPropStub->holderShape() != holder->lastProperty() ||
|
||||
!setPropStub->guard().matches(receiverGuard),
|
||||
"Why didn't we end up using this stub?");
|
||||
setPropStub->holderShape() = holder->lastProperty();
|
||||
|
||||
// Make sure to update the setter, since a shape change might
|
||||
// have changed which setter we want to use.
|
||||
setPropStub->setter() = setter;
|
||||
if (setPropStub->guard().matches(receiverGuard))
|
||||
if (setPropStub->receiverGuard().matches(receiverGuard))
|
||||
foundMatchingStub = true;
|
||||
}
|
||||
}
|
||||
@ -8882,11 +8892,10 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
// Try handling scripted setters.
|
||||
if (cacheableCall && isScripted) {
|
||||
RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
|
||||
MOZ_ASSERT(obj != holder);
|
||||
MOZ_ASSERT(callee->hasScript());
|
||||
|
||||
if (UpdateExistingSetPropCallStubs(stub, ICStub::SetProp_CallScripted,
|
||||
&holder->as<NativeObject>(), receiverGuard, callee)) {
|
||||
&holder->as<NativeObject>(), obj, callee)) {
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
@ -8907,11 +8916,10 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
// Try handling JSNative setters.
|
||||
if (cacheableCall && !isScripted) {
|
||||
RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
|
||||
MOZ_ASSERT(obj != holder);
|
||||
MOZ_ASSERT(callee->isNative());
|
||||
|
||||
if (UpdateExistingSetPropCallStubs(stub, ICStub::SetProp_CallNative,
|
||||
&holder->as<NativeObject>(), receiverGuard, callee)) {
|
||||
&holder->as<NativeObject>(), obj, callee)) {
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
@ -9651,14 +9659,16 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
|
||||
// Unbox and shape guard.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratch,
|
||||
ICSetProp_CallScripted::offsetOfGuard(), &failureUnstow);
|
||||
GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch,
|
||||
ICSetProp_CallScripted::offsetOfReceiverGuard(), &failureUnstow);
|
||||
|
||||
Register holderReg = regs.takeAny();
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfHolder()), holderReg);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfHolderShape()), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
|
||||
regs.add(holderReg);
|
||||
if (receiver_ != holder_) {
|
||||
Register holderReg = regs.takeAny();
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfHolder()), holderReg);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfHolderShape()), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
|
||||
regs.add(holderReg);
|
||||
}
|
||||
|
||||
// Push a stub frame so that we can perform a non-tail call.
|
||||
enterStubFrame(masm, scratch);
|
||||
@ -9770,14 +9780,16 @@ ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
|
||||
// Unbox and shape guard.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratch,
|
||||
ICSetProp_CallNative::offsetOfGuard(), &failureUnstow);
|
||||
GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch,
|
||||
ICSetProp_CallNative::offsetOfReceiverGuard(), &failureUnstow);
|
||||
|
||||
Register holderReg = regs.takeAny();
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolder()), holderReg);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolderShape()), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
|
||||
regs.add(holderReg);
|
||||
if (receiver_ != holder_) {
|
||||
Register holderReg = regs.takeAny();
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolder()), holderReg);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallNative::offsetOfHolderShape()), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratch, &failureUnstow);
|
||||
regs.add(holderReg);
|
||||
}
|
||||
|
||||
// Push a stub frame so that we can perform a non-tail call.
|
||||
enterStubFrame(masm, scratch);
|
||||
@ -12877,11 +12889,11 @@ ICSetPropNativeAddCompiler::ICSetPropNativeAddCompiler(JSContext* cx, HandleObje
|
||||
MOZ_ASSERT(protoChainDepth_ <= ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH);
|
||||
}
|
||||
|
||||
ICSetPropCallSetter::ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard guard,
|
||||
ICSetPropCallSetter::ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard receiverGuard,
|
||||
JSObject* holder, Shape* holderShape,
|
||||
JSFunction* setter, uint32_t pcOffset)
|
||||
: ICStub(kind, stubCode),
|
||||
guard_(guard),
|
||||
receiverGuard_(receiverGuard),
|
||||
holder_(holder),
|
||||
holderShape_(holderShape),
|
||||
setter_(setter),
|
||||
@ -12894,15 +12906,17 @@ ICSetPropCallSetter::ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverG
|
||||
ICSetProp_CallScripted::Clone(JSContext* cx, ICStubSpace* space, ICStub*,
|
||||
ICSetProp_CallScripted& other)
|
||||
{
|
||||
return New<ICSetProp_CallScripted>(cx, space, other.jitCode(), other.guard(), other.holder_,
|
||||
other.holderShape_, other.setter_, other.pcOffset_);
|
||||
return New<ICSetProp_CallScripted>(cx, space, other.jitCode(), other.receiverGuard(),
|
||||
other.holder_, other.holderShape_, other.setter_,
|
||||
other.pcOffset_);
|
||||
}
|
||||
|
||||
/* static */ ICSetProp_CallNative*
|
||||
ICSetProp_CallNative::Clone(JSContext* cx, ICStubSpace* space, ICStub*, ICSetProp_CallNative& other)
|
||||
{
|
||||
return New<ICSetProp_CallNative>(cx, space, other.jitCode(), other.guard(), other.holder_,
|
||||
other.holderShape_, other.setter_, other.pcOffset_);
|
||||
return New<ICSetProp_CallNative>(cx, space, other.jitCode(), other.receiverGuard(),
|
||||
other.holder_, other.holderShape_, other.setter_,
|
||||
other.pcOffset_);
|
||||
}
|
||||
|
||||
ICCall_Scripted::ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
|
@ -4574,6 +4574,12 @@ class ICGetPropCallGetter : public ICMonitoredStub
|
||||
return receiverGuard_;
|
||||
}
|
||||
|
||||
bool isOwnGetter() const {
|
||||
MOZ_ASSERT(holder_->isNative());
|
||||
MOZ_ASSERT(holderShape_);
|
||||
return receiverGuard_.shape() == holderShape_;
|
||||
}
|
||||
|
||||
static size_t offsetOfHolder() {
|
||||
return offsetof(ICGetPropCallGetter, holder_);
|
||||
}
|
||||
@ -4590,12 +4596,6 @@ class ICGetPropCallGetter : public ICMonitoredStub
|
||||
return offsetof(ICGetPropCallGetter, receiverGuard_);
|
||||
}
|
||||
|
||||
bool isOwnGetter() const {
|
||||
MOZ_ASSERT(holder_->isNative());
|
||||
MOZ_ASSERT(holderShape_);
|
||||
return receiverGuard_.shape() == holderShape_;
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
ICStub* firstMonitorStub_;
|
||||
@ -5331,10 +5331,13 @@ class ICSetPropCallSetter : public ICStub
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
// Object shape/group.
|
||||
HeapReceiverGuard guard_;
|
||||
// Shape/group of receiver object. Used for both own and proto setters.
|
||||
HeapReceiverGuard receiverGuard_;
|
||||
|
||||
// Holder and shape.
|
||||
// Holder and holder shape. For own setters, guarding on receiverGuard_ is
|
||||
// sufficient, although Ion may use holder_ and holderShape_ even for own
|
||||
// setters. In this case holderShape_ == receiverGuard_.shape_ (isOwnSetter
|
||||
// below relies on this).
|
||||
HeapPtrObject holder_;
|
||||
HeapPtrShape holderShape_;
|
||||
|
||||
@ -5344,13 +5347,13 @@ class ICSetPropCallSetter : public ICStub
|
||||
// PC of call, for profiler
|
||||
uint32_t pcOffset_;
|
||||
|
||||
ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard guard,
|
||||
ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard receiverGuard,
|
||||
JSObject* holder, Shape* holderShape, JSFunction* setter,
|
||||
uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
HeapReceiverGuard& guard() {
|
||||
return guard_;
|
||||
HeapReceiverGuard& receiverGuard() {
|
||||
return receiverGuard_;
|
||||
}
|
||||
HeapPtrObject& holder() {
|
||||
return holder_;
|
||||
@ -5362,8 +5365,14 @@ class ICSetPropCallSetter : public ICStub
|
||||
return setter_;
|
||||
}
|
||||
|
||||
static size_t offsetOfGuard() {
|
||||
return offsetof(ICSetPropCallSetter, guard_);
|
||||
bool isOwnSetter() const {
|
||||
MOZ_ASSERT(holder_->isNative());
|
||||
MOZ_ASSERT(holderShape_);
|
||||
return receiverGuard_.shape() == holderShape_;
|
||||
}
|
||||
|
||||
static size_t offsetOfReceiverGuard() {
|
||||
return offsetof(ICSetPropCallSetter, receiverGuard_);
|
||||
}
|
||||
static size_t offsetOfHolder() {
|
||||
return offsetof(ICSetPropCallSetter, holder_);
|
||||
@ -5380,21 +5389,22 @@ class ICSetPropCallSetter : public ICStub
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
RootedObject obj_;
|
||||
RootedObject receiver_;
|
||||
RootedObject holder_;
|
||||
RootedFunction setter_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) |
|
||||
(HeapReceiverGuard::keyBits(obj_) << 16);
|
||||
(HeapReceiverGuard::keyBits(receiver_) << 16) |
|
||||
(static_cast<int32_t>(receiver_ != holder_) << 19);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext* cx, ICStub::Kind kind, HandleObject obj, HandleObject holder,
|
||||
Compiler(JSContext* cx, ICStub::Kind kind, HandleObject receiver, HandleObject holder,
|
||||
HandleFunction setter, uint32_t pcOffset)
|
||||
: ICStubCompiler(cx, kind),
|
||||
obj_(cx, obj),
|
||||
receiver_(cx, receiver),
|
||||
holder_(cx, holder),
|
||||
setter_(cx, setter),
|
||||
pcOffset_(pcOffset)
|
||||
@ -5432,7 +5442,7 @@ class ICSetProp_CallScripted : public ICSetPropCallSetter
|
||||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
ReceiverGuard guard(obj_);
|
||||
ReceiverGuard guard(receiver_);
|
||||
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
|
||||
return newStub<ICSetProp_CallScripted>(space, getStubCode(), guard, holder_,
|
||||
holderShape, setter_, pcOffset_);
|
||||
@ -5469,7 +5479,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter
|
||||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
ReceiverGuard guard(obj_);
|
||||
ReceiverGuard guard(receiver_);
|
||||
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
|
||||
return newStub<ICSetProp_CallNative>(space, getStubCode(), guard, holder_, holderShape,
|
||||
setter_, pcOffset_);
|
||||
|
@ -672,15 +672,16 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
|
||||
for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
|
||||
ICSetPropCallSetter* nstub = static_cast<ICSetPropCallSetter*>(stub);
|
||||
if (!AddReceiver(nstub->guard(), receivers, convertUnboxedGroups))
|
||||
bool isOwn = nstub->isOwnSetter();
|
||||
if (!isOwn && !AddReceiver(nstub->receiverGuard(), receivers, convertUnboxedGroups))
|
||||
return false;
|
||||
|
||||
if (!*holder) {
|
||||
*holder = nstub->holder();
|
||||
*holderShape = nstub->holderShape();
|
||||
*commonSetter = nstub->setter();
|
||||
*isOwnProperty = false;
|
||||
} else if (nstub->holderShape() != *holderShape) {
|
||||
*isOwnProperty = isOwn;
|
||||
} else if (nstub->holderShape() != *holderShape || isOwn != *isOwnProperty) {
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(*commonSetter == nstub->setter());
|
||||
|
Loading…
Reference in New Issue
Block a user