зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1625212 - Add CellHeaderWithTenuredGCPointer and use it for Shape r=sfink
Differential Revision: https://phabricator.services.mozilla.com/D68831 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
42cc5e671d
Коммит
ecbd72e069
|
@ -679,6 +679,62 @@ class CellHeaderWithNonGCPointer : public CellHeader {
|
|||
}
|
||||
};
|
||||
|
||||
// Base class for GC things that have a tenured GC pointer as their first word.
|
||||
//
|
||||
// The low bits of the first word (see CellFlagBitsReservedForGC) are reserved
|
||||
// for GC.
|
||||
//
|
||||
// This includes a pre write barrier when the pointer is update. No post barrier
|
||||
// is necessary as the pointer is always tenured.
|
||||
template <class PtrT>
|
||||
class CellHeaderWithTenuredGCPointer : public CellHeader {
|
||||
static_assert(!std::is_pointer<PtrT>::value,
|
||||
"PtrT should be the type of the referent, not of the pointer");
|
||||
static_assert(
|
||||
std::is_base_of<Cell, PtrT>::value,
|
||||
"Only use CellHeaderWithTenuredGCPointer for pointers to GC things");
|
||||
|
||||
public:
|
||||
CellHeaderWithTenuredGCPointer() = default;
|
||||
explicit CellHeaderWithTenuredGCPointer(PtrT* initial) : CellHeader() {
|
||||
initPtr(initial);
|
||||
}
|
||||
|
||||
void initPtr(PtrT* initial) {
|
||||
MOZ_ASSERT(!IsInsideNursery(initial));
|
||||
uintptr_t data = uintptr_t(initial);
|
||||
MOZ_ASSERT((data & RESERVED_MASK) == 0);
|
||||
this->header_ = data;
|
||||
}
|
||||
|
||||
PtrT* ptr() const {
|
||||
// Currently we never observe any flags set here because this base class is
|
||||
// only used for GC things that are always tenured (for which the nursery
|
||||
// kind flags are also always clear). This means we don't need to use
|
||||
// masking to get and set the pointer.
|
||||
MOZ_ASSERT(flags() == 0);
|
||||
return reinterpret_cast<PtrT*>(this->header_);
|
||||
}
|
||||
|
||||
void setPtr(PtrT* newValue) {
|
||||
// As above, no flags are expected to be set here.
|
||||
MOZ_ASSERT(!IsInsideNursery(newValue));
|
||||
PtrT::writeBarrierPre(ptr());
|
||||
unsafeSetPtr(newValue);
|
||||
}
|
||||
|
||||
void unsafeSetPtr(PtrT* newValue) {
|
||||
uintptr_t data = uintptr_t(newValue);
|
||||
MOZ_ASSERT(flags() == 0);
|
||||
MOZ_ASSERT((data & RESERVED_MASK) == 0);
|
||||
this->header_ = data;
|
||||
}
|
||||
|
||||
static constexpr size_t offsetOfPtr() {
|
||||
return offsetof(CellHeaderWithTenuredGCPointer, header_);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -1126,7 +1126,7 @@ void BaseScript::traceChildren(JSTracer* trc) {
|
|||
}
|
||||
|
||||
void Shape::traceChildren(JSTracer* trc) {
|
||||
TraceEdge(trc, &base_, "base");
|
||||
TraceEdge(trc, &headerAndBase_, "base");
|
||||
TraceEdge(trc, &propidRef(), "propid");
|
||||
if (parent) {
|
||||
TraceEdge(trc, &parent, "parent");
|
||||
|
|
|
@ -131,6 +131,17 @@ inline void TraceEdge(JSTracer* trc, WeakHeapPtr<T>* thingp, const char* name) {
|
|||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp->unsafeGet()), name);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void TraceEdge(JSTracer* trc,
|
||||
gc::CellHeaderWithTenuredGCPointer<T>* thingp,
|
||||
const char* name) {
|
||||
T* thing = thingp->ptr();
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(&thing), name);
|
||||
if (thing != thingp->ptr()) {
|
||||
thingp->unsafeSetPtr(thing);
|
||||
}
|
||||
}
|
||||
|
||||
// Trace through a possibly-null edge in the live object graph on behalf of
|
||||
// tracing.
|
||||
|
||||
|
@ -150,6 +161,19 @@ inline void TraceNullableEdge(JSTracer* trc, WeakHeapPtr<T>* thingp,
|
|||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void TraceNullableEdge(JSTracer* trc,
|
||||
gc::CellHeaderWithTenuredGCPointer<T>* thingp,
|
||||
const char* name) {
|
||||
T* thing = thingp->ptr();
|
||||
if (thing) {
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(&thing), name);
|
||||
if (thing != thingp->ptr()) {
|
||||
thingp->unsafeSetPtr(thing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trace through a "root" edge. These edges are the initial edges in the object
|
||||
// graph traversal. Root edges are asserted to only be traversed in the initial
|
||||
// phase of a GC.
|
||||
|
|
|
@ -125,9 +125,9 @@ inline Shape* Shape::new_(JSContext* cx, Handle<StackShape> other,
|
|||
}
|
||||
|
||||
inline void Shape::updateBaseShapeAfterMovingGC() {
|
||||
BaseShape* base = base_;
|
||||
BaseShape* base = this->base();
|
||||
if (IsForwarded(base)) {
|
||||
base_.unsafeSet(Forwarded(base));
|
||||
headerAndBase_.unsafeSetPtr(Forwarded(base));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ bool Shape::makeOwnBaseShape(JSContext* cx) {
|
|||
new (nbase) BaseShape(StackBaseShape(this));
|
||||
nbase->setOwned(base()->toUnowned());
|
||||
|
||||
this->base_ = nbase;
|
||||
setBase(nbase);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -155,10 +155,10 @@ void Shape::handoffTableTo(Shape* shape) {
|
|||
MOZ_ASSERT_IF(!shape->isEmptyShape() && shape->isDataProperty(),
|
||||
nbase->slotSpan() > shape->slot());
|
||||
|
||||
this->base_ = nbase->baseUnowned();
|
||||
setBase(nbase->baseUnowned());
|
||||
nbase->adoptUnowned(shape->base()->toUnowned());
|
||||
|
||||
shape->base_ = nbase;
|
||||
shape->setBase(nbase);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -1090,7 +1090,7 @@ Shape* NativeObject::putDataProperty(JSContext* cx, HandleNativeObject obj,
|
|||
if (updateLast) {
|
||||
shape->base()->adoptUnowned(nbase);
|
||||
} else {
|
||||
shape->base_ = nbase;
|
||||
shape->setBase(nbase);
|
||||
}
|
||||
|
||||
shape->setSlot(slot);
|
||||
|
@ -1196,7 +1196,7 @@ Shape* NativeObject::putAccessorProperty(JSContext* cx, HandleNativeObject obj,
|
|||
if (updateLast) {
|
||||
shape->base()->adoptUnowned(nbase);
|
||||
} else {
|
||||
shape->base_ = nbase;
|
||||
shape->setBase(nbase);
|
||||
}
|
||||
|
||||
shape->setSlot(SHAPE_INVALID_SLOT);
|
||||
|
@ -1324,7 +1324,7 @@ bool NativeObject::removeProperty(JSContext* cx, HandleNativeObject obj,
|
|||
if (!nbase) {
|
||||
return false;
|
||||
}
|
||||
previous->base_ = nbase;
|
||||
previous->setBase(nbase);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -947,7 +947,8 @@ class Shape : public gc::TenuredCell {
|
|||
friend class js::gc::RelocationOverlay;
|
||||
|
||||
protected:
|
||||
GCPtrBaseShape base_;
|
||||
using HeaderWithBaseShape = gc::CellHeaderWithTenuredGCPointer<BaseShape>;
|
||||
HeaderWithBaseShape headerAndBase_;
|
||||
const GCPtrId propid_;
|
||||
|
||||
// Flags that are not modified after the Shape is created. Off-thread Ion
|
||||
|
@ -1272,7 +1273,7 @@ class Shape : public gc::TenuredCell {
|
|||
attrs == aattrs && getter() == rawGetter && setter() == rawSetter;
|
||||
}
|
||||
|
||||
BaseShape* base() const { return base_.get(); }
|
||||
BaseShape* base() const { return headerAndBase_.ptr(); }
|
||||
|
||||
static bool isDataProperty(unsigned attrs, GetterOp getter, SetterOp setter) {
|
||||
return !(attrs & (JSPROP_GETTER | JSPROP_SETTER)) && !getter && !setter;
|
||||
|
@ -1370,6 +1371,11 @@ class Shape : public gc::TenuredCell {
|
|||
}
|
||||
|
||||
private:
|
||||
void setBase(BaseShape* base) {
|
||||
MOZ_ASSERT(base);
|
||||
headerAndBase_.setPtr(base);
|
||||
}
|
||||
|
||||
bool isBigEnoughForAShapeTableSlow() {
|
||||
uint32_t count = 0;
|
||||
for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront()) {
|
||||
|
@ -1419,6 +1425,7 @@ class Shape : public gc::TenuredCell {
|
|||
void removeChild(JSFreeOp* fop, Shape* child);
|
||||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::Shape;
|
||||
const gc::CellHeader& cellHeader() const { return headerAndBase_; }
|
||||
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
||||
|
@ -1430,7 +1437,9 @@ class Shape : public gc::TenuredCell {
|
|||
void updateBaseShapeAfterMovingGC();
|
||||
|
||||
// For JIT usage.
|
||||
static inline size_t offsetOfBaseShape() { return offsetof(Shape, base_); }
|
||||
static constexpr size_t offsetOfBaseShape() {
|
||||
return offsetof(Shape, headerAndBase_) + HeaderWithBaseShape::offsetOfPtr();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline size_t offsetOfImmutableFlags() {
|
||||
|
@ -1444,7 +1453,7 @@ class Shape : public gc::TenuredCell {
|
|||
void fixupShapeTreeAfterMovingGC();
|
||||
|
||||
static void staticAsserts() {
|
||||
static_assert(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
|
||||
static_assert(offsetOfBaseShape() == offsetof(js::shadow::Shape, base));
|
||||
static_assert(offsetof(Shape, immutableFlags) ==
|
||||
offsetof(js::shadow::Shape, immutableFlags));
|
||||
static_assert(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT);
|
||||
|
@ -1712,7 +1721,7 @@ class MutableWrappedPtrOperations<StackShape, Wrapper>
|
|||
};
|
||||
|
||||
inline Shape::Shape(const StackShape& other, uint32_t nfixed)
|
||||
: base_(other.base),
|
||||
: headerAndBase_(other.base),
|
||||
propid_(other.propid),
|
||||
immutableFlags(other.immutableFlags),
|
||||
attrs(other.attrs),
|
||||
|
@ -1744,7 +1753,7 @@ class NurseryShapesRef : public gc::BufferableRef {
|
|||
};
|
||||
|
||||
inline Shape::Shape(UnownedBaseShape* base, uint32_t nfixed)
|
||||
: base_(base),
|
||||
: headerAndBase_(base),
|
||||
propid_(JSID_EMPTY),
|
||||
immutableFlags(SHAPE_INVALID_SLOT | (nfixed << FIXED_SLOTS_SHIFT)),
|
||||
attrs(0),
|
||||
|
|
Загрузка…
Ссылка в новой задаче