Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2216)

Unified Diff: Source/platform/heap/Visitor.h

Issue 803443002: Introduce InlinedGlobalMarkingVisitor Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/platform/heap/Heap.cpp ('k') | Source/wtf/TypeTraits.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/platform/heap/Visitor.h
diff --git a/Source/platform/heap/Visitor.h b/Source/platform/heap/Visitor.h
index f0b9ed70b31598dee872e40a39293c0055631ad8..274312bb1707c15c156e47a122c01bda19c67504 100644
--- a/Source/platform/heap/Visitor.h
+++ b/Source/platform/heap/Visitor.h
@@ -155,8 +155,12 @@ public:
template <typename T> const bool NeedsAdjustAndMark<T, false>::value;
+template <typename T, bool = WTF::HasTraceNewMethod<T>::value> struct TraceGenericCompatibilityAdaptor;
+
template<typename T, bool = NeedsAdjustAndMark<T>::value> class DefaultTraceTrait;
+class InlinedGlobalMarkingVisitor;
+
// The TraceTrait is used to specify how to mark an object pointer and
// how to trace all of the pointers in the object.
//
@@ -173,15 +177,13 @@ class TraceTrait {
public:
// Default implementation of TraceTrait<T>::trace just statically
// dispatches to the trace method of the class T.
- static void trace(Visitor* visitor, void* self)
+ template<typename VisitorDispatcher>
+ static void trace(VisitorDispatcher visitor, void* self)
{
- static_cast<T*>(self)->trace(visitor);
+ TraceGenericCompatibilityAdaptor<T>::trace(visitor, static_cast<T*>(self));
}
- static void mark(Visitor* visitor, const T* t)
- {
- DefaultTraceTrait<T>::mark(visitor, t);
- }
+ template<typename VisitorDispatcher> static void mark(VisitorDispatcher visitor, const T*);
#if ENABLE(ASSERT)
static void checkGCInfo(Visitor* visitor, const T* t)
@@ -527,13 +529,24 @@ public:
}
#endif
+ virtual bool isGlobalMarkingVisitor() { return false; }
+
+#if 0
inline bool canTraceEagerly() const { return m_traceDepth < kMaxEagerTraceDepth; }
inline void incrementTraceDepth() { m_traceDepth++; }
inline void decrementTraceDepth() { ASSERT(m_traceDepth > 0); m_traceDepth--; }
+#else
+ inline bool canTraceEagerly() const { return true; }
+ inline void incrementTraceDepth() { }
+ inline void decrementTraceDepth() { }
+#endif
+
+ // This should be only used from InlinedGlobalMarkingVisitor
+ virtual void pushTraceCallback(void*, TraceCallback) { ASSERT_NOT_REACHED(); }
protected:
Visitor()
- : m_traceDepth(0)
+ // : m_traceDepth(0)
{
}
@@ -554,11 +567,298 @@ private:
// The maximum depth of eager, unrolled trace() calls that is
// considered safe and allowed.
- const int kMaxEagerTraceDepth = 100;
+ // const int kMaxEagerTraceDepth = 100;
- int m_traceDepth;
+ // int m_traceDepth;
};
+template<typename T>
+inline T&& forward(typename WTF::Identity<T>::type&& x) { return x; }
+
+class InlinedGlobalMarkingVisitor {
+public:
+ InlinedGlobalMarkingVisitor(Visitor* visitor)
+ : m_visitor(visitor)
+ {
+ ASSERT(visitor->isGlobalMarkingVisitor());
+ }
+
+ // Hack to allow visitor->trace()
+ InlinedGlobalMarkingVisitor* operator->() { return this; }
+
+ // One-argument templated mark method. This uses the static type of
+ // the argument to get the TraceTrait. By default, the mark method
+ // of the TraceTrait just calls the virtual two-argument mark method on this
+ // visitor, where the second argument is the static trace method of the trait.
+ template<typename T> void mark(T* t);
+
+ // Member version of the one-argument templated trace method.
+ template<typename T>
+ void trace(const Member<T>& t)
+ {
+ mark(t.get());
+ }
+
+ // Fallback method used only when we need to trace raw pointers of T.
+ // This is the case when a member is a union where we do not support members.
+ template<typename T>
+ void trace(const T* t)
+ {
+ mark(const_cast<T*>(t));
+ }
+
+ template<typename T>
+ void trace(T* t)
+ {
+ mark(t);
+ }
+
+ // WeakMember version of the templated trace method. It doesn't keep
+ // the traced thing alive, but will write null to the WeakMember later
+ // if the pointed-to object is dead. It's lying for this to be const,
+ // but the overloading resolver prioritizes constness too high when
+ // picking the correct overload, so all these trace methods have to have
+ // the same constness on their argument to allow the type to decide.
+ template<typename T>
+ void trace(const WeakMember<T>& t)
+ {
+ // Check that we actually know the definition of T when tracing.
+ COMPILE_ASSERT(sizeof(T), WeNeedToKnowTheDefinitionOfTheTypeWeAreTracing);
+ registerWeakCell(const_cast<WeakMember<T>&>(t).cell());
+ COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, AttemptedToWeakTraceNonGarbageCollectedObject);
+ }
+
+ template<typename T>
+ void traceInCollection(T& t, WTF::ShouldWeakPointersBeMarkedStrongly strongify)
+ {
+ HashTraits<T>::traceInCollection(m_visitor, t, strongify);
+ }
+
+ // Fallback trace method for part objects to allow individual trace methods
+ // to trace through a part object with visitor->trace(m_partObject). This
+ // takes a const argument, because otherwise it will match too eagerly: a
+ // non-const argument would match a non-const Vector<T>& argument better
+ // than the specialization that takes const Vector<T>&. For a similar reason,
+ // the other specializations take a const argument even though they are
+ // usually used with non-const arguments, otherwise this function would match
+ // too well.
+ template<typename T>
+ void trace(const T& t)
+ {
+ if (WTF::IsPolymorphic<T>::value) {
+ intptr_t vtable = *reinterpret_cast<const intptr_t*>(&t);
+ if (!vtable)
+ return;
+ }
+ const_cast<T&>(t).trace(*this);
+ }
+
+ // The following trace methods are for off-heap collections.
+ template<typename T, size_t inlineCapacity>
+ void trace(const Vector<T, inlineCapacity>& vector)
+ {
+ OffHeapCollectionTraceTrait<Vector<T, inlineCapacity, WTF::DefaultAllocator> >::trace(m_visitor, vector);
+ }
+
+ template<typename T, size_t N>
+ void trace(const Deque<T, N>& deque)
+ {
+ OffHeapCollectionTraceTrait<Deque<T, N> >::trace(m_visitor, deque);
+ }
+
+#if !ENABLE(OILPAN)
+ // These trace methods are needed to allow compiling and calling trace on
+ // transition types. We need to support calls in the non-oilpan build
+ // because a fully transitioned type (which will have its trace method
+ // called) might trace a field that is in transition. Once transition types
+ // are removed these can be removed.
+ template<typename T> void trace(const OwnPtr<T>&) { }
+ template<typename T> void trace(const RefPtr<T>&) { }
+ template<typename T> void trace(const RawPtr<T>&) { }
+ template<typename T> void trace(const WeakPtr<T>&) { }
+#endif
+
+ // This method marks an object and adds it to the set of objects
+ // that should have their trace method called. Since not all
+ // objects have vtables we have to have the callback as an
+ // explicit argument, but we can use the templated one-argument
+ // mark method above to automatically provide the callback
+ // function.
+ void mark(const void* o, TraceCallback callback);
+
+ template<typename T> void markNoTracing(const T* pointer) { mark(pointer, reinterpret_cast<TraceCallback>(0)); }
+ void markNoTracing(const void* pointer) { mark(pointer, reinterpret_cast<TraceCallback>(0)); }
+ void markNoTracing(HeapObjectHeader* header) { mark(header, reinterpret_cast<TraceCallback>(0)); }
+ void markNoTracing(GeneralHeapObjectHeader* header) { mark(header, reinterpret_cast<TraceCallback>(0)); }
+
+ // If the object calls this during the regular trace callback, then the
+ // WeakPointerCallback argument may be called later, when the strong roots
+ // have all been found. The WeakPointerCallback will normally use isAlive
+ // to find out whether some pointers are pointing to dying objects. When
+ // the WeakPointerCallback is done the object must have purged all pointers
+ // to objects where isAlive returned false. In the weak callback it is not
+ // allowed to touch other objects (except using isAlive) or to allocate on
+ // the GC heap. Note that even removing things from HeapHashSet or
+ // HeapHashMap can cause an allocation if the backing store resizes, but
+ // these collections know to remove WeakMember elements safely.
+ //
+ // The weak pointer callbacks are run on the thread that owns the
+ // object and other threads are not stopped during the
+ // callbacks. Since isAlive is used in the callback to determine
+ // if objects pointed to are alive it is crucial that the object
+ // pointed to belong to the same thread as the object receiving
+ // the weak callback. Since other threads have been resumed the
+ // mark bits are not valid for objects from other threads.
+ void registerWeakMembers(const void* object, WeakPointerCallback callback) { m_visitor->registerWeakMembers(object, object, callback); }
+ void registerWeakMembers(const void* a , const void* b, WeakPointerCallback callback) { m_visitor->registerWeakMembers(a, b, callback); }
+
+ template<typename T, void (T::*method)(Visitor*)>
+ void registerWeakMembers(const T* obj)
+ {
+ registerWeakMembers(obj, &TraceMethodDelegate<T, method>::trampoline);
+ }
+
+#if 0
+ // For simple cases where you just want to zero out a cell when the thing
+ // it is pointing at is garbage, you can use this. This will register a
+ // callback for each cell that needs to be zeroed, so if you have a lot of
+ // weak cells in your object you should still consider using
+ // registerWeakMembers above.
+ //
+ // In contrast to registerWeakMembers, the weak cell callbacks are
+ // run on the thread performing garbage collection. Therefore, all
+ // threads are stopped during weak cell callbacks.
+ template<typename T>
+ void registerWeakCell(T** cell)
+ {
+ registerWeakCell(reinterpret_cast<void**>(cell), &handleWeakCell<T>);
+ }
+
+ virtual void registerWeakTable(const void*, EphemeronCallback, EphemeronCallback) = 0;
+#if ENABLE(ASSERT)
+ virtual bool weakTableRegistered(const void*) = 0;
+#endif
+#endif
+
+ bool isMarked(const void* obj);
+ bool ensureMarked(const void* obj);
+
+ template<typename T> inline bool isAlive(T* obj)
+ {
+ // Check that we actually know the definition of T when tracing.
+ COMPILE_ASSERT(sizeof(T), WeNeedToKnowTheDefinitionOfTheTypeWeAreTracing);
+ // The strongification of collections relies on the fact that once a
+ // collection has been strongified, there is no way that it can contain
+ // non-live entries, so no entries will be removed. Since you can't set
+ // the mark bit on a null pointer, that means that null pointers are
+ // always 'alive'.
+ if (!obj)
+ return true;
+ return ObjectAliveTrait<T>::isHeapObjectAlive(this, obj);
+ }
+ template<typename T> inline bool isAlive(const Member<T>& member)
+ {
+ return isAlive(member.get());
+ }
+ template<typename T> inline bool isAlive(RawPtr<T> ptr)
+ {
+ return isAlive(ptr.get());
+ }
+
+#if ENABLE(ASSERT)
+ void checkGCInfo(const void*, const GCInfo*);
+#endif
+
+ // Macro to declare methods needed for each typed heap.
+#define DECLARE_VISITOR_METHODS(Type) \
+ DEBUG_ONLY(void checkGCInfo(const Type*, const GCInfo*);) \
+ void mark(const Type* t, TraceCallback callback) { m_visitor->mark(t, callback); } \
+ bool isMarked(const Type* t) { return m_visitor->isMarked(t); }\
+ bool ensureMarked(const Type* t) { return m_visitor->ensureMarked(t); }
+
+ FOR_EACH_TYPED_HEAP(DECLARE_VISITOR_METHODS)
+#undef DECLARE_VISITOR_METHODS
+
+#if ENABLE(GC_PROFILE_MARKING)
+ void setHostInfo(void* object, const String& name)
+ {
+ m_visitor->setHostInfo(object, name);
+ }
+#endif
+
+ inline bool canTraceEagerly() const { return true; }
+ inline void incrementTraceDepth() { }
+ inline void decrementTraceDepth() { }
+
+ Visitor* getUninlined() { return m_visitor; }
+
+private:
+ void visitHeader(HeapObjectHeader* header, const void* objectPointer, TraceCallback callback);
+
+ Visitor* m_visitor;
+};
+
+template<typename T>
+void InlinedGlobalMarkingVisitor::mark(T* t)
+{
+ if (!t)
+ return;
+#if ENABLE(ASSERT)
+ TraceTrait<T>::checkGCInfo(m_visitor, t);
+#endif
+ TraceTrait<T>::mark(InlinedGlobalMarkingVisitor(*this), t);
+
+ COMPILE_ASSERT_IS_GARBAGE_COLLECTED(T, AttemptedToMarkNonGarbageCollectedObject);
+}
+
+template <typename T>
+struct TraceGenericCompatibilityAdaptor<T, true> {
+ static inline void trace(Visitor* visitor, T* t)
+ {
+ t->trace(visitor);
+ }
+
+ static inline void trace(InlinedGlobalMarkingVisitor visitor, T* t)
+ {
+ t->trace(InlinedGlobalMarkingVisitor(visitor));
+ }
+};
+
+template <typename T>
+struct TraceGenericCompatibilityAdaptor<T, false> {
+ static inline void trace(Visitor* visitor, T* t)
+ {
+ // Revert to old trace
+ t->trace(visitor);
+ }
+
+ static inline void trace(InlinedGlobalMarkingVisitor visitor, T* t)
+ {
+ // visiting was inlined to here, but the object we are going to trace doesn't support inlined trace
+ t->trace(visitor.getUninlined());
+ }
+};
+
+#define DECLARE_TRACE(virt, ovr) \
+ public: \
+ virt void trace(Visitor*) ovr; \
+ virt void trace(InlinedGlobalMarkingVisitor) ovr; \
+ private: \
+ template<typename VisitorDispatcher> void traceImpl(VisitorDispatcher); \
+ public:
+
+#define DEFINE_TRACE(CLASS) \
+ void CLASS::trace(Visitor* visitor) { traceImpl(visitor); } \
+ void CLASS::trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); } \
+ template<typename VisitorDispatcher> \
+ ALWAYS_INLINE void CLASS::traceImpl(VisitorDispatcher visitor) \
+
+#define DEFINE_INLINE_TRACE(virt, ovr) \
+ virt void trace(Visitor* visitor) ovr { traceImpl(visitor); } \
+ virt void trace(InlinedGlobalMarkingVisitor visitor) ovr { traceImpl(visitor); } \
+ template<typename VisitorDispatcher> \
+ inline void traceImpl(VisitorDispatcher visitor)
+
// We trace vectors by using the trace trait on each element, which means you
// can have vectors of general objects (not just pointers to objects) that can
// be traced.
@@ -598,6 +898,13 @@ public:
};
template<typename T>
+template<typename VisitorDispatcher>
+inline void TraceTrait<T>::mark(VisitorDispatcher visitor, const T* t)
+{
+ DefaultTraceTrait<T>::mark(visitor, t);
+}
+
+template<typename T>
class DefaultTraceTrait<T, false> {
public:
static void mark(Visitor* visitor, const T* t)
@@ -620,7 +927,10 @@ public:
if (LIKELY(visitor->canTraceEagerly())) {
if (visitor->ensureMarked(t)) {
visitor->incrementTraceDepth();
- TraceTrait<T>::trace(visitor, const_cast<T*>(t));
+ if (LIKELY(visitor->isGlobalMarkingVisitor()))
+ TraceTrait<T>::trace(InlinedGlobalMarkingVisitor(visitor), const_cast<T*>(t));
+ else
+ TraceTrait<T>::trace(visitor, const_cast<T*>(t));
visitor->decrementTraceDepth();
}
return;
@@ -629,6 +939,28 @@ public:
visitor->mark(const_cast<T*>(t), &TraceTrait<T>::trace);
}
+ static void mark(InlinedGlobalMarkingVisitor visitor, const T* t)
+ {
+ if (TraceEagerlyTrait<T>::value) {
+ // Protect against too deep trace call chains, and the
+ // unbounded system stack usage they can bring about.
+ //
+ // Assert against deep stacks so as to flush them out,
+ // but test and appropriately handle them should they occur
+ // in release builds.
+ ASSERT(visitor.canTraceEagerly());
+ if (LIKELY(visitor.canTraceEagerly())) {
+ if (visitor.ensureMarked(t)) {
+ visitor.incrementTraceDepth();
+ TraceTrait<T>::trace(visitor, const_cast<T*>(t));
+ visitor.decrementTraceDepth();
+ }
+ return;
+ }
+ }
+ visitor.mark(const_cast<T*>(t), &TraceTrait<T>::trace);
+ }
+
#if ENABLE(ASSERT)
static void checkGCInfo(Visitor* visitor, const T* t)
{
« no previous file with comments | « Source/platform/heap/Heap.cpp ('k') | Source/wtf/TypeTraits.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698