Bug 1268541 - Compact arenas containing base shapes r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 29 Apr 2016 10:44:22 +0100
changeset 295432 b10abfa0ce4861480b80c58f9232753f586fd23f
parent 295431 05c1151be7a7821136263bb46d887bf8e99ce64d
child 295433 33f5b0151b8b1a3d2cc1e8779c28616a5dba2971
push id30223
push userkwierso@gmail.com
push dateFri, 29 Apr 2016 21:57:49 +0000
treeherdermozilla-central@2b7c421063ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1268541
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1268541 - Compact arenas containing base shapes r=terrence
js/src/gc/GCInternals.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jspropertytree.cpp
js/src/vm/Shape-inl.h
js/src/vm/Shape.cpp
js/src/vm/Shape.h
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -123,16 +123,17 @@ struct MovingTracer : JS::CallbackTracer
 {
     explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
 
     void onObjectEdge(JSObject** objp) override;
     void onShapeEdge(Shape** shapep) override;
     void onStringEdge(JSString** stringp) override;
     void onScriptEdge(JSScript** scriptp) override;
     void onLazyScriptEdge(LazyScript** lazyp) override;
+    void onBaseShapeEdge(BaseShape** basep) override;
     void onChild(const JS::GCCellPtr& thing) override {
         MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
     }
 
 #ifdef DEBUG
     TracerKind getTracerKind() const override { return TracerKind::Moving; }
 #endif
 };
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2036,16 +2036,17 @@ static const AllocKind AllocKindsToReloc
     AllocKind::OBJECT12,
     AllocKind::OBJECT12_BACKGROUND,
     AllocKind::OBJECT16,
     AllocKind::OBJECT16_BACKGROUND,
     AllocKind::SCRIPT,
     AllocKind::LAZY_SCRIPT,
     AllocKind::SHAPE,
     AllocKind::ACCESSOR_SHAPE,
+    AllocKind::BASE_SHAPE,
     AllocKind::FAT_INLINE_STRING,
     AllocKind::STRING,
     AllocKind::EXTERNAL_STRING
 };
 
 Arena*
 ArenaList::removeRemainingArenas(Arena** arenap)
 {
@@ -2410,16 +2411,24 @@ void
 MovingTracer::onLazyScriptEdge(LazyScript** lazyp)
 {
     LazyScript* lazy = *lazyp;
     if (IsForwarded(lazy))
         *lazyp = Forwarded(lazy);
 }
 
 void
+MovingTracer::onBaseShapeEdge(BaseShape** basep)
+{
+    BaseShape* base = *basep;
+    if (IsForwarded(base))
+        *basep = Forwarded(base);
+}
+
+void
 Zone::prepareForCompacting()
 {
     FreeOp* fop = runtimeFromMainThread()->defaultFreeOp();
     discardJitCode(fop);
 }
 
 void
 GCRuntime::sweepTypesAfterCompacting(Zone* zone)
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1100,16 +1100,17 @@ struct MightBeForwarded
 {
     static_assert(mozilla::IsBaseOf<Cell, T>::value,
                   "T must derive from Cell");
     static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
                   "T must not be Cell or TenuredCell");
 
     static const bool value = mozilla::IsBaseOf<JSObject, T>::value ||
                               mozilla::IsBaseOf<Shape, T>::value ||
+                              mozilla::IsBaseOf<BaseShape, T>::value ||
                               mozilla::IsBaseOf<JSString, T>::value ||
                               mozilla::IsBaseOf<JSScript, T>::value ||
                               mozilla::IsBaseOf<js::LazyScript, T>::value;
 };
 
 template <typename T>
 inline bool
 IsForwarded(T* t)
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -234,17 +234,17 @@ Shape::fixupDictionaryShapeAfterMovingGC
         return;
     }
 
     // The listp field either points to the parent field of the next shape in
     // the list if there is one.  Otherwise if this shape is the last in the
     // list then it points to the shape_ field of the object the list is for.
     // We can tell which it is because the base shape is owned if this is the
     // last property and not otherwise.
