global-handles.h 10.3 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 <vector>
10

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

14 15
#include "src/handles.h"
#include "src/utils.h"
16

17 18
namespace v8 {
namespace internal {
19

20
class HeapStats;
21
class RootVisitor;
22

23 24 25 26 27 28
// Structure for tracking global handles.
// A single list keeps all the allocated global handles.
// Destroyed handles stay in the list but is added to the free list.
// At GC the destroyed global handles are removed from the free list
// and deallocated.

29
enum WeaknessType {
30 31
  // Embedder gets a handle to the dying object.
  FINALIZER_WEAK,
32
  // In the following cases, the embedder gets the parameter they passed in
33
  // earlier, and 0 or 2 first embedder fields. Note that the internal
34 35 36
  // 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.
37
  PHANTOM_WEAK,
38
  PHANTOM_WEAK_2_EMBEDDER_FIELDS,
39 40 41
  // The handle is automatically reset by the garbage collector when
  // the object is no longer reachable.
  PHANTOM_WEAK_RESET_HANDLE
42 43
};

44
class GlobalHandles {
45
 public:
46 47
  ~GlobalHandles();

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

51 52 53 54 55 56 57 58
  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(static_cast<Object*>(value)));
  }

59 60 61
  // Copy a global handle
  static Handle<Object> CopyGlobal(Object** location);

62
  // Destroy a global handle.
63
  static void Destroy(Object** location);
64 65 66

  // Make the global handle weak and set the callback parameter for the
  // handle.  When the garbage collector recognizes that only weak global
67 68 69 70 71 72 73
  // 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.
74 75 76
  static void MakeWeak(Object** location, void* parameter,
                       WeakCallbackInfo<void>::Callback weak_callback,
                       v8::WeakCallbackType type);
77

78 79
  static void MakeWeak(Object*** location_addr);

80 81
  static void AnnotateStrongRetainer(Object** location, const char* label);

82
  void RecordStats(HeapStats* stats);
83

84
  // Returns the current number of handles to global objects.
85
  int global_handles_count() const {
86 87 88
    return number_of_global_handles_;
  }

89 90 91 92 93 94 95 96
  size_t NumberOfPhantomHandleResets() {
    return number_of_phantom_handle_resets_;
  }

  void ResetNumberOfPhantomHandleResets() {
    number_of_phantom_handle_resets_ = 0;
  }

97
  size_t NumberOfNewSpaceNodes() { return new_space_nodes_.size(); }
98

99
  // Clear the weakness of a global handle.
100
  static void* ClearWeakness(Object** location);
101 102 103 104 105 106 107

  // Tells whether global handle is near death.
  static bool IsNearDeath(Object** location);

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

108
  // Process pending weak handles.
109
  // Returns the number of freed nodes.
110 111
  int PostGarbageCollectionProcessing(
      GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags);
112

113
  void IterateStrongRoots(RootVisitor* v);
114

115 116
  void IterateWeakRoots(RootVisitor* v);

117
  void IterateAllRoots(RootVisitor* v);
118

119
  void IterateAllNewSpaceRoots(RootVisitor* v);
120
  void IterateNewSpaceRoots(RootVisitor* v, size_t start, size_t end);
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 IterateAllRootsInNewSpaceWithClassIds(v8::PersistentHandleVisitor* v);
128

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

133 134
  // Iterates over weak roots on the heap.
  void IterateWeakRootsForFinalizers(RootVisitor* v);
135 136
  void IterateWeakRootsForPhantomHandles(
      WeakSlotCallbackWithHeap should_reset_handle);
137

138 139
  // Marks all handles that should be finalized based on the predicate
  // |should_reset_handle| as pending.
140
  void IdentifyWeakHandles(WeakSlotCallbackWithHeap should_reset_handle);
141

142
  // NOTE: Five ...NewSpace... functions below are used during
143 144 145 146
  // scavenge collections and iterate over sets of handles that are
  // guaranteed to contain all handles holding new space objects (but
  // may also include old space objects).

147
  // Iterates over strong and dependent handles. See the note above.
148
  void IterateNewSpaceStrongAndDependentRoots(RootVisitor* v);
149

150 151 152 153 154
  // Iterates over strong and dependent handles. See the note above.
  // Also marks unmodified nodes in the same iteration.
  void IterateNewSpaceStrongAndDependentRootsAndIdentifyUnmodified(
      RootVisitor* v, size_t start, size_t end);

155
  // Marks weak unmodified handles satisfying |is_dead| as pending.
156
  void MarkNewSpaceWeakUnmodifiedObjectsPending(
157
      WeakSlotCallbackWithHeap is_dead);
158

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

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

169
  // Tear down the global handle structure.
170 171 172
  void TearDown();

  Isolate* isolate() { return isolate_; }
173 174

#ifdef DEBUG
175 176
  void PrintStats();
  void Print();
177
#endif  // DEBUG
178

179 180
  void InvokeSecondPassPhantomCallbacks();

181
 private:
182 183 184 185
  // Internal node structures.
  class Node;
  class NodeBlock;
  class NodeIterator;
186
  class PendingPhantomCallback;
187 188

