summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/heap/visitor.h
blob: 15ca5dbdbf57af32faa8091c18a44d39c217bf00 (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
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_

#include <memory>
#include "third_party/blink/renderer/platform/heap/blink_gc.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
#include "third_party/blink/renderer/platform/wtf/type_traits.h"

namespace base {
class Location;
}

namespace v8 {
class Value;
}

namespace blink {

template <typename T>
class GarbageCollected;
class LivenessBroker;
template <typename T>
struct TraceTrait;
class ThreadState;
class Visitor;
template <typename T>
class TraceWrapperV8Reference;

// The TraceMethodDelegate is used to convert a trace method for type T to a
// TraceCallback.  This allows us to pass a type's trace method as a parameter
// to the PersistentNode constructor. The PersistentNode constructor needs the
// specific trace method due an issue with the Windows compiler which
// instantiates even unused variables. This causes problems
// in header files where we have only forward declarations of classes.
//
// This interface is safe to use on concurrent threads. All accesses (reads)
// from member are done atomically.
template <typename T, void (T::*method)(Visitor*) const>
struct TraceMethodDelegate {
  STATIC_ONLY(TraceMethodDelegate);
  static void Trampoline(Visitor* visitor, const void* self) {
    (reinterpret_cast<const T*>(self)->*method)(visitor);
  }
};

template <typename T, void (T::*method)(const LivenessBroker&)>
struct WeakCallbackMethodDelegate {
  STATIC_ONLY(WeakCallbackMethodDelegate);
  static void Trampoline(const LivenessBroker& info, const void* self) {
    (reinterpret_cast<T*>(const_cast<void*>(self))->*method)(info);
  }
};

// Visitor is used to traverse Oilpan's object graph.
class PLATFORM_EXPORT Visitor {
  USING_FAST_MALLOC(Visitor);

 public:
  explicit Visitor(ThreadState* state) : state_(state) {}
  virtual ~Visitor() = default;

  inline ThreadState* State() const { return state_; }
  inline ThreadHeap& Heap() const { return state_->Heap(); }

  // Static visitor implementation forwarding to dynamic interface.

  template <typename T>
  void TraceRoot(const T* t, const base::Location& location) {
    static_assert(sizeof(T), "T must be fully defined");
    static_assert(IsGarbageCollectedType<T>::value,
                  "T needs to be a garbage collected object");
    if (!t)
      return;
    VisitRoot(t, TraceDescriptorFor(t), location);
  }

  template <typename T>
  void Trace(const Member<T>& t) {
    const T* value = t.GetSafe();

    DCHECK(!Member<T>::IsMemberHashTableDeletedValue(value));

    Trace(value);
  }

  template <typename T>
  ALWAYS_INLINE void TraceMaybeDeleted(const Member<T>& t) {
    const T* value = t.GetSafe();

    if (Member<T>::IsMemberHashTableDeletedValue(value))
      return;

    Trace<T>(value);
  }

  // TraceMayBeDeleted strongifies WeakMembers.
  template <typename T>
  ALWAYS_INLINE void TraceMaybeDeleted(const WeakMember<T>& t) {
    const T* value = t.GetSafe();

    if (WeakMember<T>::IsMemberHashTableDeletedValue(value))
      return;

    Trace<T>(value);
  }

  // Fallback methods 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(T* t) {
    Trace(const_cast<const T*>(t));
  }
  template <typename T>
  void Trace(const T* t) {
    static_assert(sizeof(T), "T must be fully defined");
    static_assert(IsGarbageCollectedType<T>::value,
                  "T needs to be a garbage collected object");
    if (!t)
      return;
    Visit(t, TraceDescriptorFor(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>& weak_member) {
    static_assert(sizeof(T), "T must be fully defined");
    static_assert(IsGarbageCollectedType<T>::value,
                  "T needs to be a garbage collected object");

    const T* value = weak_member.GetSafe();

    if (!value)
      return;

    DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value));
    VisitWeak(value, &weak_member, TraceDescriptorFor(value),
              &HandleWeakCell<T>);
  }

  // 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) {
    static_assert(sizeof(T), "T must be fully defined");
    if (std::is_polymorphic<T>::value) {
      const intptr_t vtable = *reinterpret_cast<const intptr_t*>(&t);
      if (!vtable)
        return;
    }
    TraceTrait<T>::Trace(this, &t);
  }

  template <typename T>
  void TraceEphemeron(const WeakMember<T>& key,
                      const void* value,
                      TraceCallback value_trace_callback) {
    T* t = key.Get();
    if (!t)
      return;
    VisitEphemeron(TraceDescriptorFor(t).base_object_payload, value,
                   value_trace_callback);
  }

  template <typename T>
  void TraceWeakContainer(const T* object,
                          const T* const* slot,
                          TraceDescriptor strong_desc,
                          TraceDescriptor weak_dec,
                          WeakCallback weak_callback,
                          const void* weak_callback_parameter) {
    static_assert(sizeof(T), "T must be fully defined");
    static_assert(IsGarbageCollectedType<T>::value,
                  "T needs to be a garbage collected object");
    VisitWeakContainer(reinterpret_cast<const void*>(object),
                       reinterpret_cast<const void* const*>(slot), strong_desc,
                       weak_dec, weak_callback, weak_callback_parameter);
  }

  template <typename T>
  void TraceMovablePointer(const T* const* slot) {
    RegisterMovableSlot(reinterpret_cast<const void* const*>(slot));
  }

  // Cross-component tracing interface.
  template <typename V8Type>
  void Trace(const TraceWrapperV8Reference<V8Type>& v8reference) {
    Visit(v8reference.template Cast<v8::Value>());
  }

  // Dynamic visitor interface.

  // Registers backing store pointers so that they can be moved and properly
  // updated.
  virtual void RegisterBackingStoreCallback(const void* backing,
                                            MovingObjectCallback) {}

  // Adds a |callback| that is invoked with |parameter| after liveness has been
  // computed on the whole object graph. The |callback| may use the provided
  // |LivenessBroker| to determine whether an object is considered alive or
  // dead.
  //
  // - Upon returning from the callback all references to dead objects must have
  //   been cleared.
  // - Any operation that extends the object graph, including allocation
  //   or reviving objects, is prohibited.
  // - Clearing out pointers is allowed.
  // - Removing elements from heap collections is allowed as these collections
  //   are aware of custom weakness and won't resize their backings.
  virtual void RegisterWeakCallback(WeakCallback callback,
                                    const void* parameter) {}

  // Registers an instance method using |RegisterWeakCallback|. See description
  // below.
  template <typename T, void (T::*method)(const LivenessBroker&)>
  void RegisterWeakCallbackMethod(const T* obj) {
    RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>::Trampoline,
                         obj);
  }

  // Returns whether the visitor is used in a concurrent setting.
  virtual bool IsConcurrent() const { return false; }

  // Defers invoking |desc| to the main thread when running concurrently.
  // Returns true if |desc| has been queued for later processing and false if
  // running in a non-concurrent setting.
  //
  // This can be used to defer processing data structures to the main thread
  // when support for concurrent processing is missing.
  virtual bool DeferredTraceIfConcurrent(TraceDescriptor desc) { return false; }

 protected:
  // Visits an object through a strong reference.
  virtual void Visit(const void*, TraceDescriptor) {}

  // Visits an object through a weak reference.
  virtual void VisitWeak(const void*,
                         const void*,
                         TraceDescriptor,
                         WeakCallback) {}

  // Visits cross-component references to V8.
  virtual void Visit(const TraceWrapperV8Reference<v8::Value>&) {}

  virtual void VisitRoot(const void* t,
                         TraceDescriptor desc,
                         const base::Location&) {
    Visit(t, desc);
  }

  // Visits ephemeron pairs which are a combination of weak and strong keys and
  // values.
  virtual void VisitEphemeron(const void*, const void*, TraceCallback) {}

  // Visits a container |object| holding ephemeron pairs held from |slot|.  The
  // descriptor |strong_desc| can be used to enforce strong treatment of
  // |object|. The |weak_desc| descriptor is invoked repeatedly until no
  // more new objects are found. It is expected that |weak_desc| processing
  // ultimately yields in a call to VisitEphemeron. After marking all reachable
  // objects, |weak_callback| is invoked with |weak_callback_parameter|. It is
  // expected that this callback is used to reset non-live entries in the
  // ephemeron container.
  virtual void VisitWeakContainer(const void* object,
                                  const void* const* slot,
                                  TraceDescriptor strong_desc,
                                  TraceDescriptor weak_desc,
                                  WeakCallback weak_callback,
                                  const void* weak_callback_parameter) {}

  virtual void RegisterMovableSlot(const void* const* slot) {}

  template <typename T>
  static TraceDescriptor TraceDescriptorFor(const T* traceable) {
    return TraceTrait<T>::GetTraceDescriptor(traceable);
  }

 private:
  template <typename T>
  static void HandleWeakCell(const LivenessBroker&, const void*);

  ThreadState* const state_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_VISITOR_H_