summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/platform/heap/GCInfo.h
blob: a07634d454dd9f6a365420688dda735c23f4b41a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
// 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 GCInfo_h
#define GCInfo_h

#include "platform/heap/Visitor.h"
#include "platform/wtf/Allocator.h"
#include "platform/wtf/Assertions.h"
#include "platform/wtf/Atomics.h"
#include "platform/wtf/Deque.h"
#include "platform/wtf/HashCountedSet.h"
#include "platform/wtf/HashMap.h"
#include "platform/wtf/HashSet.h"
#include "platform/wtf/HashTable.h"
#include "platform/wtf/LinkedHashSet.h"
#include "platform/wtf/ListHashSet.h"
#include "platform/wtf/TypeTraits.h"
#include "platform/wtf/Vector.h"

namespace blink {

// The FinalizerTraitImpl specifies how to finalize objects. Objects that
// inherit from GarbageCollectedFinalized are finalized by calling their
// |Finalize| method which by default will call the destructor on the object.
template <typename T, bool isGarbageCollectedFinalized>
struct FinalizerTraitImpl;

template <typename T>
struct FinalizerTraitImpl<T, true> {
  STATIC_ONLY(FinalizerTraitImpl);
  static void Finalize(void* obj) {
    static_assert(sizeof(T), "T must be fully defined");
    static_cast<T*>(obj)->FinalizeGarbageCollectedObject();
  };
};

template <typename T>
struct FinalizerTraitImpl<T, false> {
  STATIC_ONLY(FinalizerTraitImpl);
  static void Finalize(void* obj) {
    static_assert(sizeof(T), "T must be fully defined");
  };
};

// The FinalizerTrait is used to determine if a type requires finalization and
// what finalization means.
//
// By default classes that inherit from GarbageCollectedFinalized need
// finalization and finalization means calling the |Finalize| method of the
// object. The FinalizerTrait can be specialized if the default behavior is not
// desired.
template <typename T>
struct FinalizerTrait {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer =
      WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
                                GarbageCollectedFinalized>::value;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<T, kNonTrivialFinalizer>::Finalize(obj);
  }
};

class HeapAllocator;
template <typename ValueArg, size_t inlineCapacity>
class HeapListHashSetAllocator;
template <typename T, typename Traits>
class HeapVectorBacking;
template <typename Table>
class HeapHashTableBacking;

template <typename T, typename U, typename V>
struct FinalizerTrait<LinkedHashSet<T, U, V, HeapAllocator>> {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer = true;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<LinkedHashSet<T, U, V, HeapAllocator>,
                       kNonTrivialFinalizer>::Finalize(obj);
  }
};

template <typename T, typename Allocator>
struct FinalizerTrait<WTF::ListHashSetNode<T, Allocator>> {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer =
      !WTF::IsTriviallyDestructible<T>::value;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<WTF::ListHashSetNode<T, Allocator>,
                       kNonTrivialFinalizer>::Finalize(obj);
  }
};

template <typename T, size_t inlineCapacity>
struct FinalizerTrait<Vector<T, inlineCapacity, HeapAllocator>> {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer =
      inlineCapacity && VectorTraits<T>::kNeedsDestruction;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<Vector<T, inlineCapacity, HeapAllocator>,
                       kNonTrivialFinalizer>::Finalize(obj);
  }
};

template <typename T, size_t inlineCapacity>
struct FinalizerTrait<Deque<T, inlineCapacity, HeapAllocator>> {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer =
      inlineCapacity && VectorTraits<T>::kNeedsDestruction;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<Deque<T, inlineCapacity, HeapAllocator>,
                       kNonTrivialFinalizer>::Finalize(obj);
  }
};

template <typename Table>
struct FinalizerTrait<HeapHashTableBacking<Table>> {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer =
      !WTF::IsTriviallyDestructible<typename Table::ValueType>::value;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<HeapHashTableBacking<Table>,
                       kNonTrivialFinalizer>::Finalize(obj);
  }
};

template <typename T, typename Traits>
struct FinalizerTrait<HeapVectorBacking<T, Traits>> {
  STATIC_ONLY(FinalizerTrait);
  static const bool kNonTrivialFinalizer = Traits::kNeedsDestruction;
  static void Finalize(void* obj) {
    FinalizerTraitImpl<HeapVectorBacking<T, Traits>,
                       kNonTrivialFinalizer>::Finalize(obj);
  }
};

// GCInfo contains meta-data associated with object classes allocated in the
// Blink heap. This meta-data consists of a function pointer used to trace the
// pointers in the class instance during garbage collection, an indication of
// whether or not the instance needs a finalization callback, and a function
// pointer used to finalize the instance when the garbage collector determines
// that the instance is no longer reachable. There is a GCInfo struct for each
// class that directly inherits from GarbageCollected or
// GarbageCollectedFinalized.
struct GCInfo {
  bool HasFinalizer() const { return non_trivial_finalizer_; }
  bool HasVTable() const { return has_v_table_; }
  TraceCallback trace_;
  FinalizationCallback finalize_;
  bool non_trivial_finalizer_;
  bool has_v_table_;
};