  explicit GlobalHandles(Isolate* isolate);
189

190
  void InvokeSecondPassPhantomCallbacksFromTask();
191 192
  int PostScavengeProcessing(int initial_post_gc_processing_count);
  int PostMarkSweepProcessing(int initial_post_gc_processing_count);
193
  int DispatchPendingPhantomCallbacks(bool synchronous_second_pass);
194
  void UpdateListOfNewSpaceNodes();
195 196
  void ApplyPersistentHandleVisitor(v8::PersistentHandleVisitor* visitor,
                                    Node* node);
197

198 199
  Isolate* isolate_;

200 201 202
  // Field always containing the number of handles to global objects.
  int number_of_global_handles_;

203 204 205 206 207
  // List of all allocated node blocks.
  NodeBlock* first_block_;

  // List of node blocks with used nodes.
  NodeBlock* first_used_block_;
208

209 210
  // Free list of nodes.
  Node* first_free_;
211

212 213
  // Contains all nodes holding new space objects. Note: when the list
  // is accessed, some of the objects may have been promoted already.
214
  std::vector<Node*> new_space_nodes_;
215

216
  int post_gc_processing_count_;
217

218 219
  size_t number_of_phantom_handle_resets_;

220
  std::vector<PendingPhantomCallback> pending_phantom_callbacks_;
221 222
  std::vector<PendingPhantomCallback> second_pass_callbacks_;
  bool second_pass_callbacks_task_posted_ = false;
223

224 225 226
  friend class Isolate;

  DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
227 228 229
};


230 231
class GlobalHandles::PendingPhantomCallback {
 public:
232
  typedef v8::WeakCallbackInfo<void> Data;
dcarney's avatar
dcarney committed
233 234
  PendingPhantomCallback(
      Node* node, Data::Callback callback, void* parameter,
235
      void* embedder_fields[v8::kEmbedderFieldsInWeakCallback])
dcarney's avatar
dcarney committed
236
      : node_(node), callback_(callback), parameter_(parameter) {
237 238
    for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
      embedder_fields_[i] = embedder_fields[i];
dcarney's avatar
dcarney committed
239 240
    }
  }
241

dcarney's avatar
dcarney committed
242
  void Invoke(Isolate* isolate);
243 244

  Node* node() { return node_; }
dcarney's avatar
dcarney committed
245
  Data::Callback callback() { return callback_; }
246 247 248 249

 private:
  Node* node_;
  Data::Callback callback_;
dcarney's avatar
dcarney committed
250
  void* parameter_;
251
  void* embedder_fields_[v8::kEmbedderFieldsInWeakCallback];
252 253 254
};


255 256 257
class EternalHandles {
 public:
  enum SingletonHandle {
258
    DATE_CACHE_VERSION,
259 260 261 262 263 264 265 266 267

    NUMBER_OF_SINGLETON_HANDLES
  };

  EternalHandles();
  ~EternalHandles();

  int NumberOfHandles() { return size_; }

268 269
  // Create an EternalHandle, overwriting the index.
  void Create(Isolate* isolate, Object* object, int* index);
270 271 272 273 274 275 276 277

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

  // Grab the handle for an existing SingletonHandle.
  inline Handle<Object> GetSingleton(SingletonHandle singleton) {
278
    DCHECK(Exists(singleton));
279 280 281 282 283 284 285 286 287 288 289 290
    return Get(singleton_handles_[singleton]);
  }

  // Checks whether a SingletonHandle has been assigned.
  inline bool Exists(SingletonHandle singleton) {
    return singleton_handles_[singleton] != kInvalidIndex;
  }

  // Assign a SingletonHandle to an empty slot and returns the handle.
  Handle<Object> CreateSingleton(Isolate* isolate,
                                 Object* object,
                                 SingletonHandle singleton) {
291
    Create(isolate, object, &singleton_handles_[singleton]);
292 293 294 295
    return Get(singleton_handles_[singleton]);
  }

  // Iterates over all handles.
296
  void IterateAllRoots(RootVisitor* visitor);
297
  // Iterates over all handles which might be in new space.
298
  void IterateNewSpaceRoots(RootVisitor* visitor);
299
  // Rebuilds new space list.
300
  void PostGarbageCollectionProcessing();
301 302 303 304 305 306 307 308 309

 private:
  static const int kInvalidIndex = -1;
  static const int kShift = 8;
  static const int kSize = 1 << kShift;
  static const int kMask = 0xff;

  // Gets the slot for an index
  inline Object** GetLocation(int index) {
310
    DCHECK(index >= 0 && index < size_);
311 312 313 314
    return &blocks_[index >> kShift][index & kMask];
  }

  int size_;
315 316
  std::vector<Object**> blocks_;
  std::vector<int> new_space_indices_;
317 318 319 320 321 322
  int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES];

  DISALLOW_COPY_AND_ASSIGN(EternalHandles);
};


323 324
}  // namespace internal
}  // namespace v8
325 326

#endif  // V8_GLOBAL_HANDLES_H_