зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1102525 (part 3) - Replace SegmentedArray with mozilla::SegmentedVector in the cycle collector. r=smaug.
--HG-- extra : rebase_source : fb8b9f52958d6823dc011892b06bf42989a60a75
This commit is contained in:
Родитель
8225c5d531
Коммит
2e23aeecb5
|
@ -157,8 +157,9 @@
|
|||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
/* This must occur *after* base/process_util.h to avoid typedefs conflicts. */
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/SegmentedVector.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCycleCollectionNoteRootCallback.h"
|
||||
|
@ -2466,77 +2467,6 @@ MayHaveChild(void* aObj, nsCycleCollectionParticipant* aCp)
|
|||
return cf.MayHaveChild();
|
||||
}
|
||||
|
||||
template<class T, size_t N>
|
||||
class SegmentedArrayElement
|
||||
: public LinkedListElement<SegmentedArrayElement<T, N>>
|
||||
, public AutoFallibleTArray<T, N>
|
||||
{
|
||||
};
|
||||
|
||||
// For a given segment size (in bytes), compute the number of T elements
|
||||
// that can fit into it.
|
||||
template<typename T, size_t IdealSegmentSize>
|
||||
class SegmentedArrayCapacity
|
||||
{
|
||||
static const size_t kSingleElemSegmentSize =
|
||||
sizeof(SegmentedArrayElement<T, 1>);
|
||||
|
||||
public:
|
||||
static const size_t value =
|
||||
(IdealSegmentSize - kSingleElemSegmentSize) / sizeof(T) + 1;
|
||||
|
||||
static const size_t kActualSegmentSize =
|
||||
sizeof(SegmentedArrayElement<T, value>);
|
||||
};
|
||||
|
||||
template<class T, size_t N>
|
||||
class SegmentedArray
|
||||
{
|
||||
typedef SegmentedArrayElement<T, N> Segment;
|
||||
|
||||
public:
|
||||
~SegmentedArray()
|
||||
{
|
||||
MOZ_ASSERT(IsEmpty());
|
||||
}
|
||||
|
||||
void AppendElement(T& aElement)
|
||||
{
|
||||
Segment* last = mSegments.getLast();
|
||||
if (!last || last->Length() == last->Capacity()) {
|
||||
last = new Segment();
|
||||
mSegments.insertBack(last);
|
||||
}
|
||||
last->AppendElement(aElement);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
Segment* first;
|
||||
while ((first = mSegments.popFirst())) {
|
||||
delete first;
|
||||
}
|
||||
}
|
||||
|
||||
Segment* GetFirstSegment()
|
||||
{
|
||||
return mSegments.getFirst();
|
||||
}
|
||||
|
||||
const Segment* GetFirstSegment() const
|
||||
{
|
||||
return mSegments.getFirst();
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return !GetFirstSegment();
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::LinkedList<Segment> mSegments;
|
||||
};
|
||||
|
||||
// JSPurpleBuffer keeps references to GCThings which might affect the
|
||||
// next cycle collection. It is owned only by itself and during unlink its
|
||||
// self reference is broken down and the object ends up killing itself.
|
||||
|
@ -2553,6 +2483,8 @@ class JSPurpleBuffer
|
|||
public:
|
||||
explicit JSPurpleBuffer(JSPurpleBuffer*& aReferenceToThis)
|
||||
: mReferenceToThis(aReferenceToThis)
|
||||
, mValues(kSegmentSize)
|
||||
, mObjects(kSegmentSize)
|
||||
{
|
||||
mReferenceToThis = this;
|
||||
NS_ADDREF_THIS();
|
||||
|
@ -2577,8 +2509,9 @@ public:
|
|||
// pointers which may point into the nursery. The purple buffer never contains
|
||||
// pointers to the nursery because nursery gcthings can never be gray and only
|
||||
// gray things can be inserted into the purple buffer.
|
||||
SegmentedArray<JS::Value, 60> mValues;
|
||||
SegmentedArray<JSObject*, 60> mObjects;
|
||||
static const size_t kSegmentSize = 512;
|
||||
SegmentedVector<JS::Value, kSegmentSize, InfallibleAllocPolicy> mValues;
|
||||
SegmentedVector<JSObject*, kSegmentSize, InfallibleAllocPolicy> mObjects;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(JSPurpleBuffer)
|
||||
|
@ -2594,13 +2527,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
|
||||
#define NS_TRACE_SEGMENTED_ARRAY(_field, _type) \
|
||||
{ \
|
||||
auto segment = tmp->_field.GetFirstSegment(); \
|
||||
while (segment) { \
|
||||
for (uint32_t i = segment->Length(); i > 0;) { \
|
||||
for (auto iter = tmp->_field.Iter(); !iter.Done(); iter.Next()) { \
|
||||
js::gc::CallTraceCallbackOnNonHeap<_type, TraceCallbacks>( \
|
||||
&segment->ElementAt(--i), aCallbacks, #_field, aClosure); \
|
||||
} \
|
||||
segment = segment->getNext(); \
|
||||
&iter.Get(), aCallbacks, #_field, aClosure); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -2622,24 +2551,22 @@ class SnowWhiteKiller : public TraceCallbacks
|
|||
};
|
||||
|
||||
// Segments are 4 KiB on 32-bit and 8 KiB on 64-bit.
|
||||
static const size_t kSegmentCapacity =
|
||||
SegmentedArrayCapacity<SnowWhiteObject, sizeof(void*) * 1024>::value;
|
||||
typedef SegmentedArray<SnowWhiteObject, kSegmentCapacity> ObjectsArray;
|
||||
static const size_t kSegmentSize = sizeof(void*) * 1024;
|
||||
typedef SegmentedVector<SnowWhiteObject, kSegmentSize, InfallibleAllocPolicy>
|
||||
ObjectsVector;
|
||||
|
||||
public:
|
||||
SnowWhiteKiller(nsCycleCollector* aCollector, uint32_t aMaxCount)
|
||||
: mCollector(aCollector)
|
||||
, mObjects()
|
||||
, mObjects(kSegmentSize)
|
||||
{
|
||||
MOZ_ASSERT(mCollector, "Calling SnowWhiteKiller after nsCC went away");
|
||||
}
|
||||
|
||||
~SnowWhiteKiller()
|
||||
{
|
||||
auto segment = mObjects.GetFirstSegment();
|
||||
while (segment) {
|
||||
for (uint32_t i = 0; i < segment->Length(); i++) {
|
||||
SnowWhiteObject& o = segment->ElementAt(i);
|
||||
for (auto iter = mObjects.Iter(); !iter.Done(); iter.Next()) {
|
||||
SnowWhiteObject& o = iter.Get();
|
||||
if (!o.mRefCnt->get() && !o.mRefCnt->IsInPurpleBuffer()) {
|
||||
mCollector->RemoveObjectFromGraph(o.mPointer);
|
||||
o.mRefCnt->stabilizeForDeletion();
|
||||
|
@ -2647,9 +2574,6 @@ public:
|
|||
o.mParticipant->DeleteCycleCollectable(o.mPointer);
|
||||
}
|
||||
}
|
||||
segment = segment->getNext();
|
||||
}
|
||||
mObjects.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2661,7 +2585,7 @@ public:
|
|||
nsCycleCollectionParticipant* cp = aEntry->mParticipant;
|
||||
CanonicalizeParticipant(&o, &cp);
|
||||
SnowWhiteObject swo = { o, cp, aEntry->mRefCnt };
|
||||
mObjects.AppendElement(swo);
|
||||
mObjects.InfallibleAppend(swo);
|
||||
aBuffer.Remove(aEntry);
|
||||
}
|
||||
}
|
||||
|
@ -2679,7 +2603,7 @@ public:
|
|||
void* thing = val.toGCThing();
|
||||
if (thing && xpc_GCThingIsGrayCCThing(thing)) {
|
||||
MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell*)thing));
|
||||
mCollector->GetJSPurpleBuffer()->mValues.AppendElement(val);
|
||||
mCollector->GetJSPurpleBuffer()->mValues.InfallibleAppend(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2693,7 +2617,7 @@ public:
|
|||
{
|
||||
if (obj && xpc_GCThingIsGrayCCThing(obj)) {
|
||||
MOZ_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(obj)));
|
||||
mCollector->GetJSPurpleBuffer()->mObjects.AppendElement(obj);
|
||||
mCollector->GetJSPurpleBuffer()->mObjects.InfallibleAppend(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2726,7 +2650,7 @@ public:
|
|||
|
||||
private:
|
||||
nsCycleCollector* mCollector;
|
||||
ObjectsArray mObjects;
|
||||
ObjectsVector mObjects;
|
||||
};
|
||||
|
||||
class RemoveSkippableVisitor : public SnowWhiteKiller
|
||||
|
@ -3261,9 +3185,9 @@ nsCycleCollector::CollectWhite()
|
|||
// - Unroot(whites), which returns the whites to normal GC.
|
||||
|
||||
// Segments are 4 KiB on 32-bit and 8 KiB on 64-bit.
|
||||
static const size_t cap =
|
||||
SegmentedArrayCapacity<PtrInfo*, sizeof(void*) * 1024>::value;
|
||||
SegmentedArray<PtrInfo*, cap> whiteNodes;
|
||||
static const size_t kSegmentSize = sizeof(void*) * 1024;
|
||||
SegmentedVector<PtrInfo*, kSegmentSize, InfallibleAllocPolicy>
|
||||
whiteNodes(kSegmentSize);
|
||||
TimeLog timeLog;
|
||||
|
||||
MOZ_ASSERT(mIncrementalPhase == ScanAndCollectWhitePhase);
|
||||
|
@ -3286,7 +3210,7 @@ nsCycleCollector::CollectWhite()
|
|||
++numWhiteJSZones;
|
||||
}
|
||||
} else {
|
||||
whiteNodes.AppendElement(pinfo);
|
||||
whiteNodes.InfallibleAppend(pinfo);
|
||||
pinfo->mParticipant->Root(pinfo->mPointer);
|
||||
++numWhiteNodes;
|
||||
}
|
||||
|
@ -3307,10 +3231,8 @@ nsCycleCollector::CollectWhite()
|
|||
// Unlink() can trigger a GC, so do not touch any JS or anything
|
||||
// else not in whiteNodes after here.
|
||||
|
||||
auto segment = whiteNodes.GetFirstSegment();
|
||||
while (segment) {
|
||||
for (uint32_t i = 0; i < segment->Length(); i++) {
|
||||
PtrInfo* pinfo = segment->ElementAt(i);
|
||||
for (auto iter = whiteNodes.Iter(); !iter.Done(); iter.Next()) {
|
||||
PtrInfo* pinfo = iter.Get();
|
||||
MOZ_ASSERT(pinfo->mParticipant,
|
||||
"Unlink shouldn't see objects removed from graph.");
|
||||
pinfo->mParticipant->Unlink(pinfo->mPointer);
|
||||
|
@ -3320,20 +3242,14 @@ nsCycleCollector::CollectWhite()
|
|||
}
|
||||
#endif
|
||||
}
|
||||
segment = segment->getNext();
|
||||
}
|
||||
timeLog.Checkpoint("CollectWhite::Unlink");
|
||||
|
||||
segment = whiteNodes.GetFirstSegment();
|
||||
while (segment) {
|
||||
for (uint32_t i = 0; i < segment->Length(); i++) {
|
||||
PtrInfo* pinfo = segment->ElementAt(i);
|
||||
for (auto iter = whiteNodes.Iter(); !iter.Done(); iter.Next()) {
|
||||
PtrInfo* pinfo = iter.Get();
|
||||
MOZ_ASSERT(pinfo->mParticipant,
|
||||
"Unroot shouldn't see objects removed from graph.");
|
||||
pinfo->mParticipant->Unroot(pinfo->mPointer);
|
||||
}
|
||||
segment = segment->getNext();
|
||||
}
|
||||
timeLog.Checkpoint("CollectWhite::Unroot");
|
||||
|
||||
nsCycleCollector_dispatchDeferredDeletion(false);
|
||||
|
@ -3341,8 +3257,6 @@ nsCycleCollector::CollectWhite()
|
|||
|
||||
mIncrementalPhase = CleanupPhase;
|
||||
|
||||
whiteNodes.Clear();
|
||||
|
||||
return numWhiteNodes > 0 || numWhiteGCed > 0 || numWhiteJSZones > 0;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче