global-handles.h 10.4 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

#ifndef V8_GLOBAL_HANDLES_H_
#define V8_GLOBAL_HANDLES_H_

8
#include <type_traits>
9
#include <utility>
10
#include <vector>
11

12 13
#include "include/v8.h"
#include "include/v8-profiler.h"
14

15
#include "src/handles.h"
16
#include "src/objects.h"
17
#include "src/utils.h"
18

19 20
namespace v8 {
namespace internal {
21

22
class HeapStats;
23
class RootVisitor;
24

25
enum WeaknessType {
26 27
  // Embedder gets a handle to the dying object.
  FINALIZER_WEAK,
28
  // In the following cases, the embedder gets the parameter they passed in
29
  // earlier, and 0 or 2 first embedder fields. Note that the internal
30 31 32
  // fields must contain aligned non-V8 pointers.  Getting pointers to V8
  // objects through this interface would be GC unsafe so in that case the
  // embedder gets a null pointer instead.
33
  PHANTOM_WEAK,
34
  PHANTOM_WEAK_2_EMBEDDER_FIELDS,
35 36 37
  // The handle is automatically reset by the garbage collector when
  // the object is no longer reachable.
  PHANTOM_WEAK_RESET_HANDLE
38 39
};

40 41
// Global handles hold handles that are independent of stack-state and can have
// callbacks and finalizers attached to them.
42
class V8_EXPORT_PRIVATE GlobalHandles final {
43
 public:
44 45 46
  template <class NodeType>
  class NodeBlock;

47 48 49
  //
  // API for regular handles.
  //
50

51
  static void MoveGlobal(Address** from, Address** to);
52 53

  static Handle<Object> CopyGlobal(Address* location);
54

55 56
  static void Destroy(Address* location);

57 58
  // Make the global handle weak and set the callback parameter for the
  // handle.  When the garbage collector recognizes that only weak global
59 60 61 62 63 64 65
  // handles point to an object the callback function is invoked (for each
  // handle) with the handle and corresponding parameter as arguments.  By
  // default the handle still contains a pointer to the object that is being
  // collected.  For this reason the object is not collected until the next
  // GC.  For a phantom weak handle the handle is cleared (set to a Smi)
  // before the callback is invoked, but the handle can still be identified
  // in the callback by using the location() of the handle.
66 67 68 69
  static void MakeWeak(Address* location, void* parameter,
                       WeakCallbackInfo<void>::Callback weak_callback,
                       v8::WeakCallbackType type);
  static void MakeWeak(Address** location_addr);
70

71
  static void AnnotateStrongRetainer(Address* location, const char* label);
72

73
  // Clear the weakness of a global handle.
74
  static void* ClearWeakness(Address* location);
75 76

  // Tells whether global handle is weak.
77
  static bool IsWeak(Address* location);
78

79 80 81 82 83 84 85 86 87 88
  //
  // API for traced handles.
  //

  static void MoveTracedGlobal(Address** from, Address** to);
  static void DestroyTraced(Address* location);
  static void SetFinalizationCallbackForTraced(
      Address* location, void* parameter,
      WeakCallbackInfo<void>::Callback callback);

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
  explicit GlobalHandles(Isolate* isolate);
  ~GlobalHandles();

  // Creates a new global handle that is alive until Destroy is called.
  Handle<Object> Create(Object value);
  Handle<Object> Create(Address value);

  template <typename T>
  Handle<T> Create(T value) {
    static_assert(std::is_base_of<Object, T>::value, "static type violation");
    // The compiler should only pick this method if T is not Object.
    static_assert(!std::is_same<Object, T>::value, "compiler error");
    return Handle<T>::cast(Create(Object(value)));
  }

104 105 106
  Handle<Object> CreateTraced(Object value, Address* slot);
  Handle<Object> CreateTraced(Address value, Address* slot);

107 108
  void RecordStats(HeapStats* stats);

109
  size_t InvokeFirstPassWeakCallbacks();
110
  void InvokeSecondPassPhantomCallbacks();
111

112
  // Process pending weak handles.
113
  // Returns the number of freed nodes.
114
  size_t PostGarbageCollectionProcessing(
115
      GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags);
116

117
  void IterateStrongRoots(RootVisitor* v);
118
  void IterateWeakRoots(RootVisitor* v);
119
  void IterateAllRoots(RootVisitor* v);
120
  void IterateAllYoungRoots(RootVisitor* v);
121

122
  // Iterates over all handles that have embedder-assigned class ID.
123
  void IterateAllRootsWithClassIds(v8::PersistentHandleVisitor* v);
124

125 126
  // Iterates over all handles in the new space that have embedder-assigned
  // class ID.
127
  void IterateAllYoungRootsWithClassIds(v8::PersistentHandleVisitor* v);
128

129 130
  // Iterate over all handles in the new space that are weak, unmodified
  // and have class IDs
131
  void IterateYoungWeakRootsWithClassIds(v8::PersistentHandleVisitor* v);
132

133 134 135 136 137 138 139 140 141 142
  // Iterates over all traces handles represented by TracedGlobal.
  void IterateTracedNodes(
      v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor);

  // Marks handles with finalizers on the predicate |should_reset_handle| as
  // pending.
  void IterateWeakRootsIdentifyFinalizers(
      WeakSlotCallbackWithHeap should_reset_handle);
  // Uses the provided visitor |v| to mark handles with finalizers that are
  // pending.
143
  void IterateWeakRootsForFinalizers(RootVisitor* v);
144 145
  // Marks handles that are phantom or have callbacks based on the predicate
  // |should_reset_handle| as pending.
146 147
  void IterateWeakRootsForPhantomHandles(
      WeakSlotCallbackWithHeap should_reset_handle);
148

149 150 151 152
  //  Note: The following *Young* methods are used for the Scavenger to
  //  identify and process handles in the young generation. The set of young
  //  handles is complete but the methods may encounter handles that are
  //  already in old space.
153

154
  // Iterates over strong and dependent handles. See the note above.
155
  void IterateYoungStrongAndDependentRoots(RootVisitor* v);
156

157
  // Marks weak unmodified handles satisfying |is_dead| as pending.
158
  void MarkYoungWeakUnmodifiedObjectsPending(WeakSlotCallbackWithHeap is_dead);
159

160 161
  // Iterates over weak independent or unmodified handles.
  // See the note above.
162 163
  void IterateYoungWeakUnmodifiedRootsForFinalizers(RootVisitor* v);
  void IterateYoungWeakUnmodifiedRootsForPhantomHandles(
164
      RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle);
165 166 167 168 169

  // Identify unmodified objects that are in weak state and marks them
  // unmodified
  void IdentifyWeakUnmodifiedObjects(WeakSlotCallback is_unmodified);

170
  Isolate* isolate() const { return isolate_; }
171

172 173 174 175 176 177 178 179
  // Number of global handles.
  size_t handles_count() const { return handles_count_; }

