зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1157703 - Cache iterators involving unboxed objects, r=jandem.
This commit is contained in:
Родитель
21b619291a
Коммит
6eb4312856
|
@ -165,57 +165,6 @@ ICStub::updateCode(JitCode* code)
|
|||
stubCode_ = code->raw();
|
||||
}
|
||||
|
||||
void
|
||||
ReceiverGuard::trace(JSTracer* trc)
|
||||
{
|
||||
if (shape_)
|
||||
TraceEdge(trc, &shape_, "receiver_guard_shape");
|
||||
else
|
||||
TraceEdge(trc, &group_, "receiver_guard_group");
|
||||
}
|
||||
|
||||
ReceiverGuard::StackGuard::StackGuard(JSObject* obj)
|
||||
: group(nullptr), shape(nullptr)
|
||||
{
|
||||
if (obj) {
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
group = obj->group();
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
|
||||
shape = expando->lastProperty();
|
||||
} else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
|
||||
group = obj->group();
|
||||
} else {
|
||||
shape = obj->maybeShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReceiverGuard::StackGuard::StackGuard(ObjectGroup* group, Shape* shape)
|
||||
: group(group), shape(shape)
|
||||
{
|
||||
if (group) {
|
||||
if (IsTypedObjectClass(group->clasp()))
|
||||
this->shape = nullptr;
|
||||
else if (group->clasp() != &UnboxedPlainObject::class_)
|
||||
this->group = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
ReceiverGuard::keyBits(JSObject* obj)
|
||||
{
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
// Both the group and shape need to be guarded for unboxed plain objects.
|
||||
return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
|
||||
}
|
||||
if (obj->is<TypedObject>()) {
|
||||
// Only the group needs to be guarded for typed objects.
|
||||
return 2;
|
||||
}
|
||||
// Other objects only need the shape to be guarded.
|
||||
return 3;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ICStub::trace(JSTracer* trc)
|
||||
{
|
||||
|
@ -6426,7 +6375,7 @@ UpdateExistingGetPropCallStubs(ICFallbackStub* fallbackStub,
|
|||
|
||||
bool isOwnGetter = (holder == receiver);
|
||||
bool foundMatchingStub = false;
|
||||
ReceiverGuard::StackGuard receiverGuard(receiver);
|
||||
ReceiverGuard receiverGuard(receiver);
|
||||
for (ICStubConstIterator iter = fallbackStub->beginChainConst(); !iter.atEnd(); iter++) {
|
||||
if (iter->kind() == kind) {
|
||||
ICGetPropCallGetter* getPropStub = static_cast<ICGetPropCallGetter*>(*iter);
|
||||
|
@ -6465,7 +6414,7 @@ static bool
|
|||
UpdateExistingSetPropCallStubs(ICSetProp_Fallback* fallbackStub,
|
||||
ICStub::Kind kind,
|
||||
NativeObject* holder,
|
||||
ReceiverGuard::StackGuard receiverGuard,
|
||||
ReceiverGuard receiverGuard,
|
||||
JSFunction* setter)
|
||||
{
|
||||
MOZ_ASSERT(kind == ICStub::SetProp_CallScripted ||
|
||||
|
@ -7941,7 +7890,7 @@ ICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
ICGetPropNativeStub*
|
||||
ICGetPropNativeCompiler::getStub(ICStubSpace* space)
|
||||
{
|
||||
ReceiverGuard::StackGuard guard(obj_);
|
||||
ReceiverGuard guard(obj_);
|
||||
|
||||
switch (kind) {
|
||||
case ICStub::GetProp_Native: {
|
||||
|
@ -7962,12 +7911,12 @@ ICGetPropNativeCompiler::getStub(ICStubSpace* space)
|
|||
}
|
||||
|
||||
static void
|
||||
GuardReceiverObject(MacroAssembler& masm, ReceiverGuard::StackGuard guard,
|
||||
GuardReceiverObject(MacroAssembler& masm, ReceiverGuard guard,
|
||||
Register object, Register scratch,
|
||||
size_t receiverGuardOffset, Label* failure)
|
||||
{
|
||||
Address groupAddress(BaselineStubReg, receiverGuardOffset + ReceiverGuard::offsetOfGroup());
|
||||
Address shapeAddress(BaselineStubReg, receiverGuardOffset + ReceiverGuard::offsetOfShape());
|
||||
Address groupAddress(BaselineStubReg, receiverGuardOffset + HeapReceiverGuard::offsetOfGroup());
|
||||
Address shapeAddress(BaselineStubReg, receiverGuardOffset + HeapReceiverGuard::offsetOfShape());
|
||||
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
|
||||
|
||||
if (guard.group) {
|
||||
|
@ -8019,7 +7968,7 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm)
|
|||
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
|
||||
|
||||
// Shape/group guard.
|
||||
GuardReceiverObject(masm, ReceiverGuard::StackGuard(obj_), objReg, scratch,
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratch,
|
||||
ICGetPropNativeStub::offsetOfReceiverGuard(), &failure);
|
||||
|
||||
Register holderReg;
|
||||
|
@ -8167,7 +8116,7 @@ ICGetPropNativeDoesNotExistCompiler::generateStubCode(MacroAssembler& masm)
|
|||
|
||||
// Unbox and guard against old shape/group.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
GuardReceiverObject(masm, ReceiverGuard::StackGuard(obj_), objReg, scratch,
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratch,
|
||||
ICGetProp_NativeDoesNotExist::offsetOfGuard(), &failure);
|
||||
|
||||
Register protoReg = regs.takeAny();
|
||||
|
@ -8206,7 +8155,7 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
|
||||
// Unbox and shape guard.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
GuardReceiverObject(masm, ReceiverGuard::StackGuard(receiver_), objReg, scratch,
|
||||
GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch,
|
||||
ICGetProp_CallScripted::offsetOfReceiverGuard(), &failure);
|
||||
|
||||
if (receiver_ != holder_) {
|
||||
|
@ -8314,7 +8263,7 @@ ICGetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
|
||||
|
||||
// Shape guard.
|
||||
GuardReceiverObject(masm, ReceiverGuard::StackGuard(receiver_), objReg, scratch,
|
||||
GuardReceiverObject(masm, ReceiverGuard(receiver_), objReg, scratch,
|
||||
ICGetProp_CallNative::offsetOfReceiverGuard(), &failure);
|
||||
|
||||
if (receiver_ != holder_ ) {
|
||||
|
@ -8372,7 +8321,7 @@ ICGetPropCallDOMProxyNativeCompiler::generateStubCode(MacroAssembler& masm,
|
|||
// Shape guard.
|
||||
static const size_t receiverShapeOffset =
|
||||
ICGetProp_CallDOMProxyNative::offsetOfReceiverGuard() +
|
||||
ReceiverGuard::offsetOfShape();
|
||||
HeapReceiverGuard::offsetOfShape();
|
||||
masm.loadPtr(Address(BaselineStubReg, receiverShapeOffset), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
|
||||
|
||||
|
@ -8910,7 +8859,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
|
|||
static bool
|
||||
TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
ICSetProp_Fallback* stub,
|
||||
HandleObject obj, const ReceiverGuard::RootedStackGuard& receiverGuard,
|
||||
HandleObject obj, const RootedReceiverGuard& receiverGuard,
|
||||
HandlePropertyName name,
|
||||
HandleId id, HandleValue rhs, bool* attached,
|
||||
bool* isTemporarilyUnoptimizable)
|
||||
|
@ -9097,7 +9046,7 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
|
|||
RootedObjectGroup oldGroup(cx, obj->getGroup(cx));
|
||||
if (!oldGroup)
|
||||
return false;
|
||||
ReceiverGuard::RootedStackGuard oldGuard(cx, ReceiverGuard::StackGuard(obj));
|
||||
RootedReceiverGuard oldGuard(cx, ReceiverGuard(obj));
|
||||
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
|
||||
|
@ -9702,7 +9651,7 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
|
||||
// Unbox and shape guard.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
GuardReceiverObject(masm, ReceiverGuard::StackGuard(obj_), objReg, scratch,
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratch,
|
||||
ICSetProp_CallScripted::offsetOfGuard(), &failureUnstow);
|
||||
|
||||
Register holderReg = regs.takeAny();
|
||||
|
@ -9821,7 +9770,7 @@ ICSetProp_CallNative::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
|
||||
// Unbox and shape guard.
|
||||
Register objReg = masm.extractObject(R0, ExtractTemp0);
|
||||
GuardReceiverObject(masm, ReceiverGuard::StackGuard(obj_), objReg, scratch,
|
||||
GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratch,
|
||||
ICSetProp_CallNative::offsetOfGuard(), &failureUnstow);
|
||||
|
||||
Register holderReg = regs.takeAny();
|
||||
|
@ -12741,7 +12690,7 @@ ICGetProp_Primitive::ICGetProp_Primitive(JitCode* stubCode, ICStub* firstMonitor
|
|||
|
||||
ICGetPropNativeStub::ICGetPropNativeStub(ICStub::Kind kind, JitCode* stubCode,
|
||||
ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard guard, uint32_t offset)
|
||||
ReceiverGuard guard, uint32_t offset)
|
||||
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
|
||||
receiverGuard_(guard),
|
||||
offset_(offset)
|
||||
|
@ -12756,7 +12705,7 @@ ICGetProp_Native::Clone(ICStubSpace* space, ICStub* firstMonitorStub,
|
|||
}
|
||||
|
||||
ICGetProp_NativePrototype::ICGetProp_NativePrototype(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard guard, uint32_t offset,
|
||||
ReceiverGuard guard, uint32_t offset,
|
||||
JSObject* holder, Shape* holderShape)
|
||||
: ICGetPropNativeStub(GetProp_NativePrototype, stubCode, firstMonitorStub, guard, offset),
|
||||
holder_(holder),
|
||||
|
@ -12773,7 +12722,7 @@ ICGetProp_NativePrototype::Clone(ICStubSpace* space, ICStub* firstMonitorStub,
|
|||
}
|
||||
|
||||
ICGetProp_NativeDoesNotExist::ICGetProp_NativeDoesNotExist(
|
||||
JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard::StackGuard guard,
|
||||
JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
|
||||
size_t protoChainDepth)
|
||||
: ICMonitoredStub(GetProp_NativeDoesNotExist, stubCode, firstMonitorStub),
|
||||
guard_(guard)
|
||||
|
@ -12793,7 +12742,7 @@ ICGetProp_NativeDoesNotExist::offsetOfShape(size_t idx)
|
|||
|
||||
template <size_t ProtoChainDepth>
|
||||
ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth>::ICGetProp_NativeDoesNotExistImpl(
|
||||
JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard::StackGuard guard,
|
||||
JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
|
||||
const AutoShapeVector* shapes)
|
||||
: ICGetProp_NativeDoesNotExist(stubCode, firstMonitorStub, guard, ProtoChainDepth)
|
||||
{
|
||||
|
@ -12815,7 +12764,7 @@ ICGetPropNativeDoesNotExistCompiler::ICGetPropNativeDoesNotExistCompiler(
|
|||
}
|
||||
|
||||
ICGetPropCallGetter::ICGetPropCallGetter(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard receiverGuard, JSObject* holder,
|
||||
ReceiverGuard receiverGuard, JSObject* holder,
|
||||
Shape* holderShape, JSFunction* getter,
|
||||
uint32_t pcOffset)
|
||||
: ICMonitoredStub(kind, stubCode, firstMonitorStub),
|
||||
|
@ -12926,7 +12875,7 @@ ICSetPropNativeAddCompiler::ICSetPropNativeAddCompiler(JSContext* cx, HandleObje
|
|||
MOZ_ASSERT(protoChainDepth_ <= ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH);
|
||||
}
|
||||
|
||||
ICSetPropCallSetter::ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard::StackGuard guard,
|
||||
ICSetPropCallSetter::ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard guard,
|
||||
JSObject* holder, Shape* holderShape,
|
||||
JSFunction* setter, uint32_t pcOffset)
|
||||
: ICStub(kind, stubCode),
|
||||
|
@ -13059,7 +13008,7 @@ ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, JitC
|
|||
Shape* holderShape,
|
||||
JSFunction* getter,
|
||||
uint32_t pcOffset)
|
||||
: ICGetPropCallGetter(kind, stubCode, firstMonitorStub, ReceiverGuard::StackGuard(nullptr, shape),
|
||||
: ICGetPropCallGetter(kind, stubCode, firstMonitorStub, ReceiverGuard(nullptr, shape),
|
||||
holder, holderShape, getter, pcOffset),
|
||||
expandoShape_(expandoShape)
|
||||
{ }
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/BaselineRegisters.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/ReceiverGuard.h"
|
||||
#include "vm/TypedArrayCommon.h"
|
||||
#include "vm/UnboxedObject.h"
|
||||
|
||||
|
@ -4172,111 +4173,21 @@ class ICGetProp_StringLength : public ICStub
|
|||
};
|
||||
};
|
||||
|
||||
// Structure encapsulating the guarding that needs to be done on an object
|
||||
// before it can be accessed or modified by an inline cache.
|
||||
class ReceiverGuard
|
||||
{
|
||||
// Group to guard on, or null. If the object is not unboxed or typed and
|
||||
// the IC does not require the object to have a specific group, this is
|
||||
// null. Otherwise, this is the object's group.
|
||||
HeapPtrObjectGroup group_;
|
||||
|
||||
// Shape to guard on, or null. If the object is not unboxed or typed then
|
||||
// this is the object's shape. If the object is unboxed, then this is the
|
||||
// shape of the object's expando, null if the object has no expando.
|
||||
HeapPtrShape shape_;
|
||||
|
||||
public:
|
||||
struct StackGuard;
|
||||
|
||||
struct RootedStackGuard
|
||||
{
|
||||
RootedObjectGroup group;
|
||||
RootedShape shape;
|
||||
|
||||
RootedStackGuard(JSContext* cx, const StackGuard& guard)
|
||||
: group(cx, guard.group), shape(cx, guard.shape)
|
||||
{}
|
||||
};
|
||||
|
||||
struct StackGuard
|
||||
{
|
||||
ObjectGroup* group;
|
||||
Shape* shape;
|
||||
|
||||
StackGuard()
|
||||
: group(nullptr), shape(nullptr)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT StackGuard(const ReceiverGuard& guard)
|
||||
: group(guard.group_), shape(guard.shape_)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT StackGuard(const RootedStackGuard& guard)
|
||||
: group(guard.group), shape(guard.shape)
|
||||
{}
|
||||
|
||||
explicit StackGuard(JSObject* obj);
|
||||
StackGuard(ObjectGroup* group, Shape* shape);
|
||||
|
||||
bool operator ==(const StackGuard& other) const {
|
||||
return group == other.group && shape == other.shape;
|
||||
}
|
||||
|
||||
bool operator !=(const StackGuard& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
explicit ReceiverGuard(const StackGuard& guard)
|
||||
: group_(guard.group), shape_(guard.shape)
|
||||
{}
|
||||
|
||||
bool matches(const StackGuard& guard) {
|
||||
return group_ == guard.group && shape_ == guard.shape;
|
||||
}
|
||||
|
||||
void update(const StackGuard& other) {
|
||||
group_ = other.group;
|
||||
shape_ = other.shape;
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
Shape* shape() const {
|
||||
return shape_;
|
||||
}
|
||||
ObjectGroup* group() const {
|
||||
return group_;
|
||||
}
|
||||
|
||||
static size_t offsetOfShape() {
|
||||
return offsetof(ReceiverGuard, shape_);
|
||||
}
|
||||
static size_t offsetOfGroup() {
|
||||
return offsetof(ReceiverGuard, group_);
|
||||
}
|
||||
|
||||
// Bits to munge into IC compiler keys when that IC has a ReceiverGuard.
|
||||
// This uses at most two bits for data.
|
||||
static int32_t keyBits(JSObject* obj);
|
||||
};
|
||||
|
||||
// Base class for native GetProp stubs.
|
||||
class ICGetPropNativeStub : public ICMonitoredStub
|
||||
{
|
||||
// Object shape/group.
|
||||
ReceiverGuard receiverGuard_;
|
||||
HeapReceiverGuard receiverGuard_;
|
||||
|
||||
// Fixed or dynamic slot offset.
|
||||
uint32_t offset_;
|
||||
|
||||
protected:
|
||||
ICGetPropNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard guard, uint32_t offset);
|
||||
ReceiverGuard guard, uint32_t offset);
|
||||
|
||||
public:
|
||||
ReceiverGuard& receiverGuard() {
|
||||
HeapReceiverGuard& receiverGuard() {
|
||||
return receiverGuard_;
|
||||
}
|
||||
uint32_t offset() const {
|
||||
|
@ -4303,7 +4214,7 @@ class ICGetProp_Native : public ICGetPropNativeStub
|
|||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
ICGetProp_Native(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard::StackGuard guard,
|
||||
ICGetProp_Native(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard,
|
||||
uint32_t offset)
|
||||
: ICGetPropNativeStub(GetProp_Native, stubCode, firstMonitorStub, guard, offset)
|
||||
{}
|
||||
|
@ -4326,7 +4237,7 @@ class ICGetProp_NativePrototype : public ICGetPropNativeStub
|
|||
HeapPtrShape holderShape_;
|
||||
|
||||
ICGetProp_NativePrototype(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard guard,
|
||||
ReceiverGuard guard,
|
||||
uint32_t offset, JSObject* holder, Shape* holderShape);
|
||||
|
||||
public:
|
||||
|
@ -4369,7 +4280,7 @@ class ICGetPropNativeCompiler : public ICStubCompiler
|
|||
(static_cast<int32_t>(isCallProp_) << 16) |
|
||||
(static_cast<int32_t>(isFixedSlot_) << 17) |
|
||||
(static_cast<int32_t>(inputDefinitelyObject_) << 18) |
|
||||
(ReceiverGuard::keyBits(obj_) << 19);
|
||||
(HeapReceiverGuard::keyBits(obj_) << 19);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -4397,13 +4308,13 @@ class ICGetProp_NativeDoesNotExist : public ICMonitoredStub
|
|||
{
|
||||
friend class ICStubSpace;
|
||||
public:
|
||||
ReceiverGuard guard_;
|
||||
HeapReceiverGuard guard_;
|
||||
|
||||
static const size_t MAX_PROTO_CHAIN_DEPTH = 8;
|
||||
|
||||
protected:
|
||||
ICGetProp_NativeDoesNotExist(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard guard,
|
||||
ReceiverGuard guard,
|
||||
size_t protoChainDepth);
|
||||
|
||||
public:
|
||||
|
@ -4418,7 +4329,7 @@ class ICGetProp_NativeDoesNotExist : public ICMonitoredStub
|
|||
return static_cast<ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth>*>(this);
|
||||
}
|
||||
|
||||
ReceiverGuard& guard() {
|
||||
HeapReceiverGuard& guard() {
|
||||
return guard_;
|
||||
}
|
||||
|
||||
|
@ -4441,7 +4352,7 @@ class ICGetProp_NativeDoesNotExistImpl : public ICGetProp_NativeDoesNotExist
|
|||
mozilla::Array<HeapPtrShape, NumShapes> shapes_;
|
||||
|
||||
ICGetProp_NativeDoesNotExistImpl(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard guard,
|
||||
ReceiverGuard guard,
|
||||
const AutoShapeVector* shapes);
|
||||
|
||||
public:
|
||||
|
@ -4465,7 +4376,7 @@ class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler
|
|||
protected:
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) |
|
||||
(ReceiverGuard::keyBits(obj_) << 16) |
|
||||
(HeapReceiverGuard::keyBits(obj_) << 16) |
|
||||
(static_cast<int32_t>(protoChainDepth_) << 18);
|
||||
}
|
||||
|
||||
|
@ -4477,7 +4388,7 @@ class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler
|
|||
|
||||
template <size_t ProtoChainDepth>
|
||||
ICStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes) {
|
||||
ReceiverGuard::StackGuard guard(obj_);
|
||||
ReceiverGuard guard(obj_);
|
||||
return ICStub::New<ICGetProp_NativeDoesNotExistImpl<ProtoChainDepth> >
|
||||
(space, getStubCode(), firstMonitorStub_, guard, shapes);
|
||||
}
|
||||
|
@ -4619,7 +4530,7 @@ class ICGetPropCallGetter : public ICMonitoredStub
|
|||
// Shape/group of receiver object. Used for both own and proto getters.
|
||||
// In the GetPropCallDOMProxyNative case, the receiver guard enforces
|
||||
// the proxy handler, because Shape implies Class.
|
||||
ReceiverGuard receiverGuard_;
|
||||
HeapReceiverGuard receiverGuard_;
|
||||
|
||||
// Holder and holder shape. For own getters, guarding on receiverGuard_ is
|
||||
// sufficient, although Ion may use holder_ and holderShape_ even for own
|
||||
|
@ -4636,7 +4547,7 @@ class ICGetPropCallGetter : public ICMonitoredStub
|
|||
uint32_t pcOffset_;
|
||||
|
||||
ICGetPropCallGetter(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard receiverGuard, JSObject* holder,
|
||||
ReceiverGuard receiverGuard, JSObject* holder,
|
||||
Shape* holderShape, JSFunction* getter, uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
|
@ -4649,7 +4560,7 @@ class ICGetPropCallGetter : public ICMonitoredStub
|
|||
HeapPtrFunction& getter() {
|
||||
return getter_;
|
||||
}
|
||||
ReceiverGuard& receiverGuard() {
|
||||
HeapReceiverGuard& receiverGuard() {
|
||||
return receiverGuard_;
|
||||
}
|
||||
|
||||
|
@ -4688,7 +4599,7 @@ class ICGetPropCallGetter : public ICMonitoredStub
|
|||
// ICGetProp_CallNative::Compiler::getKey adds more bits to our
|
||||
// return value, so be careful when making changes here.
|
||||
return static_cast<int32_t>(kind) |
|
||||
(ReceiverGuard::keyBits(receiver_) << 16) |
|
||||
(HeapReceiverGuard::keyBits(receiver_) << 16) |
|
||||
(static_cast<int32_t>(!!outerClass_) << 18) |
|
||||
(static_cast<int32_t>(receiver_ != holder_) << 19);
|
||||
}
|
||||
|
@ -4719,7 +4630,7 @@ class ICGetProp_CallScripted : public ICGetPropCallGetter
|
|||
|
||||
protected:
|
||||
ICGetProp_CallScripted(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard receiverGuard,
|
||||
ReceiverGuard receiverGuard,
|
||||
JSObject* holder, Shape* holderShape,
|
||||
JSFunction* getter, uint32_t pcOffset)
|
||||
: ICGetPropCallGetter(GetProp_CallScripted, stubCode, firstMonitorStub,
|
||||
|
@ -4743,7 +4654,7 @@ class ICGetProp_CallScripted : public ICGetPropCallGetter
|
|||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
ReceiverGuard::StackGuard guard(receiver_);
|
||||
ReceiverGuard guard(receiver_);
|
||||
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
|
||||
return ICStub::New<ICGetProp_CallScripted>(space, getStubCode(), firstMonitorStub_,
|
||||
guard, holder_, holderShape, getter_,
|
||||
|
@ -4760,7 +4671,7 @@ class ICGetProp_CallNative : public ICGetPropCallGetter
|
|||
protected:
|
||||
|
||||
ICGetProp_CallNative(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
ReceiverGuard::StackGuard receiverGuard,
|
||||
ReceiverGuard receiverGuard,
|
||||
JSObject* holder, Shape* holderShape,
|
||||
JSFunction* getter, uint32_t pcOffset)
|
||||
: ICGetPropCallGetter(GetProp_CallNative, stubCode, firstMonitorStub,
|
||||
|
@ -4794,7 +4705,7 @@ class ICGetProp_CallNative : public ICGetPropCallGetter
|
|||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
ReceiverGuard::StackGuard guard(receiver_);
|
||||
ReceiverGuard guard(receiver_);
|
||||
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
|
||||
return ICStub::New<ICGetProp_CallNative>(space, getStubCode(), firstMonitorStub_,
|
||||
guard, holder_, holderShape,
|
||||
|
@ -5410,7 +5321,7 @@ class ICSetPropCallSetter : public ICStub
|
|||
|
||||
protected:
|
||||
// Object shape/group.
|
||||
ReceiverGuard guard_;
|
||||
HeapReceiverGuard guard_;
|
||||
|
||||
// Holder and shape.
|
||||
HeapPtrObject holder_;
|
||||
|
@ -5422,12 +5333,12 @@ class ICSetPropCallSetter : public ICStub
|
|||
// PC of call, for profiler
|
||||
uint32_t pcOffset_;
|
||||
|
||||
ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard::StackGuard guard,
|
||||
ICSetPropCallSetter(Kind kind, JitCode* stubCode, ReceiverGuard guard,
|
||||
JSObject* holder, Shape* holderShape, JSFunction* setter,
|
||||
uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
ReceiverGuard& guard() {
|
||||
HeapReceiverGuard& guard() {
|
||||
return guard_;
|
||||
}
|
||||
HeapPtrObject& holder() {
|
||||
|
@ -5465,7 +5376,7 @@ class ICSetPropCallSetter : public ICStub
|
|||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) |
|
||||
(ReceiverGuard::keyBits(obj_) << 16);
|
||||
(HeapReceiverGuard::keyBits(obj_) << 16);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -5488,7 +5399,7 @@ class ICSetProp_CallScripted : public ICSetPropCallSetter
|
|||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
ICSetProp_CallScripted(JitCode* stubCode, ReceiverGuard::StackGuard guard, JSObject* holder,
|
||||
ICSetProp_CallScripted(JitCode* stubCode, ReceiverGuard guard, JSObject* holder,
|
||||
Shape* holderShape, JSFunction* setter, uint32_t pcOffset)
|
||||
: ICSetPropCallSetter(SetProp_CallScripted, stubCode, guard, holder, holderShape,
|
||||
setter, pcOffset)
|
||||
|
@ -5510,7 +5421,7 @@ class ICSetProp_CallScripted : public ICSetPropCallSetter
|
|||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
ReceiverGuard::StackGuard guard(obj_);
|
||||
ReceiverGuard guard(obj_);
|
||||
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
|
||||
return ICStub::New<ICSetProp_CallScripted>(space, getStubCode(), guard, holder_,
|
||||
holderShape, setter_, pcOffset_);
|
||||
|
@ -5524,7 +5435,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter
|
|||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
ICSetProp_CallNative(JitCode* stubCode, ReceiverGuard::StackGuard guard, JSObject* holder,
|
||||
ICSetProp_CallNative(JitCode* stubCode, ReceiverGuard guard, JSObject* holder,
|
||||
Shape* holderShape, JSFunction* setter, uint32_t pcOffset)
|
||||
: ICSetPropCallSetter(SetProp_CallNative, stubCode, guard, holder, holderShape,
|
||||
setter, pcOffset)
|
||||
|
@ -5546,7 +5457,7 @@ class ICSetProp_CallNative : public ICSetPropCallSetter
|
|||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
ReceiverGuard::StackGuard guard(obj_);
|
||||
ReceiverGuard guard(obj_);
|
||||
Shape* holderShape = holder_->as<NativeObject>().lastProperty();
|
||||
return ICStub::New<ICSetProp_CallNative>(space, getStubCode(), guard, holder_,
|
||||
holderShape, setter_, pcOffset_);
|
||||
|
|
|
@ -91,7 +91,7 @@ VectorAppendNoDuplicate(S& list, T value)
|
|||
}
|
||||
|
||||
static bool
|
||||
AddReceiver(const ReceiverGuard::StackGuard& receiver,
|
||||
AddReceiver(const ReceiverGuard& receiver,
|
||||
BaselineInspector::ReceiverVector& receivers,
|
||||
BaselineInspector::ObjectGroupVector& convertUnboxedGroups)
|
||||
{
|
||||
|
@ -122,16 +122,16 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
|
|||
|
||||
ICStub* stub = entry.firstStub();
|
||||
while (stub->next()) {
|
||||
ReceiverGuard::StackGuard receiver;
|
||||
ReceiverGuard receiver;
|
||||
if (stub->isGetProp_Native()) {
|
||||
receiver = stub->toGetProp_Native()->receiverGuard();
|
||||
} else if (stub->isSetProp_Native()) {
|
||||
receiver = ReceiverGuard::StackGuard(stub->toSetProp_Native()->group(),
|
||||
stub->toSetProp_Native()->shape());
|
||||
receiver = ReceiverGuard(stub->toSetProp_Native()->group(),
|
||||
stub->toSetProp_Native()->shape());
|
||||
} else if (stub->isGetProp_Unboxed()) {
|
||||
receiver = ReceiverGuard::StackGuard(stub->toGetProp_Unboxed()->group(), nullptr);
|
||||
receiver = ReceiverGuard(stub->toGetProp_Unboxed()->group(), nullptr);
|
||||
} else if (stub->isSetProp_Unboxed()) {
|
||||
receiver = ReceiverGuard::StackGuard(stub->toSetProp_Unboxed()->group(), nullptr);
|
||||
receiver = ReceiverGuard(stub->toSetProp_Unboxed()->group(), nullptr);
|
||||
} else {
|
||||
receivers.clear();
|
||||
return true;
|
||||
|
@ -587,7 +587,7 @@ GlobalShapeForGetPropFunction(ICStub* stub)
|
|||
if (nstub->isOwnGetter())
|
||||
return nullptr;
|
||||
|
||||
const ReceiverGuard& guard = nstub->receiverGuard();
|
||||
const HeapReceiverGuard& guard = nstub->receiverGuard();
|
||||
if (Shape* shape = guard.shape()) {
|
||||
if (shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL)
|
||||
return shape;
|
||||
|
|
|
@ -92,7 +92,7 @@ class BaselineInspector
|
|||
bool dimorphicStub(jsbytecode* pc, ICStub** pfirst, ICStub** psecond);
|
||||
|
||||
public:
|
||||
typedef Vector<ReceiverGuard::StackGuard, 4, JitAllocPolicy> ReceiverVector;
|
||||
typedef Vector<ReceiverGuard, 4, JitAllocPolicy> ReceiverVector;
|
||||
typedef Vector<ObjectGroup*, 4, JitAllocPolicy> ObjectGroupVector;
|
||||
bool maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups);
|
||||
|
|
|
@ -2252,7 +2252,7 @@ CodeGenerator::visitStoreSlotV(LStoreSlotV* lir)
|
|||
}
|
||||
|
||||
static void
|
||||
GuardReceiver(MacroAssembler& masm, const ReceiverGuard::StackGuard& guard,
|
||||
GuardReceiver(MacroAssembler& masm, const ReceiverGuard& guard,
|
||||
Register obj, Register scratch, Label* miss, bool checkNullExpando)
|
||||
{
|
||||
if (guard.group) {
|
||||
|
@ -2280,7 +2280,7 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
|
|||
Label done;
|
||||
|
||||
for (size_t i = 0; i < mir->numReceivers(); i++) {
|
||||
ReceiverGuard::StackGuard receiver = mir->receiver(i);
|
||||
ReceiverGuard receiver = mir->receiver(i);
|
||||
|
||||
Label next;
|
||||
GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
|
||||
|
@ -2359,7 +2359,7 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
|
|||
|
||||
Label done;
|
||||
for (size_t i = 0; i < mir->numReceivers(); i++) {
|
||||
ReceiverGuard::StackGuard receiver = mir->receiver(i);
|
||||
ReceiverGuard receiver = mir->receiver(i);
|
||||
|
||||
Label next;
|
||||
GuardReceiver(masm, receiver, obj, scratch, &next, /* checkNullExpando = */ false);
|
||||
|
@ -2531,7 +2531,7 @@ CodeGenerator::visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir)
|
|||
Label done;
|
||||
|
||||
for (size_t i = 0; i < mir->numReceivers(); i++) {
|
||||
const ReceiverGuard::StackGuard& receiver = mir->receiver(i);
|
||||
const ReceiverGuard& receiver = mir->receiver(i);
|
||||
|
||||
Label next;
|
||||
GuardReceiver(masm, receiver, obj, temp, &next, /* checkNullExpando = */ true);
|
||||
|
@ -7122,32 +7122,60 @@ CodeGenerator::visitIteratorStart(LIteratorStart* lir)
|
|||
masm.branchTest32(Assembler::NonZero, Address(niTemp, offsetof(NativeIterator, flags)),
|
||||
Imm32(JSITER_ACTIVE|JSITER_UNREUSABLE), ool->entry());
|
||||
|
||||
// Load the iterator's shape array.
|
||||
masm.loadPtr(Address(niTemp, offsetof(NativeIterator, shapes_array)), temp2);
|
||||
// Load the iterator's receiver guard array.
|
||||
masm.loadPtr(Address(niTemp, offsetof(NativeIterator, guard_array)), temp2);
|
||||
|
||||
// Compare shape of object with the first shape.
|
||||
masm.loadObjShape(obj, temp1);
|
||||
masm.branchPtr(Assembler::NotEqual, Address(temp2, 0), temp1, ool->entry());
|
||||
// Compare object with the first receiver guard. The last iterator can only
|
||||
// match for native objects and unboxed objects.
|
||||
{
|
||||
Address groupAddr(temp2, offsetof(ReceiverGuard, group));
|
||||
Address shapeAddr(temp2, offsetof(ReceiverGuard, shape));
|
||||
Label guardDone, shapeMismatch, noExpando;
|
||||
masm.loadObjShape(obj, temp1);
|
||||
masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, &shapeMismatch);
|
||||
|
||||
// Compare shape of object's prototype with the second shape.
|
||||
// Ensure the object does not have any elements. The presence of dense
|
||||
// elements is not captured by the shape tests above.
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(obj, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElements),
|
||||
ool->entry());
|
||||
masm.jump(&guardDone);
|
||||
|
||||
masm.bind(&shapeMismatch);
|
||||
masm.loadObjGroup(obj, temp1);
|
||||
masm.branchPtr(Assembler::NotEqual, groupAddr, temp1, ool->entry());
|
||||
masm.loadPtr(Address(obj, UnboxedPlainObject::offsetOfExpando()), temp1);
|
||||
masm.branchTestPtr(Assembler::Zero, temp1, temp1, &noExpando);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(temp1, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElements),
|
||||
ool->entry());
|
||||
masm.loadObjShape(temp1, temp1);
|
||||
masm.bind(&noExpando);
|
||||
masm.branchPtr(Assembler::NotEqual, shapeAddr, temp1, ool->entry());
|
||||
masm.bind(&guardDone);
|
||||
}
|
||||
|
||||
// Compare shape of object's prototype with the second shape. The prototype
|
||||
// must be native, as unboxed objects cannot be prototypes (they cannot
|
||||
// have the delegate flag set). Also check for the absence of dense elements.
|
||||
Address prototypeShapeAddr(temp2, sizeof(ReceiverGuard) + offsetof(ReceiverGuard, shape));
|
||||
masm.loadObjProto(obj, temp1);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(temp1, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElements),
|
||||
ool->entry());
|
||||
masm.loadObjShape(temp1, temp1);
|
||||
masm.branchPtr(Assembler::NotEqual, Address(temp2, sizeof(Shape*)), temp1, ool->entry());
|
||||
masm.branchPtr(Assembler::NotEqual, prototypeShapeAddr, temp1, ool->entry());
|
||||
|
||||
// Ensure the object's prototype's prototype is nullptr. The last native
|
||||
// iterator will always have a prototype chain length of one (i.e. it must
|
||||
// be a plain ), so we do not need to generate a loop here.
|
||||
// be a plain object), so we do not need to generate a loop here.
|
||||
masm.loadObjProto(obj, temp1);
|
||||
masm.loadObjProto(temp1, temp1);
|
||||
masm.branchTestPtr(Assembler::NonZero, temp1, temp1, ool->entry());
|
||||
|
||||
// Ensure the object does not have any elements. The presence of dense
|
||||
// elements is not captured by the shape tests above.
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(obj, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElements),
|
||||
ool->entry());
|
||||
|
||||
// Write barrier for stores to the iterator. We only need to take a write
|
||||
// barrier if NativeIterator::obj is actually going to change.
|
||||
{
|
||||
|
|
|
@ -9967,7 +9967,7 @@ class MGetPropertyPolymorphic
|
|||
{
|
||||
struct Entry {
|
||||
// The group and/or shape to guard against.
|
||||
ReceiverGuard::StackGuard receiver;
|
||||
ReceiverGuard receiver;
|
||||
|
||||
// The property to load, null for loads from unboxed properties.
|
||||
Shape* shape;
|
||||
|
@ -10001,7 +10001,7 @@ class MGetPropertyPolymorphic
|
|||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
|
||||
bool addReceiver(const ReceiverGuard::StackGuard receiver, Shape* shape) {
|
||||
bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
|
||||
Entry entry;
|
||||
entry.receiver = receiver;
|
||||
entry.shape = shape;
|
||||
|
@ -10010,7 +10010,7 @@ class MGetPropertyPolymorphic
|
|||
size_t numReceivers() const {
|
||||
return receivers_.length();
|
||||
}
|
||||
const ReceiverGuard::StackGuard receiver(size_t i) const {
|
||||
const ReceiverGuard receiver(size_t i) const {
|
||||
return receivers_[i].receiver;
|
||||
}
|
||||
Shape* shape(size_t i) const {
|
||||
|
@ -10047,7 +10047,7 @@ class MSetPropertyPolymorphic
|
|||
{
|
||||
struct Entry {
|
||||
// The group and/or shape to guard against.
|
||||
ReceiverGuard::StackGuard receiver;
|
||||
ReceiverGuard receiver;
|
||||
|
||||
// The property to store, null for stores to unboxed properties.
|
||||
Shape* shape;
|
||||
|
@ -10074,7 +10074,7 @@ class MSetPropertyPolymorphic
|
|||
return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
|
||||
}
|
||||
|
||||
bool addReceiver(const ReceiverGuard::StackGuard& receiver, Shape* shape) {
|
||||
bool addReceiver(const ReceiverGuard& receiver, Shape* shape) {
|
||||
Entry entry;
|
||||
entry.receiver = receiver;
|
||||
entry.shape = shape;
|
||||
|
@ -10083,7 +10083,7 @@ class MSetPropertyPolymorphic
|
|||
size_t numReceivers() const {
|
||||
return receivers_.length();
|
||||
}
|
||||
const ReceiverGuard::StackGuard& receiver(size_t i) const {
|
||||
const ReceiverGuard& receiver(size_t i) const {
|
||||
return receivers_[i].receiver;
|
||||
}
|
||||
Shape* shape(size_t i) const {
|
||||
|
@ -10410,7 +10410,7 @@ class MGuardReceiverPolymorphic
|
|||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
Vector<ReceiverGuard::StackGuard, 4, JitAllocPolicy> receivers_;
|
||||
Vector<ReceiverGuard, 4, JitAllocPolicy> receivers_;
|
||||
|
||||
MGuardReceiverPolymorphic(TempAllocator& alloc, MDefinition* obj)
|
||||
: MUnaryInstruction(obj),
|
||||
|
@ -10432,13 +10432,13 @@ class MGuardReceiverPolymorphic
|
|||
return getOperand(0);
|
||||
}
|
||||
|
||||
bool addReceiver(const ReceiverGuard::StackGuard& receiver) {
|
||||
bool addReceiver(const ReceiverGuard& receiver) {
|
||||
return receivers_.append(receiver);
|
||||
}
|
||||
size_t numReceivers() const {
|
||||
return receivers_.length();
|
||||
}
|
||||
const ReceiverGuard::StackGuard& receiver(size_t i) const {
|
||||
const ReceiverGuard& receiver(size_t i) const {
|
||||
return receivers_[i];
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ NativeIterator::mark(JSTracer* trc)
|
|||
if (obj)
|
||||
TraceEdge(trc, &obj, "obj");
|
||||
|
||||
for (size_t i = 0; i < guard_length; i++)
|
||||
guard_array[i].trace(trc);
|
||||
|
||||
// The SuppressDeletedPropertyHelper loop can GC, so make sure that if the
|
||||
// GC removes any elements from the list, it won't remove this one.
|
||||
if (iterObj_)
|
||||
|
@ -531,10 +534,12 @@ NewPropertyIteratorObject(JSContext* cx, unsigned flags)
|
|||
}
|
||||
|
||||
NativeIterator*
|
||||
NativeIterator::allocateIterator(JSContext* cx, uint32_t slength, const AutoIdVector& props)
|
||||
NativeIterator::allocateIterator(JSContext* cx, uint32_t numGuards, const AutoIdVector& props)
|
||||
{
|
||||
JS_STATIC_ASSERT(sizeof(ReceiverGuard) == 2 * sizeof(void*));
|
||||
|
||||
size_t plength = props.length();
|
||||
NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(plength + slength);
|
||||
NativeIterator* ni = cx->zone()->pod_malloc_with_extra<NativeIterator, void*>(plength + numGuards * 2);
|
||||
if (!ni)
|
||||
return nullptr;
|
||||
|
||||
|
@ -572,14 +577,14 @@ NativeIterator::allocateSentinel(JSContext* maybecx)
|
|||
}
|
||||
|
||||
inline void
|
||||
NativeIterator::init(JSObject* obj, JSObject* iterObj, unsigned flags, uint32_t slength, uint32_t key)
|
||||
NativeIterator::init(JSObject* obj, JSObject* iterObj, unsigned flags, uint32_t numGuards, uint32_t key)
|
||||
{
|
||||
this->obj.init(obj);
|
||||
this->iterObj_ = iterObj;
|
||||
this->flags = flags;
|
||||
this->shapes_array = (Shape**) this->props_end;
|
||||
this->shapes_length = slength;
|
||||
this->shapes_key = key;
|
||||
this->guard_array = (HeapReceiverGuard*) this->props_end;
|
||||
this->guard_length = numGuards;
|
||||
this->guard_key = key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -596,7 +601,7 @@ RegisterEnumerator(JSContext* cx, PropertyIteratorObject* iterobj, NativeIterato
|
|||
|
||||
static inline bool
|
||||
VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& keys,
|
||||
uint32_t slength, uint32_t key, MutableHandleObject objp)
|
||||
uint32_t numGuards, uint32_t key, MutableHandleObject objp)
|
||||
{
|
||||
MOZ_ASSERT(!(flags & JSITER_FOREACH));
|
||||
|
||||
|
@ -608,26 +613,20 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto
|
|||
if (!iterobj)
|
||||
return false;
|
||||
|
||||
NativeIterator* ni = NativeIterator::allocateIterator(cx, slength, keys);
|
||||
NativeIterator* ni = NativeIterator::allocateIterator(cx, numGuards, keys);
|
||||
if (!ni)
|
||||
return false;
|
||||
ni->init(obj, iterobj, flags, slength, key);
|
||||
ni->init(obj, iterobj, flags, numGuards, key);
|
||||
|
||||
if (slength) {
|
||||
/*
|
||||
* Fill in the shape array from scratch. We can't use the array that was
|
||||
* computed for the cache lookup earlier, as constructing iterobj could
|
||||
* have triggered a shape-regenerating GC. Don't bother with regenerating
|
||||
* the shape key; if such a GC *does* occur, we can only get hits through
|
||||
* the one-slot lastNativeIterator cache.
|
||||
*/
|
||||
if (numGuards) {
|
||||
// Fill in the guard array from scratch.
|
||||
JSObject* pobj = obj;
|
||||
size_t ind = 0;
|
||||
do {
|
||||
ni->shapes_array[ind++] = pobj->as<NativeObject>().lastProperty();
|
||||
ni->guard_array[ind++].init(ReceiverGuard(pobj));
|
||||
pobj = pobj->getProto();
|
||||
} while (pobj);
|
||||
MOZ_ASSERT(ind == slength);
|
||||
MOZ_ASSERT(ind == numGuards);
|
||||
}
|
||||
|
||||
iterobj->setNativeIterator(ni);
|
||||
|
@ -702,6 +701,37 @@ UpdateNativeIterator(NativeIterator* ni, JSObject* obj)
|
|||
ni->obj = obj;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CanCompareIterableObjectToCache(JSObject* obj)
|
||||
{
|
||||
if (obj->isNative())
|
||||
return obj->as<NativeObject>().hasEmptyElements();
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
|
||||
return expando->hasEmptyElements();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CanCacheIterableObject(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
if (!CanCompareIterableObjectToCache(obj))
|
||||
return false;
|
||||
if (obj->isNative()) {
|
||||
if (IsAnyTypedArray(obj) ||
|
||||
obj->hasUncacheableProto() ||
|
||||
obj->getOps()->enumerate ||
|
||||
obj->getClass()->enumerate ||
|
||||
obj->as<NativeObject>().containsPure(cx->names().iteratorIntrinsic))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleObject objp)
|
||||
{
|
||||
|
@ -720,27 +750,21 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
|||
return Proxy::enumerate(cx, obj, objp);
|
||||
}
|
||||
|
||||
Vector<Shape*, 8> shapes(cx);
|
||||
Vector<ReceiverGuard, 8> guards(cx);
|
||||
uint32_t key = 0;
|
||||
if (flags == JSITER_ENUMERATE) {
|
||||
/*
|
||||
* Check to see if this is the same as the most recent object which
|
||||
* was iterated over. We don't explicitly check for shapeless
|
||||
* objects here, as they are not inserted into the cache and
|
||||
* will result in a miss.
|
||||
*/
|
||||
// Check to see if this is the same as the most recent object which was
|
||||
// iterated over.
|
||||
PropertyIteratorObject* last = cx->runtime()->nativeIterCache.last;
|
||||
if (last) {
|
||||
NativeIterator* lastni = last->getNativeIterator();
|
||||
if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
obj->isNative() &&
|
||||
obj->as<NativeObject>().hasEmptyElements() &&
|
||||
obj->as<NativeObject>().lastProperty() == lastni->shapes_array[0])
|
||||
CanCompareIterableObjectToCache(obj) &&
|
||||
ReceiverGuard(obj) == lastni->guard_array[0])
|
||||
{
|
||||
JSObject* proto = obj->getProto();
|
||||
if (proto->isNative() &&
|
||||
proto->as<NativeObject>().hasEmptyElements() &&
|
||||
proto->as<NativeObject>().lastProperty() == lastni->shapes_array[1] &&
|
||||
if (CanCompareIterableObjectToCache(proto) &&
|
||||
ReceiverGuard(proto) == lastni->guard_array[1] &&
|
||||
!proto->getProto())
|
||||
{
|
||||
objp.set(last);
|
||||
|
@ -760,20 +784,13 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
|||
{
|
||||
JSObject* pobj = obj;
|
||||
do {
|
||||
if (!pobj->isNative() ||
|
||||
!pobj->as<NativeObject>().hasEmptyElements() ||
|
||||
IsAnyTypedArray(pobj) ||
|
||||
pobj->hasUncacheableProto() ||
|
||||
pobj->getOps()->enumerate ||
|
||||
pobj->getClass()->enumerate ||
|
||||
pobj->as<NativeObject>().containsPure(cx->names().iteratorIntrinsic))
|
||||
{
|
||||
shapes.clear();
|
||||
if (!CanCacheIterableObject(cx, pobj)) {
|
||||
guards.clear();
|
||||
goto miss;
|
||||
}
|
||||
Shape* shape = pobj->as<NativeObject>().lastProperty();
|
||||
key = (key + (key << 16)) ^ (uintptr_t(shape) >> 3);
|
||||
if (!shapes.append(shape))
|
||||
ReceiverGuard guard(pobj);
|
||||
key = (key + (key << 16)) ^ guard.hash();
|
||||
if (!guards.append(guard))
|
||||
return false;
|
||||
pobj = pobj->getProto();
|
||||
} while (pobj);
|
||||
|
@ -783,14 +800,16 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
|||
if (iterobj) {
|
||||
NativeIterator* ni = iterobj->getNativeIterator();
|
||||
if (!(ni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
|
||||
ni->shapes_key == key &&
|
||||
ni->shapes_length == shapes.length() &&
|
||||
Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) {
|
||||
ni->guard_key == key &&
|
||||
ni->guard_length == guards.length() &&
|
||||
Compare(reinterpret_cast<ReceiverGuard*>(ni->guard_array),
|
||||
guards.begin(), ni->guard_length))
|
||||
{
|
||||
objp.set(iterobj);
|
||||
|
||||
UpdateNativeIterator(ni, obj);
|
||||
RegisterEnumerator(cx, iterobj, ni);
|
||||
if (shapes.length() == 2)
|
||||
if (guards.length() == 2)
|
||||
cx->runtime()->nativeIterCache.last = iterobj;
|
||||
return true;
|
||||
}
|
||||
|
@ -805,7 +824,7 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
|||
|
||||
AutoIdVector keys(cx);
|
||||
if (flags & JSITER_FOREACH) {
|
||||
MOZ_ASSERT(shapes.empty());
|
||||
MOZ_ASSERT(guards.empty());
|
||||
|
||||
if (!Snapshot(cx, obj, flags, &keys))
|
||||
return false;
|
||||
|
@ -814,17 +833,17 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb
|
|||
} else {
|
||||
if (!Snapshot(cx, obj, flags, &keys))
|
||||
return false;
|
||||
if (!VectorToKeyIterator(cx, obj, flags, keys, shapes.length(), key, objp))
|
||||
if (!VectorToKeyIterator(cx, obj, flags, keys, guards.length(), key, objp))
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyIteratorObject* iterobj = &objp->as<PropertyIteratorObject>();
|
||||
|
||||
/* Cache the iterator object if possible. */
|
||||
if (shapes.length())
|
||||
if (guards.length())
|
||||
cx->runtime()->nativeIterCache.set(key, iterobj);
|
||||
|
||||
if (shapes.length() == 2)
|
||||
if (guards.length() == 2)
|
||||
cx->runtime()->nativeIterCache.last = iterobj;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "jscntxt.h"
|
||||
|
||||
#include "gc/Barrier.h"
|
||||
#include "vm/ReceiverGuard.h"
|
||||
#include "vm/Stack.h"
|
||||
|
||||
/*
|
||||
|
@ -34,9 +35,9 @@ struct NativeIterator
|
|||
HeapPtrFlatString* props_array;
|
||||
HeapPtrFlatString* props_cursor;
|
||||
HeapPtrFlatString* props_end;
|
||||
Shape** shapes_array;
|
||||
uint32_t shapes_length;
|
||||
uint32_t shapes_key;
|
||||
HeapReceiverGuard* guard_array;
|
||||
uint32_t guard_length;
|
||||
uint32_t guard_key;
|
||||
uint32_t flags;
|
||||
|
||||
private:
|
||||
|
|
|
@ -297,6 +297,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/PIC.cpp',
|
||||
'vm/Probes.cpp',
|
||||
'vm/ProxyObject.cpp',
|
||||
'vm/ReceiverGuard.cpp',
|
||||
'vm/RegExpObject.cpp',
|
||||
'vm/RegExpStatics.cpp',
|
||||
'vm/Runtime.cpp',
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "vm/ReceiverGuard.h"
|
||||
|
||||
#include "vm/UnboxedObject.h"
|
||||
|
||||
ReceiverGuard::ReceiverGuard(JSObject* obj)
|
||||
: group(nullptr), shape(nullptr)
|
||||
{
|
||||
if (obj) {
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
group = obj->group();
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
|
||||
shape = expando->lastProperty();
|
||||
} else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
|
||||
group = obj->group();
|
||||
} else {
|
||||
shape = obj->maybeShape();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
|
||||
: group(group), shape(shape)
|
||||
{
|
||||
if (group) {
|
||||
const Class* clasp = group->clasp();
|
||||
if (clasp == &UnboxedPlainObject::class_) {
|
||||
// Keep both group and shape.
|
||||
} else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) {
|
||||
this->shape = nullptr;
|
||||
} else {
|
||||
this->group = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
HeapReceiverGuard::keyBits(JSObject* obj)
|
||||
{
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
// Both the group and shape need to be guarded for unboxed plain objects.
|
||||
return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
|
||||
}
|
||||
if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
|
||||
// Only the group needs to be guarded for unboxed arrays and typed objects.
|
||||
return 2;
|
||||
}
|
||||
// Other objects only need the shape to be guarded.
|
||||
return 3;
|
||||
}
|
||||
|
||||
void
|
||||
HeapReceiverGuard::trace(JSTracer* trc)
|
||||
{
|
||||
if (shape_)
|
||||
TraceEdge(trc, &shape_, "receiver_guard_shape");
|
||||
else
|
||||
TraceEdge(trc, &group_, "receiver_guard_group");
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef vm_ReceiverGuard_h
|
||||
#define vm_ReceiverGuard_h
|
||||
|
||||
#include "vm/Shape.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
// A ReceiverGuard encapsulates the information about an object that needs to
|
||||
// be tested to determine if it has the same 'structure' as another object.
|
||||
// The guard includes the shape and/or group of the object, and which of these
|
||||
// is tested, as well as the meaning here of 'structure', depends on the kind
|
||||
// of object being tested:
|
||||
//
|
||||
// NativeObject: The structure of a native object is determined by its shape.
|
||||
// Two objects with the same shape have the same class, prototype, flags,
|
||||
// and all properties except those stored in dense elements.
|
||||
//
|
||||
// ProxyObject: The structure of a proxy object is determined by its shape.
|
||||
// Proxies with the same shape have the same class and prototype, but no
|
||||
// other commonality is guaranteed.
|
||||
//
|
||||
// TypedObject: The structure of a typed object is determined by its group.
|
||||
// All typed objects with the same group have the same class, prototype, and
|
||||
// own properties.
|
||||
//
|
||||
// UnboxedPlainObject: The structure of an unboxed plain object is determined
|
||||
// by its group and its expando object's shape, if there is one. All unboxed
|
||||
// plain objects with the same group and expando shape have the same
|
||||
// properties except those stored in the expando's dense elements.
|
||||
|
||||
class HeapReceiverGuard;
|
||||
class RootedReceiverGuard;
|
||||
|
||||
class ReceiverGuard
|
||||
{
|
||||
public:
|
||||
ObjectGroup* group;
|
||||
Shape* shape;
|
||||
|
||||
ReceiverGuard()
|
||||
: group(nullptr), shape(nullptr)
|
||||
{}
|
||||
|
||||
inline MOZ_IMPLICIT ReceiverGuard(const HeapReceiverGuard& guard);
|
||||
inline MOZ_IMPLICIT ReceiverGuard(const RootedReceiverGuard& guard);
|
||||
|
||||
explicit ReceiverGuard(JSObject* obj);
|
||||
ReceiverGuard(ObjectGroup* group, Shape* shape);
|
||||
|
||||
bool operator ==(const ReceiverGuard& other) const {
|
||||
return group == other.group && shape == other.shape;
|
||||
}
|
||||
|
||||
bool operator !=(const ReceiverGuard& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
uintptr_t hash() const {
|
||||
return (uintptr_t(group) >> 3) ^ (uintptr_t(shape) >> 3);
|
||||
}
|
||||
};
|
||||
|
||||
class HeapReceiverGuard
|
||||
{
|
||||
HeapPtrObjectGroup group_;
|
||||
HeapPtrShape shape_;
|
||||
|
||||
public:
|
||||
explicit HeapReceiverGuard(const ReceiverGuard& guard)
|
||||
: group_(guard.group), shape_(guard.shape)
|
||||
{}
|
||||
|
||||
bool matches(const ReceiverGuard& guard) {
|
||||
return group_ == guard.group && shape_ == guard.shape;
|
||||
}
|
||||
|
||||
void update(const ReceiverGuard& other) {
|
||||
group_ = other.group;
|
||||
shape_ = other.shape;
|
||||
}
|
||||
|
||||
void init(const ReceiverGuard& other) {
|
||||
group_.init(other.group);
|
||||
shape_.init(other.shape);
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
Shape* shape() const {
|
||||
return shape_;
|
||||
}
|
||||
ObjectGroup* group() const {
|
||||
return group_;
|
||||
}
|
||||
|
||||
static size_t offsetOfShape() {
|
||||
return offsetof(HeapReceiverGuard, shape_);
|
||||
}
|
||||
static size_t offsetOfGroup() {
|
||||
return offsetof(HeapReceiverGuard, group_);
|
||||
}
|
||||
|
||||
// Bits to munge into Baseline IC compiler keys when that IC has a
|
||||
// HeapReceiverGuard. This uses at most two bits for data.
|
||||
static int32_t keyBits(JSObject* obj);
|
||||
};
|
||||
|
||||
class RootedReceiverGuard
|
||||
{
|
||||
public:
|
||||
RootedObjectGroup group;
|
||||
RootedShape shape;
|
||||
|
||||
RootedReceiverGuard(JSContext* cx, const ReceiverGuard& guard)
|
||||
: group(cx, guard.group), shape(cx, guard.shape)
|
||||
{}
|
||||
};
|
||||
|
||||
inline
|
||||
ReceiverGuard::ReceiverGuard(const HeapReceiverGuard& guard)
|
||||
: group(guard.group()), shape(guard.shape())
|
||||
{}
|
||||
|
||||
inline
|
||||
ReceiverGuard::ReceiverGuard(const RootedReceiverGuard& guard)
|
||||
: group(guard.group), shape(guard.shape)
|
||||
{}
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* vm_ReceiverGuard_h */
|
Загрузка…
Ссылка в новой задаче