global-handles.h 14.6 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 9
#include "include/v8.h"
#include "include/v8-profiler.h"
10

11 12 13
#include "src/handles.h"
#include "src/list.h"
#include "src/utils.h"
14

15 16
namespace v8 {
namespace internal {
17

18 19 20
class HeapStats;
class ObjectVisitor;

21 22 23 24 25 26
// 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.

27 28
// Data structures for tracking object groups and implicit references.

29 30
// An object group is treated like a single JS object: if one of object in
// the group is alive, all objects in the same group are considered alive.
31
// An object group is used to simulate object relationship in a DOM tree.
32 33 34 35 36 37 38 39

// An implicit references group consists of two parts: a parent object and a
// list of children objects.  If the parent is alive, all the children are alive
// too.

struct ObjectGroup {
  explicit ObjectGroup(size_t length)
      : info(NULL), length(length) {
40
    DCHECK(length > 0);
41
    objects = new Object**[length];
42
  }
43
  ~ObjectGroup();
44

45 46 47 48
  v8::RetainedObjectInfo* info;
  Object*** objects;
  size_t length;
};
49

50

51 52 53
struct ImplicitRefGroup {
  ImplicitRefGroup(HeapObject** parent, size_t length)
      : parent(parent), length(length) {
54
    DCHECK(length > 0);
55 56 57 58 59 60 61
    children = new Object**[length];
  }
  ~ImplicitRefGroup();

  HeapObject** parent;
  Object*** children;
  size_t length;
62 63 64
};


65 66 67 68 69 70 71
// For internal bookkeeping.
struct ObjectGroupConnection {
  ObjectGroupConnection(UniqueId id, Object** object)
      : id(id), object(object) {}

  bool operator==(const ObjectGroupConnection& other) const {
    return id == other.id;
72
  }
73

74 75
  bool operator<(const ObjectGroupConnection& other) const {
    return id < other.id;
76
  }
77

78 79 80
  UniqueId id;
  Object** object;
};
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

struct ObjectGroupRetainerInfo {
  ObjectGroupRetainerInfo(UniqueId id, RetainedObjectInfo* info)
      : id(id), info(info) {}

  bool operator==(const ObjectGroupRetainerInfo& other) const {
    return id == other.id;
  }

  bool operator<(const ObjectGroupRetainerInfo& other) const {
    return id < other.id;
  }

  UniqueId id;
  RetainedObjectInfo* info;
97 98
};

99
enum WeaknessType {
100 101
  // Embedder gets a handle to the dying object.
  FINALIZER_WEAK,
102
  // In the following cases, the embedder gets the parameter they passed in
103
  // earlier, and 0 or 2 first internal fields. Note that the internal
104 105 106
  // 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.
107
  PHANTOM_WEAK,
108
  PHANTOM_WEAK_2_INTERNAL_FIELDS,
109 110 111
  // The handle is automatically reset by the garbage collector when
  // the object is no longer reachable.
  PHANTOM_WEAK_RESET_HANDLE
112 113
};

114
class GlobalHandles {
115
 public:
116 117 118 119 120 121
  enum IterationMode {
    HANDLE_PHANTOM_NODES_VISIT_OTHERS,
    VISIT_OTHERS,
    HANDLE_PHANTOM_NODES
  };

122 123
  ~GlobalHandles();

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

127 128 129
  // Copy a global handle
  static Handle<Object> CopyGlobal(Object** location);

130
  // Destroy a global handle.
131
  static void Destroy(Object** location);
132 133 134

  // Make the global handle weak and set the callback parameter for the
  // handle.  When the garbage collector recognizes that only weak global
135 136 137 138 139 140 141
  // 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.
142 143 144
  static void MakeWeak(Object** location, void* parameter,
                       WeakCallbackInfo<void>::Callback weak_callback,
                       v8::WeakCallbackType type);
145

146 147
  static void MakeWeak(Object*** location_addr);

148
  void RecordStats(HeapStats* stats);
149

150 151 152
  // Returns the current number of weak handles.
  int NumberOfWeakHandles();

153 154
  // Returns the current number of weak handles to global objects.
  // These handles are also included in NumberOfWeakHandles().
155
  int NumberOfGlobalObjectWeakHandles();
156

157
  // Returns the current number of handles to global objects.
158
  int global_handles_count() const {
159 160 161
    return number_of_global_handles_;
  }

162 163 164 165 166 167 168 169
  size_t NumberOfPhantomHandleResets() {
    return number_of_phantom_handle_resets_;
  }

  void ResetNumberOfPhantomHandleResets() {
    number_of_phantom_handle_resets_ = 0;
  }

170
  // Clear the weakness of a global handle.
171
  static void* ClearWeakness(Object** location);
172

173
  // Mark the reference to this object independent of any object group.
174
  static void MarkIndependent(Object** location);
175 176

