mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 870514 - Add Ion stubs for optimized shadowed gets on proxy objects. r=h4writer
This commit is contained in:
parent
7abd17539e
commit
e503cd4d2f
@ -625,7 +625,8 @@ EmitLoadSlot(MacroAssembler &masm, JSObject *holder, Shape *shape, Register hold
|
||||
|
||||
static void
|
||||
GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, JSObject *obj,
|
||||
PropertyName *name, Register object, Label *stubFailure)
|
||||
PropertyName *name, Register object, Label *stubFailure,
|
||||
bool skipExpandoCheck=false)
|
||||
{
|
||||
MOZ_ASSERT(IsCacheableListBase(obj));
|
||||
|
||||
@ -639,6 +640,9 @@ GenerateListBaseChecks(JSContext *cx, MacroAssembler &masm, JSObject *obj,
|
||||
// Check that object is a ListBase.
|
||||
masm.branchPrivatePtr(Assembler::NotEqual, handlerAddr, ImmWord(GetProxyHandler(obj)), stubFailure);
|
||||
|
||||
if (skipExpandoCheck)
|
||||
return;
|
||||
|
||||
// For the remaining code, we need to reserve some registers to load a value.
|
||||
// This is ugly, but unvaoidable.
|
||||
RegisterSet listBaseRegSet(RegisterSet::All());
|
||||
@ -1015,6 +1019,118 @@ GetPropertyIC::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSOb
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::attachListBaseShadowed(JSContext *cx, IonScript *ion, JSObject *obj,
|
||||
void *returnAddr)
|
||||
{
|
||||
JS_ASSERT(!idempotent());
|
||||
JS_ASSERT(IsCacheableListBase(obj));
|
||||
JS_ASSERT(output().hasValue());
|
||||
|
||||
Label failures;
|
||||
MacroAssembler masm(cx);
|
||||
RepatchStubAppender attacher(*this);
|
||||
|
||||
masm.setFramePushed(ion->frameSize());
|
||||
|
||||
// Guard on the shape of the object.
|
||||
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
|
||||
Address(object(), JSObject::offsetOfShape()),
|
||||
ImmGCPtr(obj->lastProperty()),
|
||||
&failures);
|
||||
|
||||
// Make sure object is a ListBase proxy
|
||||
GenerateListBaseChecks(cx, masm, obj, name(), object(), &failures,
|
||||
/*skipExpandoCheck=*/true);
|
||||
|
||||
// saveLive()
|
||||
masm.PushRegsInMask(liveRegs_);
|
||||
|
||||
DebugOnly<uint32_t> initialStack = masm.framePushed();
|
||||
|
||||
// Remaining registers should be free, but we need to use |object| still
|
||||
// so leave it alone.
|
||||
RegisterSet regSet(RegisterSet::All());
|
||||
regSet.take(AnyRegister(object()));
|
||||
|
||||
// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
// MutableHandleValue vp)
|
||||
Register argJSContextReg = regSet.takeGeneral();
|
||||
Register argProxyReg = regSet.takeGeneral();
|
||||
Register argIdReg = regSet.takeGeneral();
|
||||
Register argVpReg = regSet.takeGeneral();
|
||||
|
||||
Register scratch = regSet.takeGeneral();
|
||||
|
||||
// Push args on stack first so we can take pointers to make handles.
|
||||
masm.Push(UndefinedValue());
|
||||
masm.movePtr(StackPointer, argVpReg);
|
||||
|
||||
RootedId propId(cx, AtomToId(name()));
|
||||
masm.Push(propId, scratch);
|
||||
masm.movePtr(StackPointer, argIdReg);
|
||||
|
||||
// Pushing object and receiver. Both are same, so Handle to one is equivalent to
|
||||
// handle to other.
|
||||
masm.Push(object());
|
||||
masm.Push(object());
|
||||
masm.movePtr(StackPointer, argProxyReg);
|
||||
|
||||
masm.loadJSContext(argJSContextReg);
|
||||
|
||||
if (!masm.buildOOLFakeExitFrame(returnAddr))
|
||||
return false;
|
||||
masm.enterFakeExitFrame(ION_FRAME_OOL_PROXY_GET);
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(5, scratch);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
masm.passABIArg(argVpReg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, Proxy::get));
|
||||
|
||||
// Test for failure.
|
||||
Label exception;
|
||||
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &exception);
|
||||
|
||||
// Load the outparam vp[0] into output register(s).
|
||||
masm.loadValue(
|
||||
Address(StackPointer, IonOOLProxyGetExitFrameLayout::offsetOfResult()),
|
||||
JSReturnOperand);
|
||||
|
||||
Label success;
|
||||
masm.jump(&success);
|
||||
|
||||
// Handle exception case.
|
||||
masm.bind(&exception);
|
||||
masm.handleException();
|
||||
|
||||
// Handle success case.
|
||||
masm.bind(&success);
|
||||
masm.storeCallResultValue(output());
|
||||
|
||||
// The next instruction is removing the footer of the exit frame, so there
|
||||
// is no need for leaveFakeExitFrame.
|
||||
|
||||
// Move the StackPointer back to its original location, unwinding the exit frame.
|
||||
masm.adjustStack(IonOOLPropertyOpExitFrameLayout::Size());
|
||||
JS_ASSERT(masm.framePushed() == initialStack);
|
||||
|
||||
// restoreLive()
|
||||
masm.PopRegsInMask(liveRegs_);
|
||||
|
||||
// Success.
|
||||
attacher.jumpRejoin(masm);
|
||||
|
||||
// Failure.
|
||||
masm.bind(&failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "list base shadowed get");
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj,
|
||||
JSObject *holder, HandleShape shape,
|
||||
@ -1264,12 +1380,15 @@ TryAttachNativeGetPropStub(JSContext *cx, IonScript *ion,
|
||||
RootedObject checkObj(cx, obj);
|
||||
if (IsCacheableListBase(obj)) {
|
||||
RootedId id(cx, NameToId(name));
|
||||
ListBaseShadowsResult shadows =
|
||||
GetListBaseShadowsCheck()(cx, obj, id);
|
||||
ListBaseShadowsResult shadows = GetListBaseShadowsCheck()(cx, obj, id);
|
||||
if (shadows == ShadowCheckFailed)
|
||||
return false;
|
||||
if (shadows == Shadows)
|
||||
return true;
|
||||
if (shadows == Shadows) {
|
||||
if (cache.idempotent() || !cache.output().hasValue())
|
||||
return true;
|
||||
*isCacheable = true;
|
||||
return cache.attachListBaseShadowed(cx, ion, obj, returnAddr);
|
||||
}
|
||||
if (shadows == DoesntShadowUnique)
|
||||
// We reset the cache to clear out an existing IC for this object
|
||||
// (if there is one). The generation is a constant in the generated
|
||||
|
@ -542,6 +542,7 @@ class GetPropertyIC : public RepatchIonCache
|
||||
|
||||
bool attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
||||
HandleShape shape);
|
||||
bool attachListBaseShadowed(JSContext *cx, IonScript *ion, JSObject *obj, void *returnAddr);
|
||||
bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
||||
HandleShape shape,
|
||||
const SafepointIndex *safepointIndex, void *returnAddr);
|
||||
|
@ -138,6 +138,7 @@ class IonFrameIterator
|
||||
bool isNative() const;
|
||||
bool isOOLNativeGetter() const;
|
||||
bool isOOLPropertyOp() const;
|
||||
bool isOOLProxyGet() const;
|
||||
bool isDOMExit() const;
|
||||
bool isEntry() const {
|
||||
return type_ == IonFrame_Entry;
|
||||
|
@ -127,6 +127,14 @@ IonFrameIterator::isOOLPropertyOp() const
|
||||
return exitFrame()->footer()->ionCode() == ION_FRAME_OOL_PROPERTY_OP;
|
||||
}
|
||||
|
||||
bool
|
||||
IonFrameIterator::isOOLProxyGet() const
|
||||
{
|
||||
if (type_ != IonFrame_Exit)
|
||||
return false;
|
||||
return exitFrame()->footer()->ionCode() == ION_FRAME_OOL_PROXY_GET;
|
||||
}
|
||||
|
||||
bool
|
||||
IonFrameIterator::isDOMExit() const
|
||||
{
|
||||
@ -829,6 +837,16 @@ MarkIonExitFrame(JSTracer *trc, const IonFrameIterator &frame)
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame.isOOLProxyGet()) {
|
||||
IonOOLProxyGetExitFrameLayout *oolproxyget = frame.exitFrame()->oolProxyGetExit();
|
||||
gc::MarkIonCodeRoot(trc, oolproxyget->stubCode(), "ion-ool-proxy-get-code");
|
||||
gc::MarkValueRoot(trc, oolproxyget->vp(), "ion-ool-proxy-get-vp");
|
||||
gc::MarkIdRoot(trc, oolproxyget->id(), "ion-ool-proxy-get-id");
|
||||
gc::MarkObjectRoot(trc, oolproxyget->proxy(), "ion-ool-proxy-get-proxy");
|
||||
gc::MarkObjectRoot(trc, oolproxyget->receiver(), "ion-ool-proxy-get-receiver");
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame.isDOMExit()) {
|
||||
IonDOMExitFrameLayout *dom = frame.exitFrame()->DOMExit();
|
||||
gc::MarkObjectRoot(trc, dom->thisObjAddress(), "ion-dom-args");
|
||||
|
@ -192,6 +192,7 @@ class IonBaselineStubFrameLayout : public IonCommonFrameLayout
|
||||
class IonNativeExitFrameLayout;
|
||||
class IonOOLNativeGetterExitFrameLayout;
|
||||
class IonOOLPropertyOpExitFrameLayout;
|
||||
class IonOOLProxyGetExitFrameLayout;
|
||||
class IonDOMExitFrameLayout;
|
||||
|
||||
// this is the frame layout when we are exiting ion code, and about to enter EABI code
|
||||
@ -234,6 +235,9 @@ class IonExitFrameLayout : public IonCommonFrameLayout
|
||||
inline bool isOOLPropertyOpExit() {
|
||||
return footer()->ionCode() == ION_FRAME_OOL_PROPERTY_OP;
|
||||
}
|
||||
inline bool isOOLProxyGetExit() {
|
||||
return footer()->ionCode() == ION_FRAME_OOL_PROXY_GET;
|
||||
}
|
||||
inline bool isDomExit() {
|
||||
IonCode *code = footer()->ionCode();
|
||||
return
|
||||
@ -255,6 +259,10 @@ class IonExitFrameLayout : public IonCommonFrameLayout
|
||||
JS_ASSERT(isOOLPropertyOpExit());
|
||||
return reinterpret_cast<IonOOLPropertyOpExitFrameLayout *>(footer());
|
||||
}
|
||||
inline IonOOLProxyGetExitFrameLayout *oolProxyGetExit() {
|
||||
JS_ASSERT(isOOLProxyGetExit());
|
||||
return reinterpret_cast<IonOOLProxyGetExitFrameLayout *>(footer());
|
||||
}
|
||||
inline IonDOMExitFrameLayout *DOMExit() {
|
||||
JS_ASSERT(isDomExit());
|
||||
return reinterpret_cast<IonDOMExitFrameLayout *>(footer());
|
||||
@ -372,6 +380,57 @@ class IonOOLPropertyOpExitFrameLayout
|
||||
}
|
||||
};
|
||||
|
||||
// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
// MutableHandleValue vp)
|
||||
class IonOOLProxyGetExitFrameLayout
|
||||
{
|
||||
protected: // only to silence a clang warning about unused private fields
|
||||
IonExitFooterFrame footer_;
|
||||
IonExitFrameLayout exit_;
|
||||
|
||||
// The proxy object.
|
||||
JSObject *proxy_;
|
||||
|
||||
// Object for JSHandleObject
|
||||
JSObject *receiver_;
|
||||
|
||||
// id for JSHandleId
|
||||
jsid id_;
|
||||
|
||||
// space for JSMutableHandleValue result
|
||||
// use two uint32_t so compiler doesn't align.
|
||||
uint32_t vp0_;
|
||||
uint32_t vp1_;
|
||||
|
||||
// pointer to root the stub's IonCode
|
||||
IonCode *stubCode_;
|
||||
|
||||
public:
|
||||
static inline size_t Size() {
|
||||
return sizeof(IonOOLProxyGetExitFrameLayout);
|
||||
}
|
||||
|
||||
static size_t offsetOfResult() {
|
||||
return offsetof(IonOOLProxyGetExitFrameLayout, vp0_);
|
||||
}
|
||||
|
||||
inline IonCode **stubCode() {
|
||||
return &stubCode_;
|
||||
}
|
||||
inline Value *vp() {
|
||||
return reinterpret_cast<Value*>(&vp0_);
|
||||
}
|
||||
inline jsid *id() {
|
||||
return &id_;
|
||||
}
|
||||
inline JSObject **receiver() {
|
||||
return &receiver_;
|
||||
}
|
||||
inline JSObject **proxy() {
|
||||
return &proxy_;
|
||||
}
|
||||
};
|
||||
|
||||
class IonDOMExitFrameLayout
|
||||
{
|
||||
IonExitFooterFrame footer_;
|
||||
|
@ -12,5 +12,6 @@
|
||||
#define ION_FRAME_DOMMETHOD ((IonCode *)0x3)
|
||||
#define ION_FRAME_OOL_NATIVE_GETTER ((IonCode *)0x4)
|
||||
#define ION_FRAME_OOL_PROPERTY_OP ((IonCode *)0x5)
|
||||
#define ION_FRAME_OOL_PROXY_GET ((IonCode *)0x6)
|
||||
|
||||
#endif
|
||||
|
@ -155,6 +155,7 @@ class IonExitFooterFrame
|
||||
class IonNativeExitFrameLayout;
|
||||
class IonOOLNativeGetterExitFrameLayout;
|
||||
class IonOOLPropertyOpExitFrameLayout;
|
||||
class IonOOLProxyGetExitFrameLayout;
|
||||
class IonDOMExitFrameLayout;
|
||||
|
||||
class IonExitFrameLayout : public IonCommonFrameLayout
|
||||
@ -196,6 +197,9 @@ class IonExitFrameLayout : public IonCommonFrameLayout
|
||||
inline bool isOOLPropertyOpExit() {
|
||||
return footer()->ionCode() == ION_FRAME_OOL_PROPERTY_OP;
|
||||
}
|
||||
inline bool isOOLProxyGetExit() {
|
||||
return footer()->ionCode() == ION_FRAME_OOL_PROXY_GET;
|
||||
}
|
||||
inline bool isDomExit() {
|
||||
IonCode *code = footer()->ionCode();
|
||||
return
|
||||
@ -217,6 +221,10 @@ class IonExitFrameLayout : public IonCommonFrameLayout
|
||||
JS_ASSERT(isOOLPropertyOpExit());
|
||||
return reinterpret_cast<IonOOLPropertyOpExitFrameLayout *>(footer());
|
||||
}
|
||||
inline IonOOLProxyGetExitFrameLayout *oolProxyGetExit() {
|
||||
JS_ASSERT(isOOLProxyGetExit());
|
||||
return reinterpret_cast<IonOOLProxyGetExitFrameLayout *>(footer());
|
||||
}
|
||||
inline IonDOMExitFrameLayout *DOMExit() {
|
||||
JS_ASSERT(isDomExit());
|
||||
return reinterpret_cast<IonDOMExitFrameLayout *>(footer());
|
||||
@ -336,6 +344,57 @@ class IonOOLPropertyOpExitFrameLayout
|
||||
}
|
||||
};
|
||||
|
||||
// Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
// MutableHandleValue vp)
|
||||
class IonOOLProxyGetExitFrameLayout
|
||||
{
|
||||
protected: // only to silence a clang warning about unused private fields
|
||||
IonExitFooterFrame footer_;
|
||||
IonExitFrameLayout exit_;
|
||||
|
||||
// The proxy object.
|
||||
JSObject *proxy_;
|
||||
|
||||
// Object for JSHandleObject
|
||||
JSObject *receiver_;
|
||||
|
||||
// id for JSHandleId
|
||||
jsid id_;
|
||||
|
||||
// space for JSMutableHandleValue result
|
||||
// use two uint32_t so compiler doesn't align.
|
||||
uint32_t vp0_;
|
||||
uint32_t vp1_;
|
||||
|
||||
// pointer to root the stub's IonCode
|
||||
IonCode *stubCode_;
|
||||
|
||||
public:
|
||||
static inline size_t Size() {
|
||||
return sizeof(IonOOLProxyGetExitFrameLayout);
|
||||
}
|
||||
|
||||
static size_t offsetOfResult() {
|
||||
return offsetof(IonOOLProxyGetExitFrameLayout, vp0_);
|
||||
}
|
||||
|
||||
inline IonCode **stubCode() {
|
||||
return &stubCode_;
|
||||
}
|
||||
inline Value *vp() {
|
||||
return reinterpret_cast<Value*>(&vp0_);
|
||||
}
|
||||
inline jsid *id() {
|
||||
return &id_;
|
||||
}
|
||||
inline JSObject **receiver() {
|
||||
return &receiver_;
|
||||
}
|
||||
inline JSObject **proxy() {
|
||||
return &proxy_;
|
||||
}
|
||||
};
|
||||
|
||||
class IonDOMExitFrameLayout
|
||||
{
|
||||
protected: // only to silence a clang warning about unused private fields
|
||||
|
Loading…
Reference in New Issue
Block a user