blob: 79827e8e3ef07c371d9bd0d2b1be252a08b211d8 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GarbageCollected_h
#define GarbageCollected_h
#include "platform/heap/ThreadState.h"
#include "platform/wtf/Allocator.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/TypeTraits.h"
namespace blink {
template <typename T>
class GarbageCollected;
// GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
// field when checking for proper usage. When using GC_PLUGIN_IGNORE
// a bug-number should be provided as an argument where the bug describes
// what needs to happen to remove the GC_PLUGIN_IGNORE again.
#if defined(__clang__)
#define GC_PLUGIN_IGNORE(bug) \
__attribute__((annotate("blink_gc_plugin_ignore")))
#else
#define GC_PLUGIN_IGNORE(bug)
#endif
// Template to determine if a class is a GarbageCollectedMixin by checking if it
// has IsGarbageCollectedMixinMarker
template <typename T>
struct IsGarbageCollectedMixin {
private:
typedef char YesType;
struct NoType {
char padding[8];
};
template <typename U>
static YesType CheckMarker(typename U::IsGarbageCollectedMixinMarker*);
template <typename U>
static NoType CheckMarker(...);
public:
static const bool value = sizeof(CheckMarker<T>(nullptr)) == sizeof(YesType);
};
// The GarbageCollectedMixin interface and helper macro
// USING_GARBAGE_COLLECTED_MIXIN can be used to automatically define
// TraceTrait/ObjectAliveTrait on non-leftmost deriving classes
// which need to be garbage collected.
//
// Consider the following case:
// class B {};
// class A : public GarbageCollected, public B {};
//
// We can't correctly handle "Member<B> p = &a" as we can't compute addr of
// object header statically. This can be solved by using GarbageCollectedMixin:
// class B : public GarbageCollectedMixin {};
// class A : public GarbageCollected, public B {
// USING_GARBAGE_COLLECTED_MIXIN(A);
// };
//
// With the helper, as long as we are using Member<B>, TypeTrait<B> will
// dispatch adjustAndMark dynamically to find collect addr of the object header.
// Note that this is only enabled for Member<B>. For Member<A> which we can
// compute the object header addr statically, this dynamic dispatch is not used.
//
class PLATFORM_EXPORT GarbageCollectedMixin {
public:
typedef int IsGarbageCollectedMixinMarker;
virtual void AdjustAndMark(Visitor*) const = 0;
virtual void Trace(Visitor*) {}
virtual bool IsHeapObjectAlive() const = 0;
};
#define DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(VISITOR, TYPE) \
public: \
void AdjustAndMark(VISITOR visitor) const override { \
typedef WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type, \
blink::GarbageCollected> \
IsSubclassOfGarbageCollected; \
static_assert( \
IsSubclassOfGarbageCollected::value, \
"only garbage collected objects can have garbage collected mixins"); \
if (TraceEagerlyTrait<TYPE>::value) { \
if (visitor->EnsureMarked(static_cast<const TYPE*>(this))) \
TraceTrait<TYPE>::Trace(visitor, const_cast<TYPE*>(this)); \
return; \
} \
visitor->Mark(static_cast<const TYPE*>(this), \
&blink::TraceTrait<TYPE>::Trace); \
} \
\
private:
// A C++ object's vptr will be initialized to its leftmost base's vtable after
// the constructors of all its subclasses have run, so if a subclass constructor
// tries to access any of the vtbl entries of its leftmost base prematurely,
// it'll find an as-yet incorrect vptr and fail. Which is exactly what a
// garbage collector will try to do if it tries to access the leftmost base
// while one of the subclass constructors of a GC mixin object triggers a GC.
// It is consequently not safe to allow any GCs while these objects are under
// (sub constructor) construction.
//
// To prevent GCs in that restricted window of a mixin object's construction:
//
// - The initial allocation of the mixin object will enter a no GC scope.
// This is done by overriding 'operator new' for mixin instances.
// - When the constructor for the mixin is invoked, after all the
// derived constructors have run, it will invoke the constructor
// for a field whose only purpose is to leave the GC scope.
// GarbageCollectedMixinConstructorMarker's constructor takes care of
// this and the field is declared by way of USING_GARBAGE_COLLECTED_MIXIN().
#define DEFINE_GARBAGE_COLLECTED_MIXIN_CONSTRUCTOR_MARKER(TYPE) \
public: \
GC_PLUGIN_IGNORE("crbug.com/456823") \
NO_SANITIZE_UNRELATED_CAST void* operator new(size_t size) { \
void* object = \
TYPE::AllocateObject(size, IsEagerlyFinalizedType<TYPE>::value); \
ThreadState* state = \
ThreadStateFor<ThreadingTrait<TYPE>::kAffinity>::GetState(); \
state->EnterGCForbiddenScopeIfNeeded( \
&(reinterpret_cast<TYPE*>(object)->mixin_constructor_marker_)); \
return object; \
} \
GarbageCollectedMixinConstructorMarker mixin_constructor_marker_; \
\
private:
// Mixins that wrap/nest others requires extra handling:
//
// class A : public GarbageCollected<A>, public GarbageCollectedMixin {
// USING_GARBAGE_COLLECTED_MIXIN(A);
// ...
// }'
// public B final : public A, public SomeOtherMixinInterface {
// USING_GARBAGE_COLLECTED_MIXIN(B);
// ...
// };
//
// The "operator new" for B will enter the forbidden GC scope, but
// upon construction, two GarbageCollectedMixinConstructorMarker constructors
// will run -- one for A (first) and another for B (secondly). Only
// the second one should leave the forbidden GC scope. This is realized by
// recording the address of B's GarbageCollectedMixinConstructorMarker
// when the "operator new" for B runs, and leaving the forbidden GC scope
// when the constructor of the recorded GarbageCollectedMixinConstructorMarker
// runs.
#define USING_GARBAGE_COLLECTED_MIXIN(TYPE) \
IS_GARBAGE_COLLECTED_TYPE(); \
DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(blink::Visitor*, TYPE) \
DEFINE_GARBAGE_COLLECTED_MIXIN_CONSTRUCTOR_MARKER(TYPE) \
public: \
bool IsHeapObjectAlive() const override { \
return ThreadHeap::IsHeapObjectAlive(this); \
} \
\
private:
// An empty class with a constructor that's arranged invoked when all derived
// constructors of a mixin instance have completed and it is safe to allow GCs
// again. See AllocateObjectTrait<> comment for more.
//
// USING_GARBAGE_COLLECTED_MIXIN() declares a
// GarbageCollectedMixinConstructorMarker<> private field. By following Blink
// convention of using the macro at the top of a class declaration, its
// constructor will run first.
class GarbageCollectedMixinConstructorMarker {
public:
GarbageCollectedMixinConstructorMarker() {
// FIXME: if prompt conservative GCs are needed, forced GCs that
// were denied while within this scope, could now be performed.
// For now, assume the next out-of-line allocation request will
// happen soon enough and take care of it. Mixin objects aren't
// overly common.
ThreadState* state = ThreadState::Current();
state->LeaveGCForbiddenScopeIfNeeded(this);
}
};
// Base class for objects allocated in the Blink garbage-collected heap.
//
// Defines a 'new' operator that allocates the memory in the heap. 'delete'
// should not be called on objects that inherit from GarbageCollected.
//
// Instances of GarbageCollected will *NOT* get finalized. Their destructor
// will not be called. Therefore, only classes that have trivial destructors
// with no semantic meaning (including all their subclasses) should inherit from
// GarbageCollected. If there are non-trival destructors in a given class or
// any of its subclasses, GarbageCollectedFinalized should be used which
// guarantees that the destructor is called on an instance when the garbage
// collector determines that it is no longer reachable.
template <typename T>
class GarbageCollected;
// Base class for objects allocated in the Blink garbage-collected heap.
//
// Defines a 'new' operator that allocates the memory in the heap. 'delete'
// should not be called on objects that inherit from GarbageCollected.
//
// Instances of GarbageCollectedFinalized will have their destructor called when
// the garbage collector determines that the object is no longer reachable.
template <typename T>
class GarbageCollectedFinalized : public GarbageCollected<T> {
WTF_MAKE_NONCOPYABLE(GarbageCollectedFinalized);
protected:
// finalizeGarbageCollectedObject is called when the object is freed from
// the heap. By default finalization means calling the destructor on the
// object. finalizeGarbageCollectedObject can be overridden to support
// calling the destructor of a subclass. This is useful for objects without
// vtables that require explicit dispatching. The name is intentionally a
// bit long to make name conflicts less likely.
void FinalizeGarbageCollectedObject() { static_cast<T*>(this)->~T(); }
GarbageCollectedFinalized() {}
~GarbageCollectedFinalized() {}
template <typename U>
friend struct HasFinalizer;
template <typename U, bool>
friend struct FinalizerTraitImpl;
};
template <typename T,
bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
GarbageCollected>::value>
class NeedsAdjustAndMark;
template <typename T>
class NeedsAdjustAndMark<T, true> {
static_assert(sizeof(T), "T must be fully defined");
public:
static const bool value = false;
};
template <typename T>
class NeedsAdjustAndMark<T, false> {
static_assert(sizeof(T), "T must be fully defined");
public:
static const bool value =
IsGarbageCollectedMixin<typename std::remove_const<T>::type>::value;
};
// TODO(sof): migrate to wtf/TypeTraits.h
template <typename T>
class IsFullyDefined {
using TrueType = char;
struct FalseType {
char dummy[2];
};
template <typename U, size_t sz = sizeof(U)>
static TrueType IsSizeofKnown(U*);
static FalseType IsSizeofKnown(...);
static T& t_;
public:
static const bool value = sizeof(TrueType) == sizeof(IsSizeofKnown(&t_));
};
} // namespace blink
#endif