-    bool listpPointsIntoShape = !base()->isOwned();
+    bool listpPointsIntoShape = !MaybeForwarded(base())->isOwned();
 
 #ifdef DEBUG
     // Check that we got this right by interrogating the arena.
     // We use a fake cell pointer for this: it might not point to the beginning
     // of a cell, but will point into the right arena and will have the right
     // alignment.
     Cell* cell = reinterpret_cast<Cell*>(uintptr_t(listp) & ~CellMask);
     AllocKind kind = TenuredCell::fromPointer(cell)->getAllocKind();
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -93,16 +93,24 @@ Shape::new_(ExclusiveContext* cx, Handle
     if (other.isAccessorShape())
         new (shape) AccessorShape(other, nfixed);
     else
         new (shape) Shape(other, nfixed);
 
     return shape;
 }
 
+inline void
+Shape::updateBaseShapeAfterMovingGC()
+{
+    BaseShape* base = base_.unbarrieredGet();
+    if (IsForwarded(base))
+        base_.unsafeSet(Forwarded(base));
+}
+
 template<class ObjectSubclass>
 /* static */ inline bool
 EmptyShape::ensureInitialCustomShape(ExclusiveContext* cx, Handle<ObjectSubclass*> obj)
 {
     static_assert(mozilla::IsBaseOf<JSObject, ObjectSubclass>::value,
                   "ObjectSubclass must be a subclass of JSObject");
 
     // If the provided object has a non-empty shape, it was given the cached
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1330,27 +1330,27 @@ BaseShape::traceChildren(JSTracer* trc)
 {
     traceChildrenSkipShapeTable(trc);
     traceShapeTable(trc);
 }
 
 void
 BaseShape::traceChildrenSkipShapeTable(JSTracer* trc)
 {
-    assertConsistency();
-
     if (trc->isMarkingTracer())
         compartment()->mark();
 
     if (isOwned())
         TraceEdge(trc, &unowned_, "base");
 
     JSObject* global = compartment()->unsafeUnbarrieredMaybeGlobal();
     if (global)
         TraceManuallyBarrieredEdge(trc, &global, "global");
+
+    assertConsistency();
 }
 
 void
 BaseShape::traceShapeTable(JSTracer* trc)
 {
     if (hasTable())
         table().trace(trc);
 }
@@ -1584,16 +1584,17 @@ JSCompartment::fixupInitialShapeTable()
 
     for (decltype(initialShapes)::Enum e(initialShapes); !e.empty(); e.popFront()) {
         // The shape may have been moved, but we can update that in place.
         Shape* shape = e.front().shape.unbarrieredGet();
         if (IsForwarded(shape)) {
             shape = Forwarded(shape);
             e.mutableFront().shape.set(shape);
         }
+        shape->updateBaseShapeAfterMovingGC();
 
         // If the prototype has moved we have to rekey the entry.
         InitialShapeEntry entry = e.front();
         if (entry.proto.isObject() && IsForwarded(entry.proto.toObject())) {
             entry.proto = TaggedProto(Forwarded(entry.proto.toObject()));
             InitialShapeEntry::Lookup relookup(shape->getObjectClass(),
                                                entry.proto,
                                                shape->numFixedSlots(),
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -958,16 +958,17 @@ class Shape : public gc::TenuredCell
 
     void traceChildren(JSTracer* trc);
 
     inline Shape* search(ExclusiveContext* cx, jsid id);
     inline Shape* searchLinear(jsid id);
 
     void fixupAfterMovingGC();
     void fixupGetterSetterForBarrier(JSTracer* trc);
+    void updateBaseShapeAfterMovingGC();
 
     /* For JIT usage */
     static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
     static inline size_t offsetOfSlotInfo() { return offsetof(Shape, slotInfo); }
     static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
 
   private:
     void fixupDictionaryShapeAfterMovingGC();