Bug 806279 - CC macros refactoring: part 1: implement type-generic CC UNLINK/TRAVERSE macros - r=mccr8,smaug

This commit is contained in:
Benoit Jacob 2012-11-15 02:32:39 -05:00
parent 663ba004c2
commit 4a50000d0e
13 changed files with 369 additions and 90 deletions

View File

@ -1399,7 +1399,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebGLContext)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentProgram)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoundFramebuffer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBoundRenderbuffer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mAttribBuffers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttribBuffers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

View File

@ -12,6 +12,7 @@
#include "nsTArray.h"
#include "nsDataHashtable.h"
#include "nsHashKeys.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsIDocShell.h"
@ -1526,11 +1527,6 @@ struct WebGLVertexAttribData {
if (stride) return stride;
return size * componentSize();
}
// for cycle collection
WebGLBuffer* get() {
return buf.get();
}
};
class WebGLBuffer MOZ_FINAL
@ -3452,6 +3448,39 @@ private:
WebGLContext *mContext;
};
} // namespace mozilla
inline void ImplCycleCollectionUnlink(mozilla::WebGLVertexAttribData& aField)
{
aField.buf = nullptr;
}
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
mozilla::WebGLVertexAttribData& aField,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField.buf);
}
template <typename T>
inline void
ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& aField)
{
aField = nullptr;
}
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
mozilla::WebGLRefPtr<T>& aField,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField);
}
#endif

View File

@ -9,6 +9,7 @@
#include "nsCOMPtr.h"
#include "nsWeakReference.h"
#include "nsTArray.h"
#include "nsCycleCollectionNoteChild.h"
// nsMaybeWeakPtr is a helper object to hold a strong-or-weak reference
// to the template class. It's pretty minimal, but sufficient.
@ -70,6 +71,28 @@ public:
}
};
template <typename T>
inline void
ImplCycleCollectionUnlink(nsMaybeWeakPtrArray<T>& aField)
{
aField.Clear();
}
template <typename E>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsMaybeWeakPtrArray<E>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Length();
for (size_t i = 0; i < length; ++i) {
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField[i]);
}
}
// Call a method on each element in the array, but only if the element is
// non-null.

View File

@ -14,6 +14,8 @@
#include "nsCOMPtr.h"
#endif
#include "nsCycleCollectionNoteChild.h"
/*****************************************************************************/
// template <class T> class nsAutoPtrGetterTransfers;
@ -1072,6 +1074,24 @@ class nsRefPtr
}
};
template <typename T>
inline void
ImplCycleCollectionUnlink(nsRefPtr<T>& aField)
{
aField = nullptr;
}
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsRefPtr<T>& aField,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField);
}
template <class T>
inline
nsRefPtr<T>*

View File

@ -88,6 +88,8 @@ EXPORTS = \
nsProxyRelease.h \
nsXPTCUtils.h \
nsCycleCollectorUtils.h \
nsCycleCollectionNoteChild.h \
nsCycleCollectionTraversalCallback.h \
$(NULL)
EXPORTS_mozilla = \

View File

@ -8,6 +8,7 @@
#include "mozilla/Attributes.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsVoidArray.h"
#include "nsISupports.h"
@ -105,8 +106,32 @@ private:
// don't implement these, defaults will muck with refcounts!
nsCOMArray_base& operator=(const nsCOMArray_base& other) MOZ_DELETE;
// needs to call Clear() which is protected
friend void ImplCycleCollectionUnlink(nsCOMArray_base& aField);
};
inline void
ImplCycleCollectionUnlink(nsCOMArray_base& aField)
{
aField.Clear();
}
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsCOMArray_base& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Count();
for (size_t i = 0; i < length; ++i) {
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField[i]);
}
}
// a non-XPCOM, refcounting array of XPCOM objects
// used as a member variable or stack variable - this object is NOT
// refcounted, but the objects that it holds are
@ -273,5 +298,26 @@ private:
nsCOMArray<T>& operator=(const nsCOMArray<T>& other) MOZ_DELETE;
};
template <typename T>
inline void
ImplCycleCollectionUnlink(nsCOMArray<T>& aField)
{
aField.Clear();
}
template <typename E>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsCOMArray<E>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Count();
for (size_t i = 0; i < length; ++i) {
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField[i]);
}
}
#endif