// s_gcInfoTable holds the per-class GCInfo descriptors; each HeapObjectHeader
// keeps an index into this table.
extern PLATFORM_EXPORT GCInfo const** g_gc_info_table;

#if DCHECK_IS_ON()
PLATFORM_EXPORT void AssertObjectHasGCInfo(const void*, size_t gc_info_index);
#endif

class GCInfoTable {
  STATIC_ONLY(GCInfoTable);

 public:
  PLATFORM_EXPORT static void EnsureGCInfoIndex(const GCInfo*, size_t*);

  static void Init();

  static size_t GcInfoIndex() { return gc_info_index_; }

  // The (max + 1) GCInfo index supported.
  //
  // We assume that 14 bits is enough to represent all possible types: during
  // telemetry runs, we see about 1,000 different types; looking at the output
  // of the Oilpan GC Clang plugin, there appear to be at most about 6,000
  // types. Thus 14 bits should be more than twice as many bits as we will ever
  // need.
  static const size_t kMaxIndex = 1 << 14;

 private:
  static void Resize();

  static size_t gc_info_index_;
  static size_t gc_info_table_size_;
};

// GCInfoAtBaseType should be used when returning a unique 14 bit integer
// for a given gcInfo.
template <typename T>
struct GCInfoAtBaseType {
  STATIC_ONLY(GCInfoAtBaseType);
  static size_t Index() {
    static_assert(sizeof(T), "T must be fully defined");
    static const GCInfo kGcInfo = {
        TraceTrait<T>::Trace, FinalizerTrait<T>::Finalize,
        FinalizerTrait<T>::kNonTrivialFinalizer, std::is_polymorphic<T>::value,
    };

    static size_t gc_info_index = 0;
    DCHECK(g_gc_info_table);
    if (!AcquireLoad(&gc_info_index))
      GCInfoTable::EnsureGCInfoIndex(&kGcInfo, &gc_info_index);
    DCHECK_GE(gc_info_index, 1u);
    DCHECK(gc_info_index < GCInfoTable::kMaxIndex);
    return gc_info_index;
  }
};

template <typename T,
          bool = WTF::IsSubclassOfTemplate<typename std::remove_const<T>::type,
                                           GarbageCollected>::value>
struct GetGarbageCollectedType;

template <typename T>
struct GetGarbageCollectedType<T, true> {
  STATIC_ONLY(GetGarbageCollectedType);
  using type = typename T::GarbageCollectedType;
};

template <typename T>
struct GetGarbageCollectedType<T, false> {
  STATIC_ONLY(GetGarbageCollectedType);
  using type = T;
};

template <typename T>
struct GCInfoTrait {
  STATIC_ONLY(GCInfoTrait);
  static size_t Index() {
    return GCInfoAtBaseType<typename GetGarbageCollectedType<T>::type>::Index();
  }
};

template <typename U>
class GCInfoTrait<const U> : public GCInfoTrait<U> {};

template <typename T, typename U, typename V, typename W, typename X>
class HeapHashMap;
template <typename T, typename U, typename V>
class HeapHashSet;
template <typename T, typename U, typename V>
class HeapLinkedHashSet;
template <typename T, size_t inlineCapacity, typename U>
class HeapListHashSet;
template <typename T, size_t inlineCapacity>
class HeapVector;
template <typename T, size_t inlineCapacity>
class HeapDeque;
template <typename T, typename U, typename V>
class HeapHashCountedSet;

template <typename T, typename U, typename V, typename W, typename X>
struct GCInfoTrait<HeapHashMap<T, U, V, W, X>>
    : public GCInfoTrait<HashMap<T, U, V, W, X, HeapAllocator>> {};
template <typename T, typename U, typename V>
struct GCInfoTrait<HeapHashSet<T, U, V>>
    : public GCInfoTrait<HashSet<T, U, V, HeapAllocator>> {};
template <typename T, typename U, typename V>
struct GCInfoTrait<HeapLinkedHashSet<T, U, V>>
    : public GCInfoTrait<LinkedHashSet<T, U, V, HeapAllocator>> {};
template <typename T, size_t inlineCapacity, typename U>
struct GCInfoTrait<HeapListHashSet<T, inlineCapacity, U>>
    : public GCInfoTrait<
          ListHashSet<T,
                      inlineCapacity,
                      U,
                      HeapListHashSetAllocator<T, inlineCapacity>>> {};
template <typename T, size_t inlineCapacity>
struct GCInfoTrait<HeapVector<T, inlineCapacity>>
    : public GCInfoTrait<Vector<T, inlineCapacity, HeapAllocator>> {};
template <typename T, size_t inlineCapacity>
struct GCInfoTrait<HeapDeque<T, inlineCapacity>>
    : public GCInfoTrait<Deque<T, inlineCapacity, HeapAllocator>> {};
template <typename T, typename U, typename V>
struct GCInfoTrait<HeapHashCountedSet<T, U, V>>
    : public GCInfoTrait<HashCountedSet<T, U, V, HeapAllocator>> {};

}  // namespace blink

#endif