Line data Source code
1 : // Copyright 2009 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/global-handles.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/base/compiler-specific.h"
9 : #include "src/cancelable-task.h"
10 : #include "src/heap/embedder-tracing.h"
11 : #include "src/heap/heap-write-barrier-inl.h"
12 : #include "src/objects-inl.h"
13 : #include "src/objects/slots.h"
14 : #include "src/task-utils.h"
15 : #include "src/v8.h"
16 : #include "src/visitors.h"
17 : #include "src/vm-state-inl.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : namespace {
23 :
24 : constexpr size_t kBlockSize = 256;
25 :
26 : } // namespace
27 :
28 : template <class _NodeType>
29 107702 : class GlobalHandles::NodeBlock final {
30 : public:
31 : using BlockType = NodeBlock<_NodeType>;
32 : using NodeType = _NodeType;
33 :
34 : V8_INLINE static NodeBlock* From(NodeType* node);
35 :
36 53851 : NodeBlock(GlobalHandles* global_handles,
37 : GlobalHandles::NodeSpace<NodeType>* space,
38 : NodeBlock* next) V8_NOEXCEPT : next_(next),
39 : global_handles_(global_handles),
40 13839707 : space_(space) {}
41 :
42 : NodeType* at(size_t index) { return &nodes_[index]; }
43 : const NodeType* at(size_t index) const { return &nodes_[index]; }
44 : GlobalHandles::NodeSpace<NodeType>* space() const { return space_; }
45 : GlobalHandles* global_handles() const { return global_handles_; }
46 :
47 : V8_INLINE bool IncreaseUsage();
48 : V8_INLINE bool DecreaseUsage();
49 :
50 : V8_INLINE void ListAdd(NodeBlock** top);
51 : V8_INLINE void ListRemove(NodeBlock** top);
52 :
53 : NodeBlock* next() const { return next_; }
54 : NodeBlock* next_used() const { return next_used_; }
55 :
56 : private:
57 : NodeType nodes_[kBlockSize];
58 : NodeBlock* const next_;
59 : GlobalHandles* const global_handles_;
60 : GlobalHandles::NodeSpace<NodeType>* const space_;
61 : NodeBlock* next_used_ = nullptr;
62 : NodeBlock* prev_used_ = nullptr;
63 : uint32_t used_nodes_ = 0;
64 :
65 : DISALLOW_COPY_AND_ASSIGN(NodeBlock);
66 : };
67 :
68 : template <class NodeType>
69 : GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From(
70 : NodeType* node) {
71 : uintptr_t ptr =
72 18628355 : reinterpret_cast<uintptr_t>(node) - sizeof(NodeType) * node->index();
73 18628355 : BlockType* block = reinterpret_cast<BlockType*>(ptr);
74 : DCHECK_EQ(node, block->at(node->index()));
75 : return block;
76 : }
77 :
78 : template <class NodeType>
79 : bool GlobalHandles::NodeBlock<NodeType>::IncreaseUsage() {
80 : DCHECK_LT(used_nodes_, kBlockSize);
81 6449707 : return used_nodes_++ == 0;
82 : }
83 :
84 : template <class NodeType>
85 : void GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) {
86 84845 : BlockType* old_top = *top;
87 84845 : *top = this;
88 84845 : next_used_ = old_top;
89 84845 : prev_used_ = nullptr;
90 84845 : if (old_top != nullptr) {
91 12661 : old_top->prev_used_ = this;
92 : }
93 : }
94 :
95 : template <class NodeType>
96 : bool GlobalHandles::NodeBlock<NodeType>::DecreaseUsage() {
97 : DCHECK_GT(used_nodes_, 0);
98 6089319 : return --used_nodes_ == 0;
99 : }
100 :
101 : template <class NodeType>
102 : void GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) {
103 72540 : if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
104 72540 : if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
105 72540 : if (this == *top) {
106 69590 : *top = next_used_;
107 : }
108 : }
109 :
110 : template <class BlockType>
111 : class GlobalHandles::NodeIterator final {
112 : public:
113 : using NodeType = typename BlockType::NodeType;
114 :
115 : // Iterator traits.
116 : using iterator_category = std::forward_iterator_tag;
117 : using difference_type = std::ptrdiff_t;
118 : using value_type = NodeType*;
119 : using reference = value_type;
120 : using pointer = value_type*;
121 :
122 : explicit NodeIterator(BlockType* block) V8_NOEXCEPT : block_(block) {}
123 : NodeIterator(NodeIterator&& other) V8_NOEXCEPT : block_(other.block_),
124 : index_(other.index_) {}
125 :
126 : bool operator==(const NodeIterator& other) const {
127 : return block_ == other.block_;
128 : }
129 : bool operator!=(const NodeIterator& other) const {
130 : return block_ != other.block_;
131 : }
132 :
133 : NodeIterator& operator++() {
134 154219520 : if (++index_ < kBlockSize) return *this;
135 : index_ = 0;
136 602420 : block_ = block_->next_used();
137 : return *this;
138 : }
139 :
140 : NodeType* operator*() { return block_->at(index_); }
141 : NodeType* operator->() { return block_->at(index_); }
142 :
143 : private:
144 : BlockType* block_ = nullptr;
145 : size_t index_ = 0;
146 :
147 : DISALLOW_COPY_AND_ASSIGN(NodeIterator);
148 : };
149 :
150 : template <class NodeType>
151 : class GlobalHandles::NodeSpace final {
152 : public:
153 : using BlockType = NodeBlock<NodeType>;
154 : using iterator = NodeIterator<BlockType>;
155 :
156 : static NodeSpace* From(NodeType* node);
157 : static void Release(NodeType* node);
158 :
159 : explicit NodeSpace(GlobalHandles* global_handles) V8_NOEXCEPT
160 122098 : : global_handles_(global_handles) {}
161 : ~NodeSpace();
162 :
163 : V8_INLINE NodeType* Acquire(Object object);
164 :
165 : iterator begin() { return iterator(first_used_block_); }
166 : iterator end() { return iterator(nullptr); }
167 :
168 : private:
169 : void PutNodesOnFreeList(BlockType* block);
170 : V8_INLINE void Free(NodeType* node);
171 :
172 : GlobalHandles* const global_handles_;
173 : BlockType* first_block_ = nullptr;
174 : BlockType* first_used_block_ = nullptr;
175 : NodeType* first_free_ = nullptr;
176 : };
177 :
178 : template <class NodeType>
179 122068 : GlobalHandles::NodeSpace<NodeType>::~NodeSpace() {
180 175919 : auto* block = first_block_;
181 297987 : while (block != nullptr) {
182 : auto* tmp = block->next();
183 53851 : delete block;
184 : block = tmp;
185 : }
186 122068 : }
187 :
188 : template <class NodeType>
189 : NodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) {
190 12899342 : if (first_free_ == nullptr) {
191 6503558 : first_block_ = new BlockType(global_handles_, this, first_block_);
192 53851 : PutNodesOnFreeList(first_block_);
193 : }
194 : DCHECK_NOT_NULL(first_free_);
195 6449706 : NodeType* node = first_free_;
196 6449706 : first_free_ = first_free_->next_free();
197 6449707 : node->Acquire(object);
198 : BlockType* block = BlockType::From(node);
199 6449707 : if (block->IncreaseUsage()) {
200 : block->ListAdd(&first_used_block_);
201 : }
202 12899414 : global_handles_->isolate()->counters()->global_handles()->Increment();
203 6449707 : global_handles_->handles_count_++;
204 : DCHECK(node->IsInUse());
205 : return node;
206 : }
207 :
208 : template <class NodeType>
209 53851 : void GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) {
210 13785856 : for (int32_t i = kBlockSize - 1; i >= 0; --i) {
211 13785856 : NodeType* node = block->at(i);
212 : const uint8_t index = static_cast<uint8_t>(i);
213 : DCHECK_EQ(i, index);
214 13785856 : node->set_index(index);
215 13785856 : node->Free(first_free_);
216 13785856 : first_free_ = node;
217 : }
218 53851 : }
219 :
220 : template <class NodeType>
221 6089319 : void GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) {
222 6089319 : BlockType* block = BlockType::From(node);
223 : block->space()->Free(node);
224 6089319 : }
225 :
226 : template <class NodeType>
227 : void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
228 6089319 : node->Release(first_free_);
229 6089319 : first_free_ = node;
230 : BlockType* block = BlockType::From(node);
231 6089319 : if (block->DecreaseUsage()) {
232 : block->ListRemove(&first_used_block_);
233 : }
234 6089319 : global_handles_->isolate()->counters()->global_handles()->Decrement();
235 6089319 : global_handles_->handles_count_--;
236 : }
237 :
238 : template <class Child>
239 : class NodeBase {
240 : public:
241 : static Child* FromLocation(Address* location) {
242 : return reinterpret_cast<Child*>(location);
243 : }
244 :
245 : NodeBase() {
246 : DCHECK_EQ(offsetof(NodeBase, object_), 0);
247 : DCHECK_EQ(offsetof(NodeBase, class_id_), Internals::kNodeClassIdOffset);
248 : DCHECK_EQ(offsetof(NodeBase, flags_), Internals::kNodeFlagsOffset);
249 : }
250 :
251 : #ifdef ENABLE_HANDLE_ZAPPING
252 : ~NodeBase() {
253 : ClearFields();
254 13785686 : data_.next_free = nullptr;
255 13785686 : index_ = 0;
256 : }
257 : #endif
258 :
259 : void Free(Child* free_list) {
260 : ClearFields();
261 : AsChild()->MarkAsFree();
262 19875175 : data_.next_free = free_list;
263 : }
264 :
265 6449707 : void Acquire(Object object) {
266 : DCHECK(!AsChild()->IsInUse());
267 : CheckFieldsAreCleared();
268 6449707 : object_ = object.ptr();
269 : AsChild()->MarkAsUsed();
270 6449707 : data_.parameter = nullptr;
271 : DCHECK(AsChild()->IsInUse());
272 6449707 : }
273 :
274 6089319 : void Release(Child* free_list) {
275 : DCHECK(AsChild()->IsInUse());
276 : Free(free_list);
277 : DCHECK(!AsChild()->IsInUse());
278 6089319 : }
279 :
280 : Object object() const { return Object(object_); }
281 21758812 : FullObjectSlot location() { return FullObjectSlot(&object_); }
282 6449737 : Handle<Object> handle() { return Handle<Object>(&object_); }
283 :
284 18628353 : uint8_t index() const { return index_; }
285 13785856 : void set_index(uint8_t value) { index_ = value; }
286 :
287 : uint16_t wrapper_class_id() const { return class_id_; }
288 : bool has_wrapper_class_id() const {
289 : return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
290 : }
291 :
292 : // Accessors for next free node in the free list.
293 70 : Child* next_free() {
294 : DCHECK(!AsChild()->IsInUse());
295 70 : return data_.next_free;
296 : }
297 :
298 : void set_parameter(void* parameter) {
299 : DCHECK(AsChild()->IsInUse());
300 3435414 : data_.parameter = parameter;
301 : }
302 : void* parameter() const {
303 : DCHECK(AsChild()->IsInUse());
304 : return data_.parameter;
305 : }
306 :
307 : protected:
308 : Child* AsChild() { return reinterpret_cast<Child*>(this); }
309 : const Child* AsChild() const { return reinterpret_cast<const Child*>(this); }
310 :
311 : void ClearFields() {
312 : // Zap the values for eager trapping.
313 33660861 : object_ = kGlobalHandleZapValue;
314 33660861 : class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
315 : AsChild()->ClearImplFields();
316 : }
317 :
318 : void CheckFieldsAreCleared() {
319 : DCHECK_EQ(kGlobalHandleZapValue, object_);
320 : DCHECK_EQ(v8::HeapProfiler::kPersistentHandleNoClassId, class_id_);
321 : AsChild()->CheckImplFieldsAreCleared();
322 : }
323 :
324 : // Storage for object pointer.
325 : //
326 : // Placed first to avoid offset computation. The stored data is equivalent to
327 : // an Object. It is stored as a plain Address for convenience (smallest number
328 : // of casts), and because it is a private implementation detail: the public
329 : // interface provides type safety.
330 : Address object_;
331 :
332 : // Class id set by the embedder.
333 : uint16_t class_id_;
334 :
335 : // Index in the containing handle block.
336 : uint8_t index_;
337 :
338 : uint8_t flags_;
339 :
340 : // The meaning of this field depends on node state:
341 : // - Node in free list: Stores next free node pointer.
342 : // - Otherwise, specific to the node implementation.
343 : union {
344 : Child* next_free;
345 : void* parameter;
346 : } data_;
347 : };
348 :
349 : namespace {
350 :
351 27 : void ExtractInternalFields(JSObject jsobject, void** embedder_fields, int len) {
352 27 : int field_count = jsobject->GetEmbedderFieldCount();
353 76 : for (int i = 0; i < len; ++i) {
354 54 : if (field_count == i) break;
355 : void* pointer;
356 49 : if (EmbedderDataSlot(jsobject, i).ToAlignedPointer(&pointer)) {
357 49 : embedder_fields[i] = pointer;
358 : }
359 : }
360 27 : }
361 :
362 : } // namespace
363 :
364 : class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> {
365 : public:
366 : // State transition diagram:
367 : // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
368 : enum State {
369 : FREE = 0,
370 : NORMAL, // Normal global handle.
371 : WEAK, // Flagged as weak but not yet finalized.
372 : PENDING, // Has been recognized as only reachable by weak handles.
373 : NEAR_DEATH, // Callback has informed the handle is near death.
374 : NUMBER_OF_NODE_STATES
375 : };
376 :
377 : Node() {
378 : STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
379 : Internals::kNodeStateMask);
380 : STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
381 : STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
382 : STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
383 : STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
384 : Internals::kNodeIsIndependentShift);
385 : STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
386 : Internals::kNodeIsActiveShift);
387 : set_in_young_list(false);
388 : }
389 :
390 : void Zap() {
391 : DCHECK(IsInUse());
392 : // Zap the values for eager trapping.
393 : object_ = kGlobalHandleZapValue;
394 : }
395 :
396 26931 : const char* label() const {
397 : return state() == NORMAL ? reinterpret_cast<char*>(data_.parameter)
398 8264629 : : nullptr;
399 : }
400 :
401 : // State and flag accessors.
402 :
403 : State state() const {
404 : return NodeState::decode(flags_);
405 : }
406 : void set_state(State state) {
407 48582993 : flags_ = NodeState::update(flags_, state);
408 : }
409 :
410 : bool is_independent() { return IsIndependent::decode(flags_); }
411 67249902 : void set_independent(bool v) { flags_ = IsIndependent::update(flags_, v); }
412 :
413 : bool is_active() {
414 : return IsActive::decode(flags_);
415 : }
416 : void set_active(bool v) {
417 38241419 : flags_ = IsActive::update(flags_, v);
418 : }
419 :
420 : bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
421 37237928 : void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
422 :
423 : WeaknessType weakness_type() const {
424 : return NodeWeaknessType::decode(flags_);
425 : }
426 : void set_weakness_type(WeaknessType weakness_type) {
427 3435239 : flags_ = NodeWeaknessType::update(flags_, weakness_type);
428 : }
429 :
430 40 : bool IsNearDeath() const {
431 : // Check for PENDING to ensure correct answer when processing callbacks.
432 40 : return state() == PENDING || state() == NEAR_DEATH;
433 : }
434 :
435 24434384 : bool IsWeak() const { return state() == WEAK; }
436 :
437 4446523 : bool IsInUse() const { return state() != FREE; }
438 :
439 7744 : bool IsPhantomCallback() const {
440 2993049 : return weakness_type() == PHANTOM_WEAK ||
441 : weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
442 : }
443 :
444 2985336 : bool IsPhantomResetHandle() const {
445 : return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
446 : }
447 :
448 2977620 : bool IsFinalizerHandle() const { return weakness_type() == FINALIZER_WEAK; }
449 :
450 : bool IsPendingPhantomCallback() const {
451 : return state() == PENDING && IsPhantomCallback();
452 : }
453 :
454 : bool IsPendingPhantomResetHandle() const {
455 : return state() == PENDING && IsPhantomResetHandle();
456 : }
457 :
458 20 : bool IsPendingFinalizer() const {
459 40 : return state() == PENDING && weakness_type() == FINALIZER_WEAK;
460 : }
461 :
462 : bool IsPending() const { return state() == PENDING; }
463 :
464 50655057 : bool IsRetainer() const {
465 50655057 : return state() != FREE &&
466 2977561 : !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
467 : }
468 :
469 36438110 : bool IsStrongRetainer() const { return state() == NORMAL; }
470 :
471 48002048 : bool IsWeakRetainer() const {
472 48600946 : return state() == WEAK || state() == PENDING ||
473 0 : (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
474 : }
475 :
476 : void MarkPending() {
477 : DCHECK(state() == WEAK);
478 : set_state(PENDING);
479 : }
480 :
481 : bool has_callback() const { return weak_callback_ != nullptr; }
482 :
483 : // Accessors for next free node in the free list.
484 6449637 : Node* next_free() {
485 : DCHECK_EQ(FREE, state());
486 6449637 : return data_.next_free;
487 : }
488 :
489 3435203 : void MakeWeak(void* parameter,
490 : WeakCallbackInfo<void>::Callback phantom_callback,
491 : v8::WeakCallbackType type) {
492 : DCHECK_NOT_NULL(phantom_callback);
493 : DCHECK(IsInUse());
494 3435203 : CHECK_NE(object_, kGlobalHandleZapValue);
495 : set_state(WEAK);
496 3435203 : switch (type) {
497 : case v8::WeakCallbackType::kParameter:
498 : set_weakness_type(PHANTOM_WEAK);
499 : break;
500 : case v8::WeakCallbackType::kInternalFields:
501 : set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
502 : break;
503 : case v8::WeakCallbackType::kFinalizer:
504 : set_weakness_type(FINALIZER_WEAK);
505 : break;
506 : }
507 : set_parameter(parameter);
508 3435203 : weak_callback_ = phantom_callback;
509 3435203 : }
510 :
511 36 : void MakeWeak(Address** location_addr) {
512 : DCHECK(IsInUse());
513 36 : CHECK_NE(object_, kGlobalHandleZapValue);
514 : set_state(WEAK);
515 : set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
516 : set_parameter(location_addr);
517 36 : weak_callback_ = nullptr;
518 36 : }
519 :
520 : void* ClearWeakness() {
521 : DCHECK(IsInUse());
522 35 : void* p = parameter();
523 : set_state(NORMAL);
524 : set_parameter(nullptr);
525 : return p;
526 : }
527 :
528 : void AnnotateStrongRetainer(const char* label) {
529 : DCHECK_EQ(state(), NORMAL);
530 2828921 : data_.parameter = const_cast<char*>(label);
531 : }
532 :
533 2985305 : void CollectPhantomCallbackData(
534 : std::vector<std::pair<Node*, PendingPhantomCallback>>*
535 2985305 : pending_phantom_callbacks) {
536 : DCHECK(weakness_type() == PHANTOM_WEAK ||
537 : weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
538 : DCHECK(state() == PENDING);
539 : DCHECK_NOT_NULL(weak_callback_);
540 :
541 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
542 2985305 : nullptr};
543 5970627 : if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
544 : ExtractInternalFields(JSObject::cast(object()), embedder_fields,
545 17 : v8::kEmbedderFieldsInWeakCallback);
546 : }
547 :
548 : // Zap with something dangerous.
549 : location().store(Object(0xCA11));
550 :
551 : pending_phantom_callbacks->push_back(std::make_pair(
552 : this,
553 5970610 : PendingPhantomCallback(weak_callback_, parameter(), embedder_fields)));
554 : DCHECK(IsInUse());
555 : set_state(NEAR_DEATH);
556 2985305 : }
557 :
558 : void ResetPhantomHandle() {
559 : DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type());
560 : DCHECK_EQ(PENDING, state());
561 : DCHECK_NULL(weak_callback_);
562 31 : Address** handle = reinterpret_cast<Address**>(parameter());
563 31 : *handle = nullptr;
564 31 : NodeSpace<Node>::Release(this);
565 : }
566 :
567 40 : void PostGarbageCollectionProcessing(Isolate* isolate) {
568 : // This method invokes a finalizer. Updating the method name would require
569 : // adjusting CFI blacklist as weak_callback_ is invoked on the wrong type.
570 20 : CHECK(IsPendingFinalizer());
571 20 : CHECK(!is_active());
572 : set_state(NEAR_DEATH);
573 : // Check that we are not passing a finalized external string to
574 : // the callback.
575 : DCHECK(!object()->IsExternalOneByteString() ||
576 : ExternalOneByteString::cast(object())->resource() != nullptr);
577 : DCHECK(!object()->IsExternalTwoByteString() ||
578 : ExternalTwoByteString::cast(object())->resource() != nullptr);
579 : // Leaving V8.
580 20 : VMState<EXTERNAL> vmstate(isolate);
581 : HandleScope handle_scope(isolate);
582 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
583 20 : nullptr};
584 : v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
585 20 : parameter(), embedder_fields, nullptr);
586 20 : weak_callback_(data);
587 : // For finalizers the handle must have either been reset or made strong.
588 : // Both cases reset the state.
589 40 : CHECK_NE(NEAR_DEATH, state());
590 20 : }
591 :
592 : void MarkAsFree() { set_state(FREE); }
593 : void MarkAsUsed() { set_state(NORMAL); }
594 :
595 : GlobalHandles* global_handles() {
596 10 : return NodeBlock<Node>::From(this)->global_handles();
597 : }
598 :
599 : private:
600 : // Fields that are not used for managing node memory.
601 : void ClearImplFields() {
602 : set_independent(false);
603 : set_active(false);
604 33624951 : weak_callback_ = nullptr;
605 : }
606 :
607 : void CheckImplFieldsAreCleared() {
608 : DCHECK(!is_independent());
609 : DCHECK(!is_active());
610 : DCHECK_EQ(nullptr, weak_callback_);
611 : }
612 :
613 : // This stores three flags (independent, partially_dependent and
614 : // in_young_list) and a State.
615 : class NodeState : public BitField8<State, 0, 3> {};
616 : class IsIndependent : public BitField8<bool, NodeState::kNext, 1> {};
617 : // The following two fields are mutually exclusive
618 : class IsActive : public BitField8<bool, IsIndependent::kNext, 1> {};
619 : class IsInYoungList : public BitField8<bool, IsActive::kNext, 1> {};
620 : class NodeWeaknessType
621 : : public BitField8<WeaknessType, IsInYoungList::kNext, 2> {};
622 :
623 : // Handle specific callback - might be a weak reference in disguise.
624 : WeakCallbackInfo<void>::Callback weak_callback_;
625 :
626 : friend class NodeBase<Node>;
627 :
628 : DISALLOW_COPY_AND_ASSIGN(Node);
629 : };
630 :
631 : class GlobalHandles::TracedNode final
632 : : public NodeBase<GlobalHandles::TracedNode> {
633 : public:
634 : TracedNode() { set_in_young_list(false); }
635 :
636 : enum State { FREE = 0, NORMAL, NEAR_DEATH };
637 :
638 : State state() const { return NodeState::decode(flags_); }
639 18150 : void set_state(State state) { flags_ = NodeState::update(flags_, state); }
640 :
641 : void MarkAsFree() { set_state(FREE); }
642 : void MarkAsUsed() { set_state(NORMAL); }
643 9091 : bool IsInUse() const { return state() != FREE; }
644 3840 : bool IsRetainer() const { return state() == NORMAL; }
645 : bool IsPhantomResetHandle() const { return callback_ == nullptr; }
646 :
647 : bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
648 36011 : void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
649 :
650 : bool is_root() const { return IsRoot::decode(flags_); }
651 71850 : void set_root(bool v) { flags_ = IsRoot::update(flags_, v); }
652 :
653 : void SetFinalizationCallback(void* parameter,
654 : WeakCallbackInfo<void>::Callback callback) {
655 : set_parameter(parameter);
656 10 : callback_ = callback;
657 : }
658 : bool HasFinalizationCallback() const { return callback_ != nullptr; }
659 :
660 10 : void CollectPhantomCallbackData(
661 : std::vector<std::pair<TracedNode*, PendingPhantomCallback>>*
662 : pending_phantom_callbacks) {
663 : DCHECK(IsInUse());
664 : DCHECK_NOT_NULL(callback_);
665 :
666 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
667 10 : nullptr};
668 : ExtractInternalFields(JSObject::cast(object()), embedder_fields,
669 30 : v8::kEmbedderFieldsInWeakCallback);
670 :
671 : // Zap with something dangerous.
672 : location().store(Object(0xCA11));
673 :
674 : pending_phantom_callbacks->push_back(std::make_pair(
675 20 : this, PendingPhantomCallback(callback_, parameter(), embedder_fields)));
676 : set_state(NEAR_DEATH);
677 10 : }
678 :
679 : void ResetPhantomHandle() {
680 : DCHECK(IsInUse());
681 20 : Address** handle = reinterpret_cast<Address**>(data_.parameter);
682 20 : *handle = nullptr;
683 20 : NodeSpace<TracedNode>::Release(this);
684 : DCHECK(!IsInUse());
685 : }
686 :
687 : protected:
688 : class NodeState : public BitField8<State, 0, 2> {};
689 : class IsInYoungList : public BitField8<bool, NodeState::kNext, 1> {};
690 : class IsRoot : public BitField8<bool, IsInYoungList::kNext, 1> {};
691 :
692 : void ClearImplFields() {
693 : set_root(true);
694 35910 : callback_ = nullptr;
695 : }
696 :
697 : void CheckImplFieldsAreCleared() const {
698 : DCHECK(is_root());
699 : DCHECK_NULL(callback_);
700 : }
701 :
702 : WeakCallbackInfo<void>::Callback callback_;
703 :
704 : friend class NodeBase<GlobalHandles::TracedNode>;
705 :
706 : DISALLOW_COPY_AND_ASSIGN(TracedNode);
707 : };
708 :
709 61049 : GlobalHandles::GlobalHandles(Isolate* isolate)
710 : : isolate_(isolate),
711 : regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)),
712 244196 : traced_nodes_(new NodeSpace<GlobalHandles::TracedNode>(this)) {}
713 :
714 122068 : GlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); }
715 :
716 6449636 : Handle<Object> GlobalHandles::Create(Object value) {
717 6449637 : GlobalHandles::Node* result = regular_nodes_->Acquire(value);
718 9859703 : if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
719 3251467 : young_nodes_.push_back(result);
720 3251467 : result->set_in_young_list(true);
721 : }
722 12899274 : return result->handle();
723 : }
724 :
725 3049145 : Handle<Object> GlobalHandles::Create(Address value) {
726 3049155 : return Create(Object(value));
727 : }
728 :
729 70 : Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot) {
730 70 : GlobalHandles::TracedNode* result = traced_nodes_->Acquire(value);
731 140 : if (ObjectInYoungGeneration(value) && !result->is_in_young_list()) {
732 70 : traced_young_nodes_.push_back(result);
733 70 : result->set_in_young_list(true);
734 : }
735 70 : result->set_parameter(slot);
736 70 : return result->handle();
737 : }
738 :
739 70 : Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot) {
740 70 : return CreateTraced(Object(value), slot);
741 : }
742 :
743 10 : Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
744 : DCHECK_NOT_NULL(location);
745 : GlobalHandles* global_handles =
746 : Node::FromLocation(location)->global_handles();
747 : #ifdef VERIFY_HEAP
748 : if (i::FLAG_verify_heap) {
749 : Object(*location)->ObjectVerify(global_handles->isolate());
750 : }
751 : #endif // VERIFY_HEAP
752 20 : return global_handles->Create(*location);
753 : }
754 :
755 5706 : void GlobalHandles::MoveGlobal(Address** from, Address** to) {
756 : DCHECK_NOT_NULL(*from);
757 : DCHECK_NOT_NULL(*to);
758 : DCHECK_EQ(*from, *to);
759 5706 : Node* node = Node::FromLocation(*from);
760 5711 : if (node->IsWeak() && node->IsPhantomResetHandle()) {
761 : node->set_parameter(to);
762 : }
763 :
764 : // - Strong handles do not require fixups.
765 : // - Weak handles with finalizers and callbacks are too general to fix up. For
766 : // those the callers need to ensure consistency.
767 5706 : }
768 :
769 55 : void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
770 : DCHECK_NOT_NULL(*from);
771 : DCHECK_NOT_NULL(*to);
772 : DCHECK_EQ(*from, *to);
773 55 : TracedNode* node = TracedNode::FromLocation(*from);
774 : // Only set the backpointer for clearing a phantom handle when there is no
775 : // finalization callback attached. As soon as a callback is attached to a node
776 : // the embedder is on its own when resetting a handle.
777 55 : if (!node->HasFinalizationCallback()) {
778 : node->set_parameter(to);
779 : }
780 55 : }
781 :
782 6089218 : void GlobalHandles::Destroy(Address* location) {
783 6089218 : if (location != nullptr) {
784 6089218 : NodeSpace<Node>::Release(Node::FromLocation(location));
785 : }
786 6089218 : }
787 :
788 50 : void GlobalHandles::DestroyTraced(Address* location) {
789 50 : if (location != nullptr) {
790 50 : NodeSpace<TracedNode>::Release(TracedNode::FromLocation(location));
791 : }
792 50 : }
793 :
794 10 : void GlobalHandles::SetFinalizationCallbackForTraced(
795 : Address* location, void* parameter,
796 : WeakCallbackInfo<void>::Callback callback) {
797 : TracedNode::FromLocation(location)->SetFinalizationCallback(parameter,
798 : callback);
799 10 : }
800 :
801 : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
802 :
803 3435203 : void GlobalHandles::MakeWeak(Address* location, void* parameter,
804 : GenericCallback phantom_callback,
805 : v8::WeakCallbackType type) {
806 3435203 : Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
807 3435203 : }
808 :
809 36 : void GlobalHandles::MakeWeak(Address** location_addr) {
810 36 : Node::FromLocation(*location_addr)->MakeWeak(location_addr);
811 36 : }
812 :
813 35 : void* GlobalHandles::ClearWeakness(Address* location) {
814 35 : return Node::FromLocation(location)->ClearWeakness();
815 : }
816 :
817 2828921 : void GlobalHandles::AnnotateStrongRetainer(Address* location,
818 : const char* label) {
819 : Node::FromLocation(location)->AnnotateStrongRetainer(label);
820 2828921 : }
821 :
822 40 : bool GlobalHandles::IsNearDeath(Address* location) {
823 40 : return Node::FromLocation(location)->IsNearDeath();
824 : }
825 :
826 20 : bool GlobalHandles::IsWeak(Address* location) {
827 20 : return Node::FromLocation(location)->IsWeak();
828 : }
829 :
830 : DISABLE_CFI_PERF
831 74510 : void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
832 24150044 : for (Node* node : *regular_nodes_) {
833 24001024 : if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
834 : DCHECK(!node->IsPhantomCallback());
835 : DCHECK(!node->IsPhantomResetHandle());
836 : // Finalizers need to survive.
837 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
838 40 : node->location());
839 : }
840 : }
841 74510 : }
842 :
843 : DISABLE_CFI_PERF
844 74510 : void GlobalHandles::IterateWeakRootsForPhantomHandles(
845 5164052 : WeakSlotCallbackWithHeap should_reset_handle) {
846 24150044 : for (Node* node : *regular_nodes_) {
847 29165046 : if (node->IsWeakRetainer() &&
848 5164022 : should_reset_handle(isolate()->heap(), node->location())) {
849 2977592 : if (node->IsPhantomResetHandle()) {
850 : node->MarkPending();
851 : node->ResetPhantomHandle();
852 31 : ++number_of_phantom_handle_resets_;
853 2977561 : } else if (node->IsPhantomCallback()) {
854 : node->MarkPending();
855 2977561 : node->CollectPhantomCallbackData(®ular_pending_phantom_callbacks_);
856 : }
857 : }
858 : }
859 156720 : for (TracedNode* node : *traced_nodes_) {
860 7710 : if (node->IsInUse() &&
861 30 : should_reset_handle(isolate()->heap(), node->location())) {
862 20 : if (node->IsPhantomResetHandle()) {
863 : node->ResetPhantomHandle();
864 15 : ++number_of_phantom_handle_resets_;
865 : } else {
866 5 : node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
867 : }
868 : }
869 : }
870 74510 : }
871 :
872 74510 : void GlobalHandles::IterateWeakRootsIdentifyFinalizers(
873 5164022 : WeakSlotCallbackWithHeap should_reset_handle) {
874 24150044 : for (Node* node : *regular_nodes_) {
875 29165046 : if (node->IsWeak() &&
876 5164022 : should_reset_handle(isolate()->heap(), node->location())) {
877 2977620 : if (node->IsFinalizerHandle()) {
878 : node->MarkPending();
879 : }
880 : }
881 : }
882 74510 : }
883 :
884 23490 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
885 23490 : WeakSlotCallback is_unmodified) {
886 372706 : for (Node* node : young_nodes_) {
887 464026 : if (node->IsWeak() && !is_unmodified(node->location())) {
888 : node->set_active(true);
889 : }
890 : }
891 :
892 : LocalEmbedderHeapTracer* const tracer =
893 : isolate()->heap()->local_embedder_heap_tracer();
894 47005 : for (TracedNode* node : traced_young_nodes_) {
895 25 : if (node->IsInUse()) {
896 : DCHECK(node->is_root());
897 25 : if (is_unmodified(node->location())) {
898 15 : v8::Value* value = ToApi<v8::Value>(node->handle());
899 : node->set_root(tracer->IsRootForNonTracingGC(
900 : *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value)));
901 : }
902 : }
903 : }
904 23490 : }
905 :
906 23490 : void GlobalHandles::IterateYoungStrongAndDependentRoots(RootVisitor* v) {
907 372706 : for (Node* node : young_nodes_) {
908 806148 : if (node->IsStrongRetainer() ||
909 241961 : (node->IsWeakRetainer() && !node->is_independent() &&
910 : node->is_active())) {
911 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
912 549310 : node->location());
913 : }
914 : }
915 47005 : for (TracedNode* node : traced_young_nodes_) {
916 50 : if (node->IsInUse() && node->is_root()) {
917 30 : v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
918 : }
919 : }
920 23490 : }
921 :
922 23490 : void GlobalHandles::MarkYoungWeakUnmodifiedObjectsPending(
923 : WeakSlotCallbackWithHeap is_dead) {
924 372706 : for (Node* node : young_nodes_) {
925 : DCHECK(node->is_in_young_list());
926 873589 : if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
927 34675 : is_dead(isolate_->heap(), node->location())) {
928 7744 : if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
929 : node->MarkPending();
930 : }
931 : }
932 : }
933 23490 : }
934 :
935 23490 : void GlobalHandles::IterateYoungWeakUnmodifiedRootsForFinalizers(
936 : RootVisitor* v) {
937 372706 : for (Node* node : young_nodes_) {
938 : DCHECK(node->is_in_young_list());
939 838914 : if ((node->is_independent() || !node->is_active()) &&
940 360401 : node->IsWeakRetainer() && (node->state() == Node::PENDING)) {
941 : DCHECK(!node->IsPhantomCallback());
942 : DCHECK(!node->IsPhantomResetHandle());
943 : // Finalizers need to survive.
944 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
945 0 : node->location());
946 : }
947 : }
948 23490 : }
949 :
950 23490 : void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles(
951 : RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) {
952 372706 : for (Node* node : young_nodes_) {
953 : DCHECK(node->is_in_young_list());
954 838914 : if ((node->is_independent() || !node->is_active()) &&
955 360401 : node->IsWeakRetainer() && (node->state() != Node::PENDING)) {
956 34675 : if (should_reset_handle(isolate_->heap(), node->location())) {
957 : DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
958 7744 : if (node->IsPhantomResetHandle()) {
959 : node->MarkPending();
960 : node->ResetPhantomHandle();
961 0 : ++number_of_phantom_handle_resets_;
962 7744 : } else if (node->IsPhantomCallback()) {
963 : node->MarkPending();
964 7744 : node->CollectPhantomCallbackData(®ular_pending_phantom_callbacks_);
965 : } else {
966 0 : UNREACHABLE();
967 : }
968 : } else {
969 : // Node survived and needs to be visited.
970 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
971 53862 : node->location());
972 : }
973 : }
974 : }
975 47030 : for (TracedNode* node : traced_young_nodes_) {
976 25 : if (!node->IsInUse()) continue;
977 :
978 : DCHECK_IMPLIES(node->is_root(),
979 : !should_reset_handle(isolate_->heap(), node->location()));
980 25 : if (should_reset_handle(isolate_->heap(), node->location())) {
981 10 : if (node->IsPhantomResetHandle()) {
982 : node->ResetPhantomHandle();
983 5 : ++number_of_phantom_handle_resets_;
984 : } else {
985 5 : node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
986 : }
987 : } else {
988 15 : if (!node->is_root()) {
989 : node->set_root(true);
990 0 : v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
991 : }
992 : }
993 : }
994 23490 : }
995 :
996 1998 : void GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() {
997 : DCHECK(second_pass_callbacks_task_posted_);
998 666 : second_pass_callbacks_task_posted_ = false;
999 1332 : TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
1000 : isolate()->heap()->CallGCPrologueCallbacks(
1001 666 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
1002 666 : InvokeSecondPassPhantomCallbacks();
1003 : isolate()->heap()->CallGCEpilogueCallbacks(
1004 666 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
1005 666 : }
1006 :
1007 2734013 : void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
1008 2840814 : while (!second_pass_callbacks_.empty()) {
1009 2627212 : auto callback = second_pass_callbacks_.back();
1010 : second_pass_callbacks_.pop_back();
1011 2627212 : callback.Invoke(isolate(), PendingPhantomCallback::kSecondPass);
1012 : }
1013 106801 : }
1014 :
1015 23490 : size_t GlobalHandles::PostScavengeProcessing(unsigned post_processing_count) {
1016 : size_t freed_nodes = 0;
1017 372706 : for (Node* node : young_nodes_) {
1018 : // Filter free nodes.
1019 325726 : if (!node->IsRetainer()) continue;
1020 :
1021 : // Reset active state for all affected nodes.
1022 : node->set_active(false);
1023 :
1024 301586 : if (node->IsPending()) {
1025 : DCHECK(node->has_callback());
1026 : DCHECK(node->IsPendingFinalizer());
1027 0 : node->PostGarbageCollectionProcessing(isolate_);
1028 : }
1029 301586 : if (InRecursiveGC(post_processing_count)) return freed_nodes;
1030 :
1031 301586 : if (!node->IsRetainer()) freed_nodes++;
1032 : }
1033 : return freed_nodes;
1034 : }
1035 :
1036 74510 : size_t GlobalHandles::PostMarkSweepProcessing(unsigned post_processing_count) {
1037 : size_t freed_nodes = 0;
1038 21697820 : for (Node* node : *regular_nodes_) {
1039 : // Filter free nodes.
1040 21548800 : if (!node->IsRetainer()) continue;
1041 :
1042 : // Reset active state for all affected nodes.
1043 : node->set_active(false);
1044 :
1045 4038364 : if (node->IsPending()) {
1046 : DCHECK(node->has_callback());
1047 : DCHECK(node->IsPendingFinalizer());
1048 20 : node->PostGarbageCollectionProcessing(isolate_);
1049 : }
1050 4038364 : if (InRecursiveGC(post_processing_count)) return freed_nodes;
1051 :
1052 4038364 : if (!node->IsRetainer()) freed_nodes++;
1053 : }
1054 74510 : return freed_nodes;
1055 : }
1056 :
1057 : template <typename T>
1058 196000 : void GlobalHandles::UpdateAndCompactListOfYoungNode(
1059 1557350 : std::vector<T*>* node_list) {
1060 : size_t last = 0;
1061 4838579 : for (T* node : *node_list) {
1062 : DCHECK(node->is_in_young_list());
1063 4446579 : if (node->IsInUse()) {
1064 1867274 : if (ObjectInYoungGeneration(node->object())) {
1065 3114700 : (*node_list)[last++] = node;
1066 1557350 : isolate_->heap()->IncrementNodesCopiedInNewSpace();
1067 : } else {
1068 : node->set_in_young_list(false);
1069 309924 : isolate_->heap()->IncrementNodesPromoted();
1070 : }
1071 : } else {
1072 : node->set_in_young_list(false);
1073 2579305 : isolate_->heap()->IncrementNodesDiedInNewSpace();
1074 : }
1075 : }
1076 : DCHECK_LE(last, node_list->size());
1077 196000 : node_list->resize(last);
1078 : node_list->shrink_to_fit();
1079 196000 : }
1080 :
1081 98000 : void GlobalHandles::UpdateListOfYoungNodes() {
1082 98000 : UpdateAndCompactListOfYoungNode(&young_nodes_);
1083 98000 : UpdateAndCompactListOfYoungNode(&traced_young_nodes_);
1084 98000 : }
1085 :
1086 : template <typename T>
1087 196000 : size_t GlobalHandles::InvokeFirstPassWeakCallbacks(
1088 2985315 : std::vector<std::pair<T*, PendingPhantomCallback>>* pending) {
1089 : size_t freed_nodes = 0;
1090 : std::vector<std::pair<T*, PendingPhantomCallback>> pending_phantom_callbacks;
1091 : pending_phantom_callbacks.swap(*pending);
1092 : {
1093 : // The initial pass callbacks must simply clear the nodes.
1094 3377315 : for (auto& pair : pending_phantom_callbacks) {
1095 5970630 : T* node = pair.first;
1096 : DCHECK_EQ(T::NEAR_DEATH, node->state());
1097 5970630 : pair.second.Invoke(isolate(), PendingPhantomCallback::kFirstPass);
1098 :
1099 : // Transition to second pass. It is required that the first pass callback
1100 : // resets the handle using |v8::PersistentBase::Reset|. Also see comments
1101 : // on |v8::WeakCallbackInfo|.
1102 2985315 : CHECK_WITH_MSG(T::FREE == node->state(),
1103 : "Handle not reset in first callback. See comments on "
1104 : "|v8::WeakCallbackInfo|.");
1105 :
1106 2985315 : if (pair.second.callback()) second_pass_callbacks_.push_back(pair.second);
1107 2985315 : freed_nodes++;
1108 : }
1109 : }
1110 196000 : return freed_nodes;
1111 : }
1112 :
1113 98000 : size_t GlobalHandles::InvokeFirstPassWeakCallbacks() {
1114 98000 : return InvokeFirstPassWeakCallbacks(®ular_pending_phantom_callbacks_) +
1115 98000 : InvokeFirstPassWeakCallbacks(&traced_pending_phantom_callbacks_);
1116 : }
1117 :
1118 98000 : void GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks(
1119 17602 : bool synchronous_second_pass) {
1120 98000 : if (!second_pass_callbacks_.empty()) {
1121 9076 : if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
1122 : isolate()->heap()->CallGCPrologueCallbacks(
1123 8135 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
1124 8135 : InvokeSecondPassPhantomCallbacks();
1125 : isolate()->heap()->CallGCEpilogueCallbacks(
1126 8135 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
1127 941 : } else if (!second_pass_callbacks_task_posted_) {
1128 666 : second_pass_callbacks_task_posted_ = true;
1129 666 : auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
1130 1332 : reinterpret_cast<v8::Isolate*>(isolate()));
1131 666 : taskrunner->PostTask(MakeCancelableTask(
1132 4662 : isolate(), [this] { InvokeSecondPassPhantomCallbacksFromTask(); }));
1133 : }
1134 : }
1135 98000 : }
1136 :
1137 5612527 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate,
1138 : InvocationType type) {
1139 : Data::Callback* callback_addr = nullptr;
1140 5612527 : if (type == kFirstPass) {
1141 2985315 : callback_addr = &callback_;
1142 : }
1143 : Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
1144 5612527 : embedder_fields_, callback_addr);
1145 5612527 : Data::Callback callback = callback_;
1146 5612527 : callback_ = nullptr;
1147 5612527 : callback(data);
1148 5612527 : }
1149 :
1150 0 : bool GlobalHandles::InRecursiveGC(unsigned gc_processing_counter) {
1151 4535950 : return gc_processing_counter != post_gc_processing_count_;
1152 : }
1153 :
1154 98000 : size_t GlobalHandles::PostGarbageCollectionProcessing(
1155 : GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
1156 : // Process weak global handle callbacks. This must be done after the
1157 : // GC is completely done, because the callbacks may invoke arbitrary
1158 : // API functions.
1159 : DCHECK_EQ(Heap::NOT_IN_GC, isolate_->heap()->gc_state());
1160 98000 : const unsigned post_processing_count = ++post_gc_processing_count_;
1161 : size_t freed_nodes = 0;
1162 : bool synchronous_second_pass =
1163 196000 : isolate_->heap()->IsTearingDown() ||
1164 98000 : (gc_callback_flags &
1165 : (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
1166 : kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
1167 98000 : InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
1168 98000 : if (InRecursiveGC(post_processing_count)) return freed_nodes;
1169 :
1170 : freed_nodes += Heap::IsYoungGenerationCollector(collector)
1171 : ? PostScavengeProcessing(post_processing_count)
1172 98000 : : PostMarkSweepProcessing(post_processing_count);
1173 98000 : if (InRecursiveGC(post_processing_count)) return freed_nodes;
1174 :
1175 98000 : UpdateListOfYoungNodes();
1176 98000 : return freed_nodes;
1177 : }
1178 :
1179 120298 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
1180 36352980 : for (Node* node : *regular_nodes_) {
1181 36112384 : if (node->IsStrongRetainer()) {
1182 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1183 7756298 : node->location());
1184 : }
1185 : }
1186 120298 : }
1187 :
1188 398 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
1189 102684 : for (Node* node : *regular_nodes_) {
1190 101888 : if (node->IsWeak()) {
1191 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1192 60 : node->location());
1193 : }
1194 : }
1195 796 : for (TracedNode* node : *traced_nodes_) {
1196 0 : if (node->IsInUse()) {
1197 0 : v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
1198 : }
1199 : }
1200 398 : }
1201 :
1202 : DISABLE_CFI_PERF
1203 76389 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
1204 24590794 : for (Node* node : *regular_nodes_) {
1205 24438016 : if (node->IsRetainer()) {
1206 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1207 8169688 : node->location());
1208 : }
1209 : }
1210 156618 : for (TracedNode* node : *traced_nodes_) {
1211 3840 : if (node->IsRetainer()) {
1212 20 : v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
1213 : }
1214 : }
1215 76389 : }
1216 :
1217 : DISABLE_CFI_PERF
1218 0 : void GlobalHandles::IterateAllYoungRoots(RootVisitor* v) {
1219 0 : for (Node* node : young_nodes_) {
1220 0 : if (node->IsRetainer()) {
1221 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1222 0 : node->location());
1223 : }
1224 : }
1225 0 : for (TracedNode* node : traced_young_nodes_) {
1226 0 : if (node->IsRetainer()) {
1227 0 : v->VisitRootPointer(Root::kGlobalHandles, nullptr, node->location());
1228 : }
1229 : }
1230 0 : }
1231 :
1232 : DISABLE_CFI_PERF
1233 0 : void GlobalHandles::ApplyPersistentHandleVisitor(
1234 : v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
1235 50 : v8::Value* value = ToApi<v8::Value>(node->handle());
1236 : visitor->VisitPersistentHandle(
1237 : reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
1238 50 : node->wrapper_class_id());
1239 0 : }
1240 :
1241 : DISABLE_CFI_PERF
1242 10 : void GlobalHandles::IterateAllRootsWithClassIds(
1243 : v8::PersistentHandleVisitor* visitor) {
1244 2580 : for (Node* node : *regular_nodes_) {
1245 2560 : if (node->IsRetainer() && node->has_wrapper_class_id()) {
1246 : ApplyPersistentHandleVisitor(visitor, node);
1247 : }
1248 : }
1249 10 : }
1250 :
1251 : DISABLE_CFI_PERF
1252 5 : void GlobalHandles::IterateTracedNodes(
1253 : v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor) {
1254 1290 : for (TracedNode* node : *traced_nodes_) {
1255 1280 : if (node->IsInUse()) {
1256 5 : v8::Value* value = ToApi<v8::Value>(node->handle());
1257 : visitor->VisitTracedGlobalHandle(
1258 5 : *reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value));
1259 : }
1260 : }
1261 5 : }
1262 :
1263 : DISABLE_CFI_PERF
1264 5 : void GlobalHandles::IterateAllYoungRootsWithClassIds(
1265 : v8::PersistentHandleVisitor* visitor) {
1266 15 : for (Node* node : young_nodes_) {
1267 5 : if (node->IsRetainer() && node->has_wrapper_class_id()) {
1268 : ApplyPersistentHandleVisitor(visitor, node);
1269 : }
1270 : }
1271 5 : }
1272 :
1273 : DISABLE_CFI_PERF
1274 0 : void GlobalHandles::IterateYoungWeakRootsWithClassIds(
1275 : v8::PersistentHandleVisitor* visitor) {
1276 0 : for (Node* node : young_nodes_) {
1277 0 : if (node->has_wrapper_class_id() && node->IsWeak()) {
1278 : ApplyPersistentHandleVisitor(visitor, node);
1279 : }
1280 : }
1281 0 : }
1282 :
1283 15 : void GlobalHandles::RecordStats(HeapStats* stats) {
1284 15 : *stats->global_handle_count = 0;
1285 15 : *stats->weak_global_handle_count = 0;
1286 15 : *stats->pending_global_handle_count = 0;
1287 15 : *stats->near_death_global_handle_count = 0;
1288 15 : *stats->free_global_handle_count = 0;
1289 30 : for (Node* node : *regular_nodes_) {
1290 0 : *stats->global_handle_count += 1;
1291 0 : if (node->state() == Node::WEAK) {
1292 0 : *stats->weak_global_handle_count += 1;
1293 0 : } else if (node->state() == Node::PENDING) {
1294 0 : *stats->pending_global_handle_count += 1;
1295 0 : } else if (node->state() == Node::NEAR_DEATH) {
1296 0 : *stats->near_death_global_handle_count += 1;
1297 0 : } else if (node->state() == Node::FREE) {
1298 0 : *stats->free_global_handle_count += 1;
1299 : }
1300 : }
1301 15 : }
1302 :
1303 : #ifdef DEBUG
1304 :
1305 : void GlobalHandles::PrintStats() {
1306 : int total = 0;
1307 : int weak = 0;
1308 : int pending = 0;
1309 : int near_death = 0;
1310 : int destroyed = 0;
1311 :
1312 : for (Node* node : *regular_nodes_) {
1313 : total++;
1314 : if (node->state() == Node::WEAK) weak++;
1315 : if (node->state() == Node::PENDING) pending++;
1316 : if (node->state() == Node::NEAR_DEATH) near_death++;
1317 : if (node->state() == Node::FREE) destroyed++;
1318 : }
1319 :
1320 : PrintF("Global Handle Statistics:\n");
1321 : PrintF(" allocated memory = %" PRIuS "B\n", total * sizeof(Node));
1322 : PrintF(" # weak = %d\n", weak);
1323 : PrintF(" # pending = %d\n", pending);
1324 : PrintF(" # near_death = %d\n", near_death);
1325 : PrintF(" # free = %d\n", destroyed);
1326 : PrintF(" # total = %d\n", total);
1327 : }
1328 :
1329 :
1330 : void GlobalHandles::Print() {
1331 : PrintF("Global handles:\n");
1332 : for (Node* node : *regular_nodes_) {
1333 : PrintF(" handle %p to %p%s\n", node->location().ToVoidPtr(),
1334 : reinterpret_cast<void*>(node->object()->ptr()),
1335 : node->IsWeak() ? " (weak)" : "");
1336 : }
1337 : }
1338 :
1339 : #endif
1340 :
1341 61034 : EternalHandles::~EternalHandles() {
1342 122153 : for (Address* block : blocks_) delete[] block;
1343 61034 : }
1344 :
1345 196289 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
1346 196289 : int limit = size_;
1347 392955 : for (Address* block : blocks_) {
1348 : DCHECK_GT(limit, 0);
1349 : visitor->VisitRootPointers(Root::kEternalHandles, nullptr,
1350 : FullObjectSlot(block),
1351 1131 : FullObjectSlot(block + Min(limit, kSize)));
1352 377 : limit -= kSize;
1353 : }
1354 196289 : }
1355 :
1356 23490 : void EternalHandles::IterateYoungRoots(RootVisitor* visitor) {
1357 62028 : for (int index : young_node_indices_) {
1358 : visitor->VisitRootPointer(Root::kEternalHandles, nullptr,
1359 30096 : FullObjectSlot(GetLocation(index)));
1360 : }
1361 23490 : }
1362 :
1363 98000 : void EternalHandles::PostGarbageCollectionProcessing() {
1364 : size_t last = 0;
1365 236890 : for (int index : young_node_indices_) {
1366 81780 : if (ObjectInYoungGeneration(Object(*GetLocation(index)))) {
1367 40840 : young_node_indices_[last++] = index;
1368 : }
1369 : }
1370 : DCHECK_LE(last, young_node_indices_.size());
1371 98000 : young_node_indices_.resize(last);
1372 98000 : }
1373 :
1374 20480 : void EternalHandles::Create(Isolate* isolate, Object object, int* index) {
1375 : DCHECK_EQ(kInvalidIndex, *index);
1376 40960 : if (object == Object()) return;
1377 : Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
1378 : DCHECK_NE(the_hole, object);
1379 20480 : int block = size_ >> kShift;
1380 20480 : int offset = size_ & kMask;
1381 : // Need to resize.
1382 20480 : if (offset == 0) {
1383 85 : Address* next_block = new Address[kSize];
1384 : MemsetPointer(FullObjectSlot(next_block), the_hole, kSize);
1385 20565 : blocks_.push_back(next_block);
1386 : }
1387 : DCHECK_EQ(the_hole->ptr(), blocks_[block][offset]);
1388 40960 : blocks_[block][offset] = object->ptr();
1389 20480 : if (ObjectInYoungGeneration(object)) {
1390 20475 : young_node_indices_.push_back(size_);
1391 : }
1392 20480 : *index = size_++;
1393 : }
1394 :
1395 : } // namespace internal
1396 178779 : } // namespace v8
|