Merge mozilla-central and mozilla-inbound

This commit is contained in:
Matt Brubeck 2012-01-15 20:54:40 -08:00
commit 6618255819
6 changed files with 292 additions and 25 deletions

View File

@ -161,6 +161,33 @@ nsPropertyTable::Enumerate(nsPropertyOwner aObject,
}
}
struct PropertyEnumeratorData
{
nsIAtom* mName;
NSPropertyFunc mCallBack;
void* mData;
};
static PLDHashOperator
PropertyEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
PRUint32 aNumber, void* aArg)
{
PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(aHdr);
PropertyEnumeratorData* data = static_cast<PropertyEnumeratorData*>(aArg);
data->mCallBack(const_cast<void*>(entry->key), data->mName, entry->value,
data->mData);
return PL_DHASH_NEXT;
}
void
nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData)
{
for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
PropertyEnumeratorData data = { prop->mName, aCallBack, aData };
PL_DHashTableEnumerate(&prop->mObjectValueMap, PropertyEnumerator, &data);
}
}
void*
nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
nsIAtom *aPropertyName,

View File

@ -181,6 +181,13 @@ class nsPropertyTable
NS_HIDDEN_(void) Enumerate(nsPropertyOwner aObject,
NSPropertyFunc aCallback, void *aData);
/**
* Enumerate all the properties.
* For every property |aCallback| will be called with arguments the owner,
* the property name, the property value and |aData|.
*/
NS_HIDDEN_(void) EnumerateAll(NSPropertyFunc aCallback, void *aData);
/**
* Deletes all of the properties for all objects in the property
* table, calling the destructor function for each property.

View File

@ -867,6 +867,11 @@ public:
void SelectPointers(GCGraphBuilder &builder);
// RemoveSkippable removes entries from the purple buffer if
// nsPurpleBufferEntry::mObject is null or if the object's
// nsXPCOMCycleCollectionParticipant::CanSkip() returns true.
void RemoveSkippable();
#ifdef DEBUG_CC
void NoteAll(GCGraphBuilder &builder);
@ -985,8 +990,22 @@ void
nsPurpleBuffer::SelectPointers(GCGraphBuilder &aBuilder)
{
#ifdef DEBUG_CC
// Can't use mCount here, since it may include null entries.
PRUint32 realCount = 0;
for (Block *b = &mFirstBlock; b; b = b->mNext) {
for (nsPurpleBufferEntry *e = b->mEntries,
*eEnd = ArrayEnd(b->mEntries);
e != eEnd; ++e) {
if (!(PRUword(e->mObject) & PRUword(1))) {
if (e->mObject) {
++realCount;
}
}
}
}
NS_ABORT_IF_FALSE(mCompatObjects.Count() + mNormalObjects.Count() ==
mCount,
realCount,
"count out of sync");
#endif
@ -1006,16 +1025,7 @@ nsPurpleBuffer::SelectPointers(GCGraphBuilder &aBuilder)
// This is a real entry (rather than something on the
// free list).
if (!e->mObject || AddPurpleRoot(aBuilder, e->mObject)) {
#ifdef DEBUG_CC
mNormalObjects.RemoveEntry(e->mObject);
#endif
--mCount;
// Put this entry on the free list in case some
// call to AddPurpleRoot fails and we don't rebuild
// the free list below.
e->mNextInFreeList = (nsPurpleBufferEntry*)
(PRUword(mFreeList) | PRUword(1));
mFreeList = e;
Remove(e);
}
}
}
@ -1085,6 +1095,9 @@ struct nsCycleCollector
nsPurpleBuffer mPurpleBuf;
CC_BeforeUnlinkCallback mBeforeUnlinkCB;
CC_ForgetSkippableCallback mForgetSkippableCB;
void RegisterRuntime(PRUint32 langID,
nsCycleCollectionLanguageRuntime *rt);
nsCycleCollectionLanguageRuntime * GetRuntime(PRUint32 langID);
@ -1095,6 +1108,8 @@ struct nsCycleCollector
void ScanRoots();
void ScanWeakMaps();
void ForgetSkippable();
// returns whether anything was collected
bool CollectWhite(nsICycleCollectorListener *aListener);
@ -1139,6 +1154,8 @@ struct nsCycleCollector
void Allocated(void *n, size_t sz);
void Freed(void *n);
void LogPurpleRemoval(void* aObject);
void ExplainLiveExpectedGarbage();
bool CreateReversedEdges();
void DestroyReversedEdges();
@ -1772,7 +1789,8 @@ GCGraphBuilder::NoteXPCOMChild(nsISupports *child)
nsXPCOMCycleCollectionParticipant *cp;
ToParticipant(child, &cp);
if (cp) {
if (cp && !cp->CanSkipThis(child)) {
PtrInfo *childPi = AddNode(child, cp, nsIProgrammingLanguage::CPLUSPLUS);
if (!childPi)
return;
@ -1878,7 +1896,7 @@ GCGraphBuilder::AddWeakMapNode(void *node)
cp = mRuntimes[nsIProgrammingLanguage::JAVASCRIPT]->ToParticipant(node);
NS_ASSERTION(cp, "Javascript runtime participant should be non-null.");
return AddNode(node, cp);
return AddNode(node, cp, nsIProgrammingLanguage::JAVASCRIPT);
}
NS_IMETHODIMP_(void)
@ -1905,10 +1923,12 @@ AddPurpleRoot(GCGraphBuilder &builder, nsISupports *root)
nsXPCOMCycleCollectionParticipant *cp;
ToParticipant(root, &cp);
PtrInfo *pinfo = builder.AddNode(root, cp,
nsIProgrammingLanguage::CPLUSPLUS);
if (!pinfo) {
return false;
if (!cp->CanSkipInCC(root)) {
PtrInfo *pinfo = builder.AddNode(root, cp,
nsIProgrammingLanguage::CPLUSPLUS);
if (!pinfo) {
return false;
}
}
cp->UnmarkPurple(root);
@ -1916,6 +1936,32 @@ AddPurpleRoot(GCGraphBuilder &builder, nsISupports *root)
return true;
}
void
nsPurpleBuffer::RemoveSkippable()
{
// Walk through all the blocks.
for (Block *b = &mFirstBlock; b; b = b->mNext) {
for (nsPurpleBufferEntry *e = b->mEntries,
*eEnd = ArrayEnd(b->mEntries);
e != eEnd; ++e) {
if (!(PRUword(e->mObject) & PRUword(1))) {
// This is a real entry (rather than something on the
// free list).
if (e->mObject) {
nsISupports* o = canonicalize(e->mObject);
nsXPCOMCycleCollectionParticipant* cp;
ToParticipant(o, &cp);
if (!cp->CanSkip(o)) {
continue;
}
cp->UnmarkPurple(o);
}
Remove(e);
}
}
}
}
#ifdef DEBUG_CC
static PLDHashOperator
noteAllCallback(nsVoidPtrHashKey* key, void* userArg)
@ -1949,6 +1995,19 @@ nsCycleCollector::SelectPurple(GCGraphBuilder &builder)
mPurpleBuf.SelectPointers(builder);
}
void
nsCycleCollector::ForgetSkippable()
{
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nsnull, "cycle-collector-forget-skippable", nsnull);
}
mPurpleBuf.RemoveSkippable();
if (mForgetSkippableCB) {
mForgetSkippableCB();
}
}
void
nsCycleCollector::MarkRoots(GCGraphBuilder &builder)
{
@ -2130,6 +2189,9 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
}
}
if (mBeforeUnlinkCB) {
mBeforeUnlinkCB();
}
#if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
struct _CrtMemState ms1, ms2;
_CrtMemCheckpoint(&ms1);
@ -2387,10 +2449,12 @@ nsCycleCollector::nsCycleCollector() :
mVisitedGCed(0),
#ifdef DEBUG_CC
mPurpleBuf(mParams, mStats),
mPtrLog(nsnull)
mPtrLog(nsnull),
#else
mPurpleBuf(mParams)
mPurpleBuf(mParams),
#endif
mBeforeUnlinkCB(nsnull),
mForgetSkippableCB(nsnull)
{
#ifdef DEBUG_CC
mExpectedGarbage.Init();
@ -2657,6 +2721,27 @@ nsCycleCollector::Forget2(nsPurpleBufferEntry *e)
return false;
#ifdef DEBUG_CC
LogPurpleRemoval(e->mObject);
#endif
mPurpleBuf.Remove(e);
return true;
}
#ifdef DEBUG_CC
void
nsCycleCollector_logPurpleRemoval(void* aObject)
{
if (sCollector) {
sCollector->LogPurpleRemoval(aObject);
}
}
void
nsCycleCollector::LogPurpleRemoval(void* aObject)
{
AbortIfOffMainThreadIfCheckFast();
mStats.mForgetNode++;
#ifndef __MINGW32__
@ -2667,15 +2752,11 @@ nsCycleCollector::Forget2(nsPurpleBufferEntry *e)
if (mParams.mLogPointers) {
if (!mPtrLog)
mPtrLog = fopen("pointer_log", "w");
fprintf(mPtrLog, "F %p\n", static_cast<void*>(e->mObject));
fprintf(mPtrLog, "F %p\n", aObject);
}
#endif
mPurpleBuf.Remove(e);
return true;
mPurpleBuf.mNormalObjects.RemoveEntry(aObject);
}
#ifdef DEBUG_CC
void
nsCycleCollector::Allocated(void *n, size_t sz)
{
@ -3727,6 +3808,30 @@ nsCycleCollector_startup()
return rv;
}
void
nsCycleCollector_setBeforeUnlinkCallback(CC_BeforeUnlinkCallback aCB)
{
if (sCollector) {
sCollector->mBeforeUnlinkCB = aCB;
}
}
void
nsCycleCollector_setForgetSkippableCallback(CC_ForgetSkippableCallback aCB)
{
if (sCollector) {
sCollector->mForgetSkippableCB = aCB;
}
}
void
nsCycleCollector_forgetSkippable()
{
if (sCollector) {
sCollector->ForgetSkippable();
}
}
PRUint32
nsCycleCollector_collect(nsICycleCollectorListener *aListener)
{

View File

@ -63,6 +63,19 @@ struct nsCycleCollectionLanguageRuntime
};
nsresult nsCycleCollector_startup();
typedef void (*CC_BeforeUnlinkCallback)(void);
void nsCycleCollector_setBeforeUnlinkCallback(CC_BeforeUnlinkCallback aCB);
typedef void (*CC_ForgetSkippableCallback)(void);
void nsCycleCollector_setForgetSkippableCallback(CC_ForgetSkippableCallback aCB);
void nsCycleCollector_forgetSkippable();
#ifdef DEBUG_CC
void nsCycleCollector_logPurpleRemoval(void* aObject);
#endif
// Returns the number of collected nodes.
PRUint32 nsCycleCollector_collect(nsICycleCollectorListener *aListener);
PRUint32 nsCycleCollector_suspectedCount();

View File

@ -164,6 +164,9 @@ class NS_COM_GLUE nsXPCOMCycleCollectionParticipant
: public nsScriptObjectTracer
{
public:
nsXPCOMCycleCollectionParticipant() : mMightSkip(false) {}
nsXPCOMCycleCollectionParticipant(bool aSkip) : mMightSkip(aSkip) {}
NS_IMETHOD Traverse(void *p, nsCycleCollectionTraversalCallback &cb);
NS_IMETHOD Root(void *p);
@ -175,6 +178,49 @@ public:
NS_IMETHOD_(void) UnmarkPurple(nsISupports *p);
bool CheckForRightISupports(nsISupports *s);
// If CanSkip returns true, p is removed from the purple buffer during
// a call to nsCycleCollector_forgetSkippable().
// Note, calling CanSkip may remove objects from the purple buffer!
bool CanSkip(void *p)
{
return mMightSkip ? CanSkipReal(p) : false;
}
// If CanSkipInCC returns true, p is skipped when selecting roots for the
// cycle collector graph.
// Note, calling CanSkipInCC may remove other objects from the purple buffer!
bool CanSkipInCC(void *p)
{
return mMightSkip ? CanSkipInCCReal(p) : false;
}
// If CanSkipThis returns true, p is not added to the graph.
// This method is called during cycle collection, so don't
// change the state of any objects!
bool CanSkipThis(void *p)
{
return mMightSkip ? CanSkipThisReal(p) : false;
}
protected:
NS_IMETHOD_(bool) CanSkipReal(void *p)
{
NS_ASSERTION(false, "Forgot to implement CanSkipReal?");
return false;
}
NS_IMETHOD_(bool) CanSkipInCCReal(void *p)
{
NS_ASSERTION(false, "Forgot to implement CanSkipInCCReal?");
return false;
}
NS_IMETHOD_(bool) CanSkipThisReal(void *p)
{
NS_ASSERTION(false, "Forgot to implement CanSkipThisReal?");
return false;
}
private:
bool mMightSkip;
};
#undef IMETHOD_VISIBILITY
@ -245,6 +291,45 @@ public:
#define NS_CYCLE_COLLECTION_UPCAST(obj, clazz) \
NS_CYCLE_COLLECTION_CLASSNAME(clazz)::Upcast(obj)
#define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(_class) \
NS_IMETHODIMP_(bool) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipReal(void *p) \
{ \
nsISupports *s = static_cast<nsISupports*>(p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = Downcast(s);
#define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END \
return false; \
}
#define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(_class) \
NS_IMETHODIMP_(bool) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipInCCReal(void *p) \
{ \
nsISupports *s = static_cast<nsISupports*>(p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = Downcast(s);
#define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END \
return false; \
}
#define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(_class) \
NS_IMETHODIMP_(bool) \
NS_CYCLE_COLLECTION_CLASSNAME(_class)::CanSkipThisReal(void *p) \
{ \
nsISupports *s = static_cast<nsISupports*>(p); \
NS_ASSERTION(CheckForRightISupports(s), \
"not the nsISupports pointer we expect"); \
_class *tmp = Downcast(s);
#define NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END \
return false; \
}
///////////////////////////////////////////////////////////////////////////////
// Helpers for implementing nsCycleCollectionParticipant::Unlink
///////////////////////////////////////////////////////////////////////////////
@ -552,6 +637,24 @@ class NS_CYCLE_COLLECTION_INNERCLASS \
}; \
NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
#define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _base) \
class NS_CYCLE_COLLECTION_INNERCLASS \
: public nsXPCOMCycleCollectionParticipant \
{ \
public: \
NS_CYCLE_COLLECTION_INNERCLASS () : nsXPCOMCycleCollectionParticipant(true) {} \
NS_DECL_CYCLE_COLLECTION_CLASS_BODY(_class, _base) \
NS_IMETHOD_(void) Trace(void *p, TraceCallback cb, void *closure); \
protected: \
NS_IMETHOD_(bool) CanSkipReal(void *p); \
NS_IMETHOD_(bool) CanSkipInCCReal(void *p); \
NS_IMETHOD_(bool) CanSkipThisReal(void *p); \
}; \
NS_CYCLE_COLLECTION_PARTICIPANT_INSTANCE
#define NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(_class) \
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class)
#define NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(_class) \
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(_class, _class)

View File

@ -226,6 +226,18 @@ public:
mTagged = NS_CCAR_REFCNT_TO_TAGGED(refcount);
}
void RemovePurple()
{
NS_ASSERTION(IsPurple(), "must be purple");
#ifdef DEBUG_CC
nsCycleCollector_logPurpleRemoval(
NS_CCAR_TAGGED_TO_PURPLE_ENTRY(mTagged)->mObject);
#endif
// The entry will be added to the free list later.
NS_CCAR_TAGGED_TO_PURPLE_ENTRY(mTagged)->mObject = nsnull;
unmarkPurple();
}
bool IsPurple() const
{
NS_ASSERTION(mTagged != NS_CCAR_TAGGED_STABILIZED_REFCNT,