  static bool IsIndependent(Object** location);
177

178 179 180 181 182 183
  // Tells whether global handle is near death.
  static bool IsNearDeath(Object** location);

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

184
  // Process pending weak handles.
185
  // Returns the number of freed nodes.
186 187
  int PostGarbageCollectionProcessing(
      GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags);
188

189
  // Iterates over all strong handles.
190
  void IterateStrongRoots(ObjectVisitor* v);
191

192
  // Iterates over all handles.
193
  void IterateAllRoots(ObjectVisitor* v);
194

195
  // Iterates over all handles that have embedder-assigned class ID.
196
  void IterateAllRootsWithClassIds(ObjectVisitor* v);
197

198 199 200 201
  // Iterates over all handles in the new space that have embedder-assigned
  // class ID.
  void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v);

202 203 204 205
  // Iterate over all handles in the new space that are weak, unmodified
  // and have class IDs
  void IterateWeakRootsInNewSpaceWithClassIds(ObjectVisitor* v);

206
  // Iterates over all weak roots in heap.
207
  void IterateWeakRoots(ObjectVisitor* v);
208

209 210
  // Find all weak handles satisfying the callback predicate, mark
  // them as pending.
211
  void IdentifyWeakHandles(WeakSlotCallback f);
212

213
  // NOTE: Five ...NewSpace... functions below are used during
214 215 216 217 218 219 220
  // 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).

  // Iterates over strong and dependent handles. See the node above.
  void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v);

221 222
  // Finds weak independent or partially independent handles satisfying
  // the callback predicate and marks them as pending. See the note above.
223
  void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f);
224

225 226
  // Iterates over weak independent or partially independent handles.
  // See the note above.
227 228
  void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);

229 230 231 232 233 234 235
  // Finds weak independent or unmodified handles satisfying
  // the callback predicate and marks them as pending. See the note above.
  void MarkNewSpaceWeakUnmodifiedObjectsPending(
      WeakSlotCallbackWithHeap is_unscavenged);

  // Iterates over weak independent or unmodified handles.
  // See the note above.
236
  template <IterationMode mode>
237 238 239 240 241 242
  void IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v);

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

243 244 245 246 247
  // Iterate over objects in object groups that have at least one object
  // which requires visiting. The callback has to return true if objects
  // can be skipped and false otherwise.
  bool IterateObjectGroups(ObjectVisitor* v, WeakSlotCallbackWithHeap can_skip);

248 249 250
  // Print all objects in object groups
  void PrintObjectGroups();

251
  // Add an object group.
252
  // Should be only used in GC callback function before a collection.
253
  // All groups are destroyed after a garbage collection.
254 255 256
  void AddObjectGroup(Object*** handles,
                      size_t length,
                      v8::RetainedObjectInfo* info);
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
  // Associates handle with the object group represented by id.
  // Should be only used in GC callback function before a collection.
  // All groups are destroyed after a garbage collection.
  void SetObjectGroupId(Object** handle, UniqueId id);

  // Set RetainedObjectInfo for an object group. Should not be called more than
  // once for a group. Should not be called for a group which contains no
  // handles.
  void SetRetainedObjectInfo(UniqueId id, RetainedObjectInfo* info);

  // Adds an implicit reference from a group to an object. Should be only used
  // in GC callback function before a collection. All implicit references are
  // destroyed after a mark-compact collection.
  void SetReferenceFromGroup(UniqueId id, Object** child);

  // Adds an implicit reference from a parent object to a child object. Should
  // be only used in GC callback function before a collection. All implicit
  // references are destroyed after a mark-compact collection.
  void SetReference(HeapObject** parent, Object** child);

  List<ObjectGroup*>* object_groups() {
    ComputeObjectGroupsAndImplicitReferences();
    return &object_groups_;
  }
282

283
  List<ImplicitRefGroup*>* implicit_ref_groups() {
284
    ComputeObjectGroupsAndImplicitReferences();
285 286
    return &implicit_ref_groups_;
  }
287

288
  // Remove bags, this should only happen after GC.
289 290
  void RemoveObjectGroups();
  void RemoveImplicitRefGroups();
291 292

  // Tear down the global handle structure.
293 294 295
  void TearDown();

  Isolate* isolate() { return isolate_; }
296 297

#ifdef DEBUG
298 299
  void PrintStats();
  void Print();
300
#endif  // DEBUG
301

302
 private:
303 304
  explicit GlobalHandles(Isolate* isolate);

