Bug 1157703 - Cache iterators involving unboxed objects, r=jandem.

This commit is contained in:
Brian Hackett 2015-05-03 15:27:12 -07:00
Родитель 21b619291a
Коммит 6eb4312856
11 изменённых файлов: 392 добавлений и 282 удалений

Просмотреть файл

@ -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");
}

137
js/src/vm/ReceiverGuard.h Normal file
Просмотреть файл

@ -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 */