  size_t GetAndResetGlobalHandleResetCount() {
    size_t old = number_of_phantom_handle_resets_;
    number_of_phantom_handle_resets_ = 0;
    return old;
  }
180 181

#ifdef DEBUG
182 183
  void PrintStats();
  void Print();
184
#endif  // DEBUG
185

186
 private:
187 188
  // Internal node structures.
  class Node;
189
  template <class BlockType>
190
  class NodeIterator;
191 192
  template <class NodeType>
  class NodeSpace;
193
  class PendingPhantomCallback;
194
  class TracedNode;
195

196 197
  bool InRecursiveGC(unsigned gc_processing_counter);

198
  void InvokeSecondPassPhantomCallbacksFromTask();
199
  void InvokeOrScheduleSecondPassPhantomCallbacks(bool synchronous_second_pass);
200 201 202
  size_t PostScavengeProcessing(unsigned post_processing_count);
  size_t PostMarkSweepProcessing(unsigned post_processing_count);

203 204 205 206
  template <typename T>
  size_t InvokeFirstPassWeakCallbacks(
      std::vector<std::pair<T*, PendingPhantomCallback>>* pending);

207
  template <typename T>
208 209
  void UpdateAndCompactListOfYoungNode(std::vector<T*>* node_list);
  void UpdateListOfYoungNodes();
210

211 212
  void ApplyPersistentHandleVisitor(v8::PersistentHandleVisitor* visitor,
                                    Node* node);
213

214
  Isolate* const isolate_;
215

216
  std::unique_ptr<NodeSpace<Node>> regular_nodes_;
217
  // Contains all nodes holding young objects. Note: when the list
218
  // is accessed, some of the objects may have been promoted already.
219
  std::vector<Node*> young_nodes_;
220

221
  std::unique_ptr<NodeSpace<TracedNode>> traced_nodes_;
222
  std::vector<TracedNode*> traced_young_nodes_;
223

224
  // Field always containing the number of handles to global objects.
225 226
  size_t handles_count_ = 0;
  size_t number_of_phantom_handle_resets_ = 0;
227

228 229 230 231
  std::vector<std::pair<Node*, PendingPhantomCallback>>
      regular_pending_phantom_callbacks_;
  std::vector<std::pair<TracedNode*, PendingPhantomCallback>>
      traced_pending_phantom_callbacks_;
232 233
  std::vector<PendingPhantomCallback> second_pass_callbacks_;
  bool second_pass_callbacks_task_posted_ = false;
234
  bool running_second_pass_callbacks_ = false;
235

236 237
  // Counter for recursive garbage collections during callback processing.
  unsigned post_gc_processing_count_ = 0;
238 239

  DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
240 241
};

242
class GlobalHandles::PendingPhantomCallback final {
243
 public:
244
  typedef v8::WeakCallbackInfo<void> Data;
245 246 247

  enum InvocationType { kFirstPass, kSecondPass };

dcarney's avatar
dcarney committed
248
  PendingPhantomCallback(
249
      Data::Callback callback, void* parameter,
250
      void* embedder_fields[v8::kEmbedderFieldsInWeakCallback])
251
      : callback_(callback), parameter_(parameter) {
252 253
    for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
      embedder_fields_[i] = embedder_fields[i];
dcarney's avatar
dcarney committed
254 255
    }
  }
256

257
  void Invoke(Isolate* isolate, InvocationType type);
258

259
  Data::Callback callback() const { return callback_; }
260 261 262

 private:
  Data::Callback callback_;
dcarney's avatar
dcarney committed
263
  void* parameter_;
264
  void* embedder_fields_[v8::kEmbedderFieldsInWeakCallback];
265 266
};

267
class EternalHandles final {
268
 public:
269
  EternalHandles() = default;
270 271
  ~EternalHandles();

272
  // Create an EternalHandle, overwriting the index.
273
  V8_EXPORT_PRIVATE void Create(Isolate* isolate, Object object, int* index);
274 275 276 277 278 279 280

  // Grab the handle for an existing EternalHandle.
  inline Handle<Object> Get(int index) {
    return Handle<Object>(GetLocation(index));
  }

  // Iterates over all handles.
281
  void IterateAllRoots(RootVisitor* visitor);
282 283
  // Iterates over all handles which might be in the young generation.
  void IterateYoungRoots(RootVisitor* visitor);
284
  // Rebuilds new space list.
285
  void PostGarbageCollectionProcessing();
286

287 288
  size_t handles_count() const { return size_; }

289 290 291 292 293 294
 private:
  static const int kInvalidIndex = -1;
  static const int kShift = 8;
  static const int kSize = 1 << kShift;
  static const int kMask = 0xff;

295 296 297
  // Gets the slot for an index. This returns an Address* rather than an
  // ObjectSlot in order to avoid #including slots.h in this header file.
  inline Address* GetLocation(int index) {
298
    DCHECK(index >= 0 && index < size_);
299 300 301
    return &blocks_[index >> kShift][index & kMask];
  }

302
  int size_ = 0;
303
  std::vector<Address*> blocks_;
304
  std::vector<int> young_node_indices_;
305 306 307 308

  DISALLOW_COPY_AND_ASSIGN(EternalHandles);
};

309 310
}  // namespace internal
}  // namespace v8
311 312

#endif  // V8_GLOBAL_HANDLES_H_