305 306 307 308 309 310 311 312 313
  // Migrates data from the internal representation (object_group_connections_,
  // retainer_infos_ and implicit_ref_connections_) to the public and more
  // efficient representation (object_groups_ and implicit_ref_groups_).
  void ComputeObjectGroupsAndImplicitReferences();

  // v8::internal::List is inefficient even for small number of elements, if we
  // don't assign any initial capacity.
  static const int kObjectGroupConnectionsCapacity = 20;

314 315
  class PendingPhantomCallback;

316
  // Helpers for PostGarbageCollectionProcessing.
317 318
  static void InvokeSecondPassPhantomCallbacks(
      List<PendingPhantomCallback>* callbacks, Isolate* isolate);
319 320
  int PostScavengeProcessing(int initial_post_gc_processing_count);
  int PostMarkSweepProcessing(int initial_post_gc_processing_count);
321
  int DispatchPendingPhantomCallbacks(bool synchronous_second_pass);
322 323
  void UpdateListOfNewSpaceNodes();

324
  // Internal node structures.
325
  class Node;
326 327
  class NodeBlock;
  class NodeIterator;
328
  class PendingPhantomCallbacksSecondPassTask;
329

330 331
  Isolate* isolate_;

332 333 334
  // Field always containing the number of handles to global objects.
  int number_of_global_handles_;

335 336 337 338 339
  // List of all allocated node blocks.
  NodeBlock* first_block_;

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

341 342
  // Free list of nodes.
  Node* first_free_;
343

344 345 346 347
  // Contains all nodes holding new space objects. Note: when the list
  // is accessed, some of the objects may have been promoted already.
  List<Node*> new_space_nodes_;

348
  int post_gc_processing_count_;
349

350 351
  size_t number_of_phantom_handle_resets_;

352 353
  // Object groups and implicit references, public and more efficient
  // representation.
354 355
  List<ObjectGroup*> object_groups_;
  List<ImplicitRefGroup*> implicit_ref_groups_;
356

357 358 359 360 361 362
  // Object groups and implicit references, temporary representation while
  // constructing the groups.
  List<ObjectGroupConnection> object_group_connections_;
  List<ObjectGroupRetainerInfo> retainer_infos_;
  List<ObjectGroupConnection> implicit_ref_connections_;

363 364
  List<PendingPhantomCallback> pending_phantom_callbacks_;

365 366 367
  friend class Isolate;

  DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
368 369 370
};


371 372
class GlobalHandles::PendingPhantomCallback {
 public:
373
  typedef v8::WeakCallbackInfo<void> Data;
dcarney's avatar
dcarney committed
374 375 376 377 378 379 380 381
  PendingPhantomCallback(
      Node* node, Data::Callback callback, void* parameter,
      void* internal_fields[v8::kInternalFieldsInWeakCallback])
      : node_(node), callback_(callback), parameter_(parameter) {
    for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) {
      internal_fields_[i] = internal_fields[i];
    }
  }
382

dcarney's avatar
dcarney committed
383
  void Invoke(Isolate* isolate);
384 385

  Node* node() { return node_; }
dcarney's avatar
dcarney committed
386
  Data::Callback callback() { return callback_; }
387 388 389 390

 private:
  Node* node_;
  Data::Callback callback_;
dcarney's avatar
dcarney committed
391 392
  void* parameter_;
  void* internal_fields_[v8::kInternalFieldsInWeakCallback];
393 394 395
};


396 397 398
class EternalHandles {
 public:
  enum SingletonHandle {
399
    DATE_CACHE_VERSION,
400 401 402 403 404 405 406 407 408

    NUMBER_OF_SINGLETON_HANDLES
  };

  EternalHandles();
  ~EternalHandles();

  int NumberOfHandles() { return size_; }

409 410
  // Create an EternalHandle, overwriting the index.
  void Create(Isolate* isolate, Object* object, int* index);
411 412 413 414 415 416 417 418

  // 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) {
419
    DCHECK(Exists(singleton));
420 421 422 423 424 425 426 427 428 429 430 431
    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) {
432
    Create(isolate, object, &singleton_handles_[singleton]);
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
    return Get(singleton_handles_[singleton]);
  }

  // Iterates over all handles.
  void IterateAllRoots(ObjectVisitor* visitor);
  // Iterates over all handles which might be in new space.
  void IterateNewSpaceRoots(ObjectVisitor* visitor);
  // Rebuilds new space list.
  void PostGarbageCollectionProcessing(Heap* heap);

 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) {
451
    DCHECK(index >= 0 && index < size_);
452 453 454 455 456 457 458 459 460 461 462 463
    return &blocks_[index >> kShift][index & kMask];
  }

  int size_;
  List<Object**> blocks_;
  List<int> new_space_indices_;
  int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES];

  DISALLOW_COPY_AND_ASSIGN(EternalHandles);
};


464 465
}  // namespace internal
}  // namespace v8
466 467

#endif  // V8_GLOBAL_HANDLES_H_