View File

@ -37,6 +37,8 @@
// for |NS_COM_GLUE|
#endif
#include "nsCycleCollectionNoteChild.h"
/*
WARNING:
@ -1126,6 +1128,24 @@ class nsCOMPtr<nsISupports>
}
};
template <typename T>
inline void
ImplCycleCollectionUnlink(nsCOMPtr<T>& aField)
{
aField = nullptr;
}
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsCOMPtr<T>& aField,
const char* aName,
uint32_t aFlags = 0)
{
CycleCollectionNoteEdgeName(aCallback, aName, aFlags);
aCallback.NoteXPCOMChild(aField);
}
#ifndef NSCAP_FEATURE_USE_BASE
template <class T>
void

View File

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
// This header will be included by headers that define refpointer and array classes
// in order to specialize CC helpers such as ImplCycleCollectionTraverse for them.
#ifndef nsCycleCollectionNoteChild_h__
#define nsCycleCollectionNoteChild_h__
#include "nsCycleCollectionTraversalCallback.h"
#include "mozilla/Likely.h"
enum {
CycleCollectionEdgeNameArrayFlag = 1
};
// Just a helper for appending "[i]". Didn't want to pull in string headers here.
void
CycleCollectionNoteEdgeNameImpl(nsCycleCollectionTraversalCallback& aCallback,
const char* aName,
uint32_t aFlags = 0);
// Should be inlined so that in the no-debug-info case this is just a simple if().
MOZ_ALWAYS_INLINE void
CycleCollectionNoteEdgeName(nsCycleCollectionTraversalCallback& aCallback,
const char* aName,
uint32_t aFlags = 0)
{
if (MOZ_UNLIKELY(aCallback.WantDebugInfo())) {
CycleCollectionNoteEdgeNameImpl(aCallback, aName, aFlags);
}
}
#endif // nsCycleCollectionNoteChild_h__

View File

@ -6,6 +6,12 @@
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
#ifdef MOZILLA_INTERNAL_API
#include "nsString.h"
#else
#include "nsStringAPI.h"
#endif
void
nsScriptObjectTracer::NoteJSChild(void *aScriptThing, const char *name,
void *aClosure)
@ -48,3 +54,15 @@ nsXPCOMCycleCollectionParticipant::CheckForRightISupports(nsISupports *s)
reinterpret_cast<void**>(&foo));
return s == foo;
}
void
CycleCollectionNoteEdgeNameImpl(nsCycleCollectionTraversalCallback& aCallback,
const char* aName,
uint32_t aFlags = 0)
{
nsAutoCString arrayEdgeName(aName);
if (aFlags & CycleCollectionEdgeNameArrayFlag) {
arrayEdgeName.AppendLiteral("[i]");
}
aCallback.NoteNextEdgeName(arrayEdgeName.get());
}

View File

@ -8,7 +8,9 @@
#include "mozilla/Likely.h"
#include "mozilla/TypeTraits.h"
#include "nsISupports.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsCycleCollectionTraversalCallback.h"
#define NS_CYCLECOLLECTIONPARTICIPANT_IID \
{ \
@ -52,60 +54,8 @@ class nsCycleCollectionParticipant;
class nsScriptObjectTracer;
class nsXPCOMCycleCollectionParticipant;
/**
* Callback definitions
*/
typedef void
(* TraceCallback)(void *p, const char *name, void *closure);
class NS_NO_VTABLE nsCycleCollectionTraversalCallback
{
public:
// You must call DescribeRefCountedNode() with an accurate
// refcount, otherwise cycle collection will fail, and probably crash.
// If the callback cares about objname, it should put
// WANT_DEBUG_INFO in mFlags.
NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
const char *objname) = 0;
NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
const char *objname) = 0;
NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) = 0;
NS_IMETHOD_(void) NoteJSRoot(void *root) = 0;
NS_IMETHOD_(void) NoteNativeRoot(void *root, nsCycleCollectionParticipant *participant) = 0;
NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child) = 0;
NS_IMETHOD_(void) NoteJSChild(void *child) = 0;
NS_IMETHOD_(void) NoteNativeChild(void *child,
nsCycleCollectionParticipant *helper) = 0;
// Give a name to the edge associated with the next call to
// NoteXPCOMChild, NoteJSChild, or NoteNativeChild.
// Callbacks who care about this should set WANT_DEBUG_INFO in the
// flags.
NS_IMETHOD_(void) NoteNextEdgeName(const char* name) = 0;
NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) = 0;
enum {
// Values for flags:
// Caller should call NoteNextEdgeName and pass useful objName
// to DescribeRefCountedNode and DescribeGCedNode.
WANT_DEBUG_INFO = (1<<0),
// Caller should not skip objects that we know will be
// uncollectable.
WANT_ALL_TRACES = (1<<1)
};
uint32_t Flags() const { return mFlags; }
bool WantDebugInfo() const { return (mFlags & WANT_DEBUG_INFO) != 0; }
bool WantAllTraces() const { return (mFlags & WANT_ALL_TRACES) != 0; }
protected:
nsCycleCollectionTraversalCallback() : mFlags(0) {}
uint32_t mFlags;
};
(* TraceCallback)(void *p, const char* name, void *closure);
/**
* VTables
@ -443,14 +393,17 @@ public:
{ \
_class *tmp = static_cast<_class*>(p);
#define NS_IMPL_CYCLE_COLLECTION_UNLINK(_field) \
ImplCycleCollectionUnlink(tmp->_field);
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_field) \
tmp->_field = NULL;
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(_field) \
tmp->_field.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(_field) \
tmp->_field.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field)
#define NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
(void)tmp; \
@ -516,12 +469,8 @@ public:
_class *tmp = static_cast<_class*>(p); \
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(_class, tmp->mRefCnt.get())
#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(_cb, _name) \
PR_BEGIN_MACRO \
if (MOZ_UNLIKELY((_cb).WantDebugInfo())) { \
(_cb).NoteNextEdgeName(_name); \
} \
PR_END_MACRO
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field) \
ImplCycleCollectionTraverse(cb, tmp->_field, #_field, 0);
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(_field) \
PR_BEGIN_MACRO \
@ -530,10 +479,7 @@ public:
PR_END_MACRO;
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_field) \
PR_BEGIN_MACRO \
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field); \
cb.NoteXPCOMChild(tmp->_field.get()); \
PR_END_MACRO;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(_field, _base) \
PR_BEGIN_MACRO \
@ -542,13 +488,7 @@ public:
PR_END_MACRO;
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(_field) \
{ \
int32_t i; \
for (i = 0; i < tmp->_field.Count(); ++i) { \
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field "[i]"); \
cb.NoteXPCOMChild(tmp->_field[i]); \
} \
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(_ptr, _ptr_class, _name) \
PR_BEGIN_MACRO \
@ -571,13 +511,7 @@ public:
}
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(_field) \
{ \
uint32_t i, length = tmp->_field.Length(); \
for (i = 0; i < length; ++i) { \
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, #_field "[i]"); \
cb.NoteXPCOMChild(tmp->_field[i].get()); \
} \
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field)
#define NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_MEMBER(_field, \
_element_class) \
@ -1212,4 +1146,6 @@ struct Skippable
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f8) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
#define NS_CYCLE_COLLECTION_NOTE_EDGE_NAME CycleCollectionNoteEdgeName
#endif // nsCycleCollectionParticipant_h__

View File

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 nsCycleCollectionTraversalCallback_h__
#define nsCycleCollectionTraversalCallback_h__
#include "nsISupports.h"
class nsCycleCollectionParticipant;
class NS_NO_VTABLE nsCycleCollectionTraversalCallback
{
public:
// You must call DescribeRefCountedNode() with an accurate
// refcount, otherwise cycle collection will fail, and probably crash.
// If the callback cares about objname, it should put
// WANT_DEBUG_INFO in mFlags.
NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refcount,
const char* objname) = 0;
NS_IMETHOD_(void) DescribeGCedNode(bool ismarked,
const char* objname) = 0;
NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) = 0;
NS_IMETHOD_(void) NoteJSRoot(void *root) = 0;
NS_IMETHOD_(void) NoteNativeRoot(void *root, nsCycleCollectionParticipant *participant) = 0;
NS_IMETHOD_(void) NoteXPCOMChild(nsISupports *child) = 0;
NS_IMETHOD_(void) NoteJSChild(void *child) = 0;
NS_IMETHOD_(void) NoteNativeChild(void *child,
nsCycleCollectionParticipant *helper) = 0;
// Give a name to the edge associated with the next call to
// NoteXPCOMChild, NoteJSChild, or NoteNativeChild.
// Callbacks who care about this should set WANT_DEBUG_INFO in the
// flags.
NS_IMETHOD_(void) NoteNextEdgeName(const char* name) = 0;
NS_IMETHOD_(void) NoteWeakMapping(void *map, void *key, void *kdelegate, void *val) = 0;
enum {
// Values for flags:
// Caller should call NoteNextEdgeName and pass useful objName
// to DescribeRefCountedNode and DescribeGCedNode.
WANT_DEBUG_INFO = (1<<0),
// Caller should not skip objects that we know will be
// uncollectable.
WANT_ALL_TRACES = (1<<1)
};
uint32_t Flags() const { return mFlags; }
bool WantDebugInfo() const { return (mFlags & WANT_DEBUG_INFO) != 0; }
bool WantAllTraces() const { return (mFlags & WANT_ALL_TRACES) != 0; }
protected:
nsCycleCollectionTraversalCallback() : mFlags(0) {}
uint32_t mFlags;
};
#endif // nsCycleCollectionTraversalCallback_h__

View File

@ -12,6 +12,7 @@
#include <string.h>
#include "nsCycleCollectionNoteChild.h"
#include "nsAlgorithm.h"
#include "nscore.h"
#include "nsQuickSort.h"
@ -1268,10 +1269,31 @@ protected:
}
};
template <typename E, typename Alloc>
inline void
ImplCycleCollectionUnlink(nsTArray<E, Alloc>& aField)
{
aField.Clear();
}
template <typename E, typename Alloc>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsTArray<E, Alloc>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Length();
for (size_t i = 0; i < length; ++i) {
ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
}
}
//
// Convenience subtypes of nsTArray.
//
template<class E>
template <class E>
class FallibleTArray : public nsTArray<E, nsTArrayFallibleAllocator>
{
public:
@ -1283,8 +1305,30 @@ public:
FallibleTArray(const FallibleTArray& other) : base_type(other) {}
};
template <typename E>
inline void
ImplCycleCollectionUnlink(FallibleTArray<E>& aField)
{
aField.Clear();
}
template <typename E>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
FallibleTArray<E>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Length();
for (size_t i = 0; i < length; ++i) {
ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
}
}
#ifdef MOZALLOC_HAVE_XMALLOC
template<class E>
template <class E>
class InfallibleTArray : public nsTArray<E, nsTArrayInfallibleAllocator>
{
public:
@ -1295,9 +1339,30 @@ public:
explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
};
template <typename E>
inline void ImplCycleCollectionUnlink(InfallibleTArray<E>& aField)
{
aField.Clear();
}
template <typename E>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
InfallibleTArray<E>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Length();
for (size_t i = 0; i < length; ++i) {
ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
}
}
#endif
template<class TArrayBase, uint32_t N>
template <class TArrayBase, uint32_t N>
class nsAutoArrayBase : public TArrayBase
{
public:

View File

@ -7,6 +7,7 @@
#define nsTObserverArray_h___
#include "nsTArray.h"
#include "nsCycleCollectionNoteChild.h"
/**
* An array of observers. Like a normal array, but supports iterators that are
@ -374,6 +375,27 @@ class nsTObserverArray : public nsAutoTObserverArray<T, 0> {
}
};
template <typename T>
inline void
ImplCycleCollectionUnlink(nsTObserverArray<T>& aField)
{
aField.Clear();
}
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
nsTObserverArray<T>& aField,
const char* aName,
uint32_t aFlags = 0)
{
aFlags |= CycleCollectionEdgeNameArrayFlag;
size_t length = aField.Length();
for (size_t i = 0; i < length; ++i) {
ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
}
}
// XXXbz I wish I didn't have to pass in the observer type, but I
// don't see a way to get it out of array_.
// Note that this macro only works if the array holds pointers to XPCOM objects.