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/objects-inl.h"
11 : #include "src/objects/slots.h"
12 : #include "src/task-utils.h"
13 : #include "src/v8.h"
14 : #include "src/visitors.h"
15 : #include "src/vm-state-inl.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : namespace {
21 :
22 : constexpr size_t kBlockSize = 256;
23 :
24 : } // namespace
25 :
26 : template <class _NodeType>
27 111424 : class GlobalHandles::NodeBlock final {
28 : public:
29 : using BlockType = NodeBlock<_NodeType>;
30 : using NodeType = _NodeType;
31 :
32 : V8_INLINE static NodeBlock* From(NodeType* node);
33 :
34 55713 : NodeBlock(GlobalHandles* global_handles,
35 : GlobalHandles::NodeSpace<NodeType>* space,
36 : NodeBlock* next) V8_NOEXCEPT : next_(next),
37 : global_handles_(global_handles),
38 14318241 : space_(space) {}
39 :
40 : NodeType* at(size_t index) { return &nodes_[index]; }
41 : const NodeType* at(size_t index) const { return &nodes_[index]; }
42 : GlobalHandles::NodeSpace<NodeType>* space() const { return space_; }
43 : GlobalHandles* global_handles() const { return global_handles_; }
44 :
45 : V8_INLINE bool IncreaseUsage();
46 : V8_INLINE bool DecreaseUsage();
47 :
48 : V8_INLINE void ListAdd(NodeBlock** top);
49 : V8_INLINE void ListRemove(NodeBlock** top);
50 :
51 : NodeBlock* next() const { return next_; }
52 : NodeBlock* next_used() const { return next_used_; }
53 :
54 : private:
55 : NodeType nodes_[kBlockSize];
56 : NodeBlock* const next_;
57 : GlobalHandles* const global_handles_;
58 : GlobalHandles::NodeSpace<NodeType>* const space_;
59 : NodeBlock* next_used_ = nullptr;
60 : NodeBlock* prev_used_ = nullptr;
61 : uint32_t used_nodes_ = 0;
62 :
63 : DISALLOW_COPY_AND_ASSIGN(NodeBlock);
64 : };
65 :
66 : template <class NodeType>
67 : GlobalHandles::NodeBlock<NodeType>* GlobalHandles::NodeBlock<NodeType>::From(
68 20720765 : NodeType* node) {
69 : uintptr_t ptr =
70 34676921 : reinterpret_cast<uintptr_t>(node) - sizeof(NodeType) * node->index();
71 20720765 : BlockType* block = reinterpret_cast<BlockType*>(ptr);
72 : DCHECK_EQ(node, block->at(node->index()));
73 : return block;
74 : }
75 :
76 : template <class NodeType>
77 : bool GlobalHandles::NodeBlock<NodeType>::IncreaseUsage() {
78 : DCHECK_LT(used_nodes_, kBlockSize);
79 7191537 : return used_nodes_++ == 0;
80 : }
81 :
82 : template <class NodeType>
83 : void GlobalHandles::NodeBlock<NodeType>::ListAdd(BlockType** top) {
84 88260 : BlockType* old_top = *top;
85 88260 : *top = this;
86 88260 : next_used_ = old_top;
87 88260 : prev_used_ = nullptr;
88 88260 : if (old_top != nullptr) {
89 14900 : old_top->prev_used_ = this;
90 : }
91 : }
92 :
93 : template <class NodeType>
94 : bool GlobalHandles::NodeBlock<NodeType>::DecreaseUsage() {
95 : DCHECK_GT(used_nodes_, 0);
96 6764609 : return --used_nodes_ == 0;
97 : }
98 :
99 : template <class NodeType>
100 : void GlobalHandles::NodeBlock<NodeType>::ListRemove(BlockType** top) {
101 73552 : if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
102 73552 : if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
103 73552 : if (this == *top) {
104 69860 : *top = next_used_;
105 : }
106 : }
107 :
108 : template <class BlockType>
109 : class GlobalHandles::NodeIterator final {
110 : public:
111 : using NodeType = typename BlockType::NodeType;
112 :
113 : // Iterator traits.
114 : using iterator_category = std::forward_iterator_tag;
115 : using difference_type = std::ptrdiff_t;
116 : using value_type = NodeType*;
117 : using reference = value_type;
118 : using pointer = value_type*;
119 :
120 : explicit NodeIterator(BlockType* block) V8_NOEXCEPT : block_(block) {}
121 : NodeIterator(NodeIterator&& other) V8_NOEXCEPT : block_(other.block_),
122 : index_(other.index_) {}
123 :
124 : bool operator==(const NodeIterator& other) const {
125 : return block_ == other.block_;
126 : }
127 : bool operator!=(const NodeIterator& other) const {
128 : return block_ != other.block_;
129 : }
130 :
131 : NodeIterator& operator++() {
132 172731136 : if (++index_ < kBlockSize) return *this;
133 : index_ = 0;
134 674731 : block_ = block_->next_used();
135 : return *this;
136 : }
137 :
138 : NodeType* operator*() { return block_->at(index_); }
139 : NodeType* operator->() { return block_->at(index_); }
140 :
141 : private:
142 : BlockType* block_ = nullptr;
143 : size_t index_ = 0;
144 :
145 : DISALLOW_COPY_AND_ASSIGN(NodeIterator);
146 : };
147 :
148 : template <class NodeType>
149 : class GlobalHandles::NodeSpace final {
150 : public:
151 : using BlockType = NodeBlock<NodeType>;
152 : using iterator = NodeIterator<BlockType>;
153 :
154 : static NodeSpace* From(NodeType* node);
155 : static void Release(NodeType* node);
156 :
157 : explicit NodeSpace(GlobalHandles* global_handles) V8_NOEXCEPT
158 62883 : : global_handles_(global_handles) {}
159 : ~NodeSpace();
160 :
161 : V8_INLINE NodeType* Acquire(Object object);
162 :
163 : iterator begin() { return iterator(first_used_block_); }
164 : iterator end() { return iterator(nullptr); }
165 :
166 : private:
167 : void PutNodesOnFreeList(BlockType* block);
168 : V8_INLINE void Free(NodeType* node);
169 :
170 : GlobalHandles* const global_handles_;
171 : BlockType* first_block_ = nullptr;
172 : BlockType* first_used_block_ = nullptr;
173 : NodeType* first_free_ = nullptr;
174 : };
175 :
176 : template <class NodeType>
177 62867 : GlobalHandles::NodeSpace<NodeType>::~NodeSpace() {
178 118579 : auto* block = first_block_;
179 181447 : while (block != nullptr) {
180 : auto* tmp = block->next();
181 55712 : delete block;
182 : block = tmp;
183 : }
184 62868 : }
185 :
186 : template <class NodeType>
187 : NodeType* GlobalHandles::NodeSpace<NodeType>::Acquire(Object object) {
188 14383066 : if (first_free_ == nullptr) {
189 7247250 : first_block_ = new BlockType(global_handles_, this, first_block_);
190 55713 : PutNodesOnFreeList(first_block_);
191 : }
192 : DCHECK_NOT_NULL(first_free_);
193 7191533 : NodeType* node = first_free_;
194 7191533 : first_free_ = first_free_->next_free();
195 7191537 : node->Acquire(object);
196 : BlockType* block = BlockType::From(node);
197 7191537 : if (block->IncreaseUsage()) {
198 : block->ListAdd(&first_used_block_);
199 : }
200 14383074 : global_handles_->isolate()->counters()->global_handles()->Increment();
201 7191537 : global_handles_->number_of_global_handles_++;
202 : DCHECK(node->IsInUse());
203 : return node;
204 : }
205 :
206 : template <class NodeType>
207 55713 : void GlobalHandles::NodeSpace<NodeType>::PutNodesOnFreeList(BlockType* block) {
208 14262528 : for (int32_t i = kBlockSize - 1; i >= 0; --i) {
209 14262528 : NodeType* node = block->at(i);
210 : const uint8_t index = static_cast<uint8_t>(i);
211 : DCHECK_EQ(i, index);
212 14262528 : node->set_index(index);
213 14262528 : node->Free(first_free_);
214 14262528 : first_free_ = node;
215 : }
216 55713 : }
217 :
218 : template <class NodeType>
219 6764609 : void GlobalHandles::NodeSpace<NodeType>::Release(NodeType* node) {
220 6764609 : BlockType* block = BlockType::From(node);
221 : block->space()->Free(node);
222 6764609 : }
223 :
224 : template <class NodeType>
225 : void GlobalHandles::NodeSpace<NodeType>::Free(NodeType* node) {
226 6764609 : node->Release(first_free_);
227 6764609 : first_free_ = node;
228 : BlockType* block = BlockType::From(node);
229 6764609 : if (block->DecreaseUsage()) {
230 : block->ListRemove(&first_used_block_);
231 : }
232 6764609 : global_handles_->isolate()->counters()->global_handles()->Decrement();
233 6764609 : global_handles_->number_of_global_handles_--;
234 : }
235 :
236 : class GlobalHandles::Node final {
237 : public:
238 : // State transition diagram:
239 : // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
240 : enum State {
241 : FREE = 0,
242 : NORMAL, // Normal global handle.
243 : WEAK, // Flagged as weak but not yet finalized.
244 : PENDING, // Has been recognized as only reachable by weak handles.
245 : NEAR_DEATH, // Callback has informed the handle is near death.
246 : NUMBER_OF_NODE_STATES
247 : };
248 :
249 : // Maps handle location (slot) to the containing node.
250 : static Node* FromLocation(Address* location) {
251 : DCHECK_EQ(offsetof(Node, object_), 0);
252 : return reinterpret_cast<Node*>(location);
253 : }
254 :
255 : Node() {
256 : DCHECK_EQ(offsetof(Node, class_id_), Internals::kNodeClassIdOffset);
257 : DCHECK_EQ(offsetof(Node, flags_), Internals::kNodeFlagsOffset);
258 : STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
259 : Internals::kNodeStateMask);
260 : STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
261 : STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
262 : STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
263 : STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
264 : Internals::kNodeIsIndependentShift);
265 : STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
266 : Internals::kNodeIsActiveShift);
267 : set_in_new_space_list(false);
268 : }
269 :
270 : #ifdef ENABLE_HANDLE_ZAPPING
271 : ~Node() {
272 : ClearFields();
273 14262168 : data_.next_free = nullptr;
274 14262168 : index_ = 0;
275 : }
276 : #endif
277 :
278 : void Free(Node* free_list) {
279 : ClearFields();
280 : set_state(FREE);
281 21027137 : data_.next_free = free_list;
282 : }
283 :
284 7191537 : void Acquire(Object object) {
285 : DCHECK(!IsInUse());
286 : CheckFieldsAreCleared();
287 7191537 : object_ = object.ptr();
288 : set_state(NORMAL);
289 7191537 : data_.parameter = nullptr;
290 : DCHECK(IsInUse());
291 7191537 : }
292 :
293 6764609 : void Release(Node* free_list) {
294 : DCHECK(IsInUse());
295 : Free(free_list);
296 : DCHECK(!IsInUse());
297 6764609 : }
298 :
299 : void Zap() {
300 : DCHECK(IsInUse());
301 : // Zap the values for eager trapping.
302 : object_ = kGlobalHandleZapValue;
303 : }
304 :
305 : // Object slot accessors.
306 : Object object() const { return Object(object_); }
307 24703882 : FullObjectSlot location() { return FullObjectSlot(&object_); }
308 8489580 : const char* label() { return state() == NORMAL ? data_.label : nullptr; }
309 7191562 : Handle<Object> handle() { return Handle<Object>(&object_); }
310 :
311 : // Wrapper class ID accessors.
312 : bool has_wrapper_class_id() const {
313 : return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
314 : }
315 : uint16_t wrapper_class_id() const { return class_id_; }
316 :
317 : // State and flag accessors.
318 :
319 : State state() const {
320 : return NodeState::decode(flags_);
321 : }
322 : void set_state(State state) {
323 79554580 : flags_ = NodeState::update(flags_, state);
324 : }
325 :
326 : bool is_independent() { return IsIndependent::decode(flags_); }
327 70578610 : void set_independent(bool v) { flags_ = IsIndependent::update(flags_, v); }
328 :
329 : bool is_active() {
330 : return IsActive::decode(flags_);
331 : }
332 : void set_active(bool v) {
333 79913297 : flags_ = IsActive::update(flags_, v);
334 : }
335 :
336 : bool is_in_new_space_list() {
337 : return IsInNewSpaceList::decode(flags_);
338 : }
339 : void set_in_new_space_list(bool v) {
340 43353324 : flags_ = IsInNewSpaceList::update(flags_, v);
341 : }
342 :
343 : WeaknessType weakness_type() const {
344 : return NodeWeaknessType::decode(flags_);
345 : }
346 : void set_weakness_type(WeaknessType weakness_type) {
347 8393686 : flags_ = NodeWeaknessType::update(flags_, weakness_type);
348 : }
349 :
350 40 : bool IsNearDeath() const {
351 : // Check for PENDING to ensure correct answer when processing callbacks.
352 40 : return state() == PENDING || state() == NEAR_DEATH;
353 : }
354 :
355 27282107 : bool IsWeak() const { return state() == WEAK; }
356 :
357 : bool IsInUse() const { return state() != FREE; }
358 :
359 3680870 : bool IsPhantomCallback() const {
360 7361696 : return weakness_type() == PHANTOM_WEAK ||
361 : weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS;
362 : }
363 :
364 3680842 : bool IsPhantomResetHandle() const {
365 : return weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
366 : }
367 :
368 : bool IsPendingPhantomCallback() const {
369 : return state() == PENDING && IsPhantomCallback();
370 : }
371 :
372 : bool IsPendingPhantomResetHandle() const {
373 : return state() == PENDING && IsPhantomResetHandle();
374 : }
375 :
376 61355071 : bool IsRetainer() const {
377 61355071 : return state() != FREE &&
378 3673089 : !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
379 : }
380 :
381 41161363 : bool IsStrongRetainer() const { return state() == NORMAL; }
382 :
383 53713408 : bool IsWeakRetainer() const {
384 54305855 : return state() == WEAK || state() == PENDING ||
385 0 : (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
386 : }
387 :
388 : void MarkPending() {
389 : DCHECK(state() == WEAK);
390 : set_state(PENDING);
391 : }
392 :
393 : // Callback parameter accessors.
394 : void set_parameter(void* parameter) {
395 : DCHECK(IsInUse());
396 4196908 : data_.parameter = parameter;
397 : }
398 : void* parameter() const {
399 : DCHECK(IsInUse());
400 : return data_.parameter;
401 : }
402 :
403 : // Accessors for next free node in the free list.
404 7191537 : Node* next_free() {
405 : DCHECK_EQ(FREE, state());
406 7191537 : return data_.next_free;
407 : }
408 :
409 4196847 : void MakeWeak(void* parameter,
410 : WeakCallbackInfo<void>::Callback phantom_callback,
411 : v8::WeakCallbackType type) {
412 : DCHECK_NOT_NULL(phantom_callback);
413 : DCHECK(IsInUse());
414 4196847 : CHECK_NE(object_, kGlobalHandleZapValue);
415 : set_state(WEAK);
416 4196847 : switch (type) {
417 : case v8::WeakCallbackType::kParameter:
418 : set_weakness_type(PHANTOM_WEAK);
419 : break;
420 : case v8::WeakCallbackType::kInternalFields:
421 : set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
422 : break;
423 : case v8::WeakCallbackType::kFinalizer:
424 : set_weakness_type(FINALIZER_WEAK);
425 : break;
426 : }
427 : set_parameter(parameter);
428 4196847 : weak_callback_ = phantom_callback;
429 4196847 : }
430 :
431 26 : void MakeWeak(Address** location_addr) {
432 : DCHECK(IsInUse());
433 26 : CHECK_NE(object_, kGlobalHandleZapValue);
434 : set_state(WEAK);
435 : set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
436 : set_parameter(location_addr);
437 26 : weak_callback_ = nullptr;
438 26 : }
439 :
440 35 : void* ClearWeakness() {
441 : DCHECK(IsInUse());
442 : void* p = parameter();
443 : set_state(NORMAL);
444 : set_parameter(nullptr);
445 : return p;
446 : }
447 :
448 : void AnnotateStrongRetainer(const char* label) {
449 : DCHECK_EQ(state(), NORMAL);
450 2814437 : data_.label = label;
451 : }
452 :
453 3680826 : void CollectPhantomCallbackData(
454 :
455 7361686 : std::vector<PendingPhantomCallback>* pending_phantom_callbacks) {
456 : DCHECK(weakness_type() == PHANTOM_WEAK ||
457 : weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
458 : DCHECK(state() == PENDING);
459 : DCHECK_NOT_NULL(weak_callback_);
460 :
461 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
462 3680826 : nullptr};
463 3680860 : if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
464 17 : JSObject jsobject = JSObject::cast(object());
465 17 : int field_count = jsobject->GetEmbedderFieldCount();
466 46 : for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
467 34 : if (field_count == i) break;
468 : void* pointer;
469 29 : if (EmbedderDataSlot(jsobject, i).ToAlignedPointer(&pointer)) {
470 29 : embedder_fields[i] = pointer;
471 : }
472 : }
473 : }
474 :
475 : // Zap with something dangerous.
476 : location().store(Object(0x6057CA11));
477 :
478 : pending_phantom_callbacks->push_back(PendingPhantomCallback(
479 7361652 : this, weak_callback_, parameter(), embedder_fields));
480 : DCHECK(IsInUse());
481 : set_state(NEAR_DEATH);
482 3680826 : }
483 :
484 16 : void ResetPhantomHandle() {
485 : DCHECK(weakness_type() == PHANTOM_WEAK_RESET_HANDLE);
486 : DCHECK(state() == PENDING);
487 : DCHECK_NULL(weak_callback_);
488 : Address** handle = reinterpret_cast<Address**>(parameter());
489 16 : *handle = nullptr;
490 16 : NodeSpace<Node>::Release(this);
491 : }
492 :
493 4525174 : bool PostGarbageCollectionProcessing(Isolate* isolate) {
494 : // Handles only weak handles (not phantom) that are dying.
495 4525134 : if (state() != Node::PENDING) return false;
496 20 : if (weak_callback_ == nullptr) {
497 0 : NodeSpace<Node>::Release(this);
498 0 : return false;
499 : }
500 : set_state(NEAR_DEATH);
501 :
502 : // Check that we are not passing a finalized external string to
503 : // the callback.
504 : DCHECK(!object()->IsExternalOneByteString() ||
505 : ExternalOneByteString::cast(object())->resource() != nullptr);
506 : DCHECK(!object()->IsExternalTwoByteString() ||
507 : ExternalTwoByteString::cast(object())->resource() != nullptr);
508 20 : if (weakness_type() != FINALIZER_WEAK) {
509 : return false;
510 : }
511 :
512 : // Leaving V8.
513 20 : VMState<EXTERNAL> vmstate(isolate);
514 : HandleScope handle_scope(isolate);
515 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
516 20 : nullptr};
517 : v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
518 : parameter(), embedder_fields, nullptr);
519 20 : weak_callback_(data);
520 :
521 : // Absence of explicit cleanup or revival of weak handle
522 : // in most of the cases would lead to memory leak.
523 20 : CHECK(state() != NEAR_DEATH);
524 20 : return true;
525 : }
526 :
527 : inline GlobalHandles* GetGlobalHandles();
528 :
529 20720764 : uint8_t index() const { return index_; }
530 14262528 : void set_index(uint8_t value) { index_ = value; }
531 :
532 : private:
533 : // Fields that are not used for managing node memory.
534 : void ClearFields() {
535 : // Zap the values for eager trapping.
536 35289305 : object_ = kGlobalHandleZapValue;
537 35289305 : class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
538 : set_independent(false);
539 : set_active(false);
540 35289305 : weak_callback_ = nullptr;
541 : }
542 :
543 : void CheckFieldsAreCleared() {
544 : DCHECK_EQ(kGlobalHandleZapValue, object_);
545 : DCHECK_EQ(v8::HeapProfiler::kPersistentHandleNoClassId, class_id_);
546 : DCHECK(!is_independent());
547 : DCHECK(!is_active());
548 : DCHECK_EQ(nullptr, weak_callback_);
549 : }
550 :
551 : // Storage for object pointer.
552 : //
553 : // Placed first to avoid offset computation. The stored data is equivalent to
554 : // an Object. It is stored as a plain Address for convenience (smallest number
555 : // of casts), and because it is a private implementation detail: the public
556 : // interface provides type safety.
557 : Address object_;
558 :
559 : // Next word stores class_id, index, state, and independent.
560 : // Note: the most aligned fields should go first.
561 :
562 : // Wrapper class ID.
563 : uint16_t class_id_;
564 :
565 : // Index in the containing handle block.
566 : uint8_t index_;
567 :
568 : // This stores three flags (independent, partially_dependent and
569 : // in_new_space_list) and a State.
570 : class NodeState : public BitField<State, 0, 3> {};
571 : class IsIndependent : public BitField<bool, 3, 1> {};
572 : // The following two fields are mutually exclusive
573 : class IsActive : public BitField<bool, 4, 1> {};
574 : class IsInNewSpaceList : public BitField<bool, 5, 1> {};
575 : class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
576 :
577 : uint8_t flags_;
578 :
579 : // Handle specific callback - might be a weak reference in disguise.
580 : WeakCallbackInfo<void>::Callback weak_callback_;
581 :
582 : // The meaning of this field depends on node state:
583 : // state == FREE: it stores the next free node pointer.
584 : // state == NORMAL: it stores the strong retainer label.
585 : // otherwise: it stores the parameter for the weak callback.
586 : union {
587 : Node* next_free;
588 : const char* label;
589 : void* parameter;
590 : } data_;
591 :
592 : DISALLOW_COPY_AND_ASSIGN(Node);
593 : };
594 :
595 : GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
596 10 : return NodeBlock<Node>::From(this)->global_handles();
597 : }
598 :
599 62883 : GlobalHandles::GlobalHandles(Isolate* isolate)
600 : : isolate_(isolate),
601 : regular_nodes_(new NodeSpace<GlobalHandles::Node>(this)),
602 : number_of_global_handles_(0),
603 : post_gc_processing_count_(0),
604 188649 : number_of_phantom_handle_resets_(0) {}
605 :
606 125735 : GlobalHandles::~GlobalHandles() { regular_nodes_.reset(nullptr); }
607 :
608 7191533 : Handle<Object> GlobalHandles::Create(Object value) {
609 7191537 : GlobalHandles::Node* result = regular_nodes_->Acquire(value);
610 11270579 : if (Heap::InNewSpace(value) && !result->is_in_new_space_list()) {
611 3918755 : new_space_nodes_.push_back(result);
612 3918755 : result->set_in_new_space_list(true);
613 : }
614 14383074 : return result->handle();
615 : }
616 :
617 3032512 : Handle<Object> GlobalHandles::Create(Address value) {
618 3032522 : return Create(Object(value));
619 : }
620 :
621 10 : Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
622 : DCHECK_NOT_NULL(location);
623 : GlobalHandles* global_handles =
624 : Node::FromLocation(location)->GetGlobalHandles();
625 : #ifdef VERIFY_HEAP
626 : if (i::FLAG_verify_heap) {
627 : Object(*location)->ObjectVerify(global_handles->isolate());
628 : }
629 : #endif // VERIFY_HEAP
630 20 : return global_handles->Create(*location);
631 : }
632 :
633 6764593 : void GlobalHandles::Destroy(Address* location) {
634 6764593 : if (location != nullptr) {
635 6764593 : NodeSpace<Node>::Release(Node::FromLocation(location));
636 : }
637 6764593 : }
638 :
639 : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
640 :
641 :
642 4196847 : void GlobalHandles::MakeWeak(Address* location, void* parameter,
643 : GenericCallback phantom_callback,
644 : v8::WeakCallbackType type) {
645 4196847 : Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
646 4196848 : }
647 :
648 26 : void GlobalHandles::MakeWeak(Address** location_addr) {
649 26 : Node::FromLocation(*location_addr)->MakeWeak(location_addr);
650 26 : }
651 :
652 35 : void* GlobalHandles::ClearWeakness(Address* location) {
653 35 : return Node::FromLocation(location)->ClearWeakness();
654 : }
655 :
656 2814437 : void GlobalHandles::AnnotateStrongRetainer(Address* location,
657 : const char* label) {
658 : Node::FromLocation(location)->AnnotateStrongRetainer(label);
659 2814437 : }
660 :
661 40 : bool GlobalHandles::IsNearDeath(Address* location) {
662 40 : return Node::FromLocation(location)->IsNearDeath();
663 : }
664 :
665 20 : bool GlobalHandles::IsWeak(Address* location) {
666 20 : return Node::FromLocation(location)->IsWeak();
667 : }
668 :
669 : DISABLE_CFI_PERF
670 83492 : void GlobalHandles::IterateWeakRootsForFinalizers(RootVisitor* v) {
671 27023688 : for (Node* node : *regular_nodes_) {
672 26856704 : if (node->IsWeakRetainer() && node->state() == Node::PENDING) {
673 : DCHECK(!node->IsPhantomCallback());
674 : DCHECK(!node->IsPhantomResetHandle());
675 : // Finalizers need to survive.
676 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
677 40 : node->location());
678 : }
679 : }
680 83492 : }
681 :
682 : DISABLE_CFI_PERF
683 83492 : void GlobalHandles::IterateWeakRootsForPhantomHandles(
684 6189964 : WeakSlotCallbackWithHeap should_reset_handle) {
685 27023688 : for (Node* node : *regular_nodes_) {
686 33046668 : if (node->IsWeakRetainer() &&
687 6189964 : should_reset_handle(isolate()->heap(), node->location())) {
688 3673105 : if (node->IsPhantomResetHandle()) {
689 : node->MarkPending();
690 : node->ResetPhantomHandle();
691 16 : ++number_of_phantom_handle_resets_;
692 3673089 : } else if (node->IsPhantomCallback()) {
693 : node->MarkPending();
694 3673089 : node->CollectPhantomCallbackData(&pending_phantom_callbacks_);
695 : }
696 : }
697 : }
698 83492 : }
699 :
700 83492 : void GlobalHandles::IdentifyWeakHandles(
701 6189964 : WeakSlotCallbackWithHeap should_reset_handle) {
702 27023688 : for (Node* node : *regular_nodes_) {
703 33046668 : if (node->IsWeak() &&
704 6189964 : should_reset_handle(isolate()->heap(), node->location())) {
705 3673133 : if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
706 : node->MarkPending();
707 : }
708 : }
709 : }
710 83492 : }
711 :
712 23594 : void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(RootVisitor* v) {
713 370407 : for (Node* node : new_space_nodes_) {
714 798807 : if (node->IsStrongRetainer() ||
715 241290 : (node->IsWeakRetainer() && !node->is_independent() &&
716 : node->is_active())) {
717 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
718 548060 : node->location());
719 : }
720 : }
721 23594 : }
722 :
723 0 : void GlobalHandles::IterateNewSpaceStrongAndDependentRootsAndIdentifyUnmodified(
724 : RootVisitor* v, size_t start, size_t end) {
725 0 : for (size_t i = start; i < end; ++i) {
726 0 : Node* node = new_space_nodes_[i];
727 0 : if (node->IsWeak() && !JSObject::IsUnmodifiedApiObject(node->location())) {
728 : node->set_active(true);
729 : }
730 0 : if (node->IsStrongRetainer() ||
731 0 : (node->IsWeakRetainer() && !node->is_independent() &&
732 : node->is_active())) {
733 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
734 0 : node->location());
735 : }
736 : }
737 0 : }
738 :
739 23594 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
740 : WeakSlotCallback is_unmodified) {
741 370407 : for (Node* node : new_space_nodes_) {
742 461293 : if (node->IsWeak() && !is_unmodified(node->location())) {
743 : node->set_active(true);
744 : }
745 : }
746 23594 : }
747 :
748 23594 : void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
749 : WeakSlotCallbackWithHeap is_dead) {
750 370407 : for (Node* node : new_space_nodes_) {
751 : DCHECK(node->is_in_new_space_list());
752 866513 : if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
753 34894 : is_dead(isolate_->heap(), node->location())) {
754 7737 : if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) {
755 : node->MarkPending();
756 : }
757 : }
758 : }
759 23594 : }
760 :
761 23594 : void GlobalHandles::IterateNewSpaceWeakUnmodifiedRootsForFinalizers(
762 : RootVisitor* v) {
763 370407 : for (Node* node : new_space_nodes_) {
764 : DCHECK(node->is_in_new_space_list());
765 831619 : if ((node->is_independent() || !node->is_active()) &&
766 358113 : node->IsWeakRetainer() && (node->state() == Node::PENDING)) {
767 : DCHECK(!node->IsPhantomCallback());
768 : DCHECK(!node->IsPhantomResetHandle());
769 : // Finalizers need to survive.
770 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
771 0 : node->location());
772 : }
773 : }
774 23594 : }
775 :
776 23594 : void GlobalHandles::IterateNewSpaceWeakUnmodifiedRootsForPhantomHandles(
777 : RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) {
778 370407 : for (Node* node : new_space_nodes_) {
779 : DCHECK(node->is_in_new_space_list());
780 831619 : if ((node->is_independent() || !node->is_active()) &&
781 358113 : node->IsWeakRetainer() && (node->state() != Node::PENDING)) {
782 34894 : if (should_reset_handle(isolate_->heap(), node->location())) {
783 : DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
784 7737 : if (node->IsPhantomResetHandle()) {
785 : node->MarkPending();
786 : node->ResetPhantomHandle();
787 0 : ++number_of_phantom_handle_resets_;
788 :
789 7737 : } else if (node->IsPhantomCallback()) {
790 : node->MarkPending();
791 7737 : node->CollectPhantomCallbackData(&pending_phantom_callbacks_);
792 : } else {
793 0 : UNREACHABLE();
794 : }
795 : } else {
796 : // Node survived and needs to be visited.
797 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
798 54314 : node->location());
799 : }
800 : }
801 : }
802 23594 : }
803 :
804 2565 : void GlobalHandles::InvokeSecondPassPhantomCallbacksFromTask() {
805 : DCHECK(second_pass_callbacks_task_posted_);
806 855 : second_pass_callbacks_task_posted_ = false;
807 1710 : TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
808 : isolate()->heap()->CallGCPrologueCallbacks(
809 855 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
810 855 : InvokeSecondPassPhantomCallbacks();
811 : isolate()->heap()->CallGCEpilogueCallbacks(
812 855 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
813 855 : }
814 :
815 3353299 : void GlobalHandles::InvokeSecondPassPhantomCallbacks() {
816 3470633 : while (!second_pass_callbacks_.empty()) {
817 3235965 : auto callback = second_pass_callbacks_.back();
818 : second_pass_callbacks_.pop_back();
819 : DCHECK_NULL(callback.node());
820 : // Fire second pass callback
821 3235965 : callback.Invoke(isolate());
822 : }
823 117334 : }
824 :
825 23594 : int GlobalHandles::PostScavengeProcessing(
826 : const int initial_post_gc_processing_count) {
827 : int freed_nodes = 0;
828 370407 : for (Node* node : new_space_nodes_) {
829 : DCHECK(node->is_in_new_space_list());
830 323219 : if (!node->IsRetainer()) {
831 : // Free nodes do not have weak callbacks. Do not use them to compute
832 : // the freed_nodes.
833 : continue;
834 : }
835 : // Skip dependent or unmodified handles. Their weak callbacks might expect
836 : // to be
837 : // called between two global garbage collection callbacks which
838 : // are not called for minor collections.
839 575227 : if (!node->is_independent() && (node->is_active())) {
840 : node->set_active(false);
841 : continue;
842 : }
843 : node->set_active(false);
844 :
845 198007 : if (node->PostGarbageCollectionProcessing(isolate_)) {
846 0 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
847 : // Weak callback triggered another GC and another round of
848 : // PostGarbageCollection processing. The current node might
849 : // have been deleted in that round, so we need to bail out (or
850 : // restart the processing).
851 : return freed_nodes;
852 : }
853 : }
854 198007 : if (!node->IsRetainer()) {
855 0 : freed_nodes++;
856 : }
857 : }
858 : return freed_nodes;
859 : }
860 :
861 :
862 83492 : int GlobalHandles::PostMarkSweepProcessing(
863 : const int initial_post_gc_processing_count) {
864 : int freed_nodes = 0;
865 23995208 : for (Node* node : *regular_nodes_) {
866 23828224 : if (!node->IsRetainer()) {
867 : // Free nodes do not have weak callbacks. Do not use them to compute
868 : // the freed_nodes.
869 : continue;
870 : }
871 : node->set_active(false);
872 4327127 : if (node->PostGarbageCollectionProcessing(isolate_)) {
873 20 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
874 : // See the comment above.
875 : return freed_nodes;
876 : }
877 : }
878 4327127 : if (!node->IsRetainer()) {
879 5 : freed_nodes++;
880 : }
881 : }
882 83492 : return freed_nodes;
883 : }
884 :
885 :
886 107086 : void GlobalHandles::UpdateListOfNewSpaceNodes() {
887 : size_t last = 0;
888 7615465 : for (Node* node : new_space_nodes_) {
889 : DCHECK(node->is_in_new_space_list());
890 5285977 : if (node->IsRetainer()) {
891 2115316 : if (Heap::InNewSpace(node->object())) {
892 3581196 : new_space_nodes_[last++] = node;
893 1790598 : isolate_->heap()->IncrementNodesCopiedInNewSpace();
894 : } else {
895 : node->set_in_new_space_list(false);
896 324718 : isolate_->heap()->IncrementNodesPromoted();
897 : }
898 : } else {
899 : node->set_in_new_space_list(false);
900 3170661 : isolate_->heap()->IncrementNodesDiedInNewSpace();
901 : }
902 : }
903 : DCHECK_LE(last, new_space_nodes_.size());
904 107086 : new_space_nodes_.resize(last);
905 : new_space_nodes_.shrink_to_fit();
906 107086 : }
907 :
908 3787912 : int GlobalHandles::InvokeFirstPassWeakCallbacks() {
909 : int freed_nodes = 0;
910 : std::vector<PendingPhantomCallback> pending_phantom_callbacks;
911 : pending_phantom_callbacks.swap(pending_phantom_callbacks_);
912 : {
913 : // The initial pass callbacks must simply clear the nodes.
914 3894998 : for (auto callback : pending_phantom_callbacks) {
915 : // Skip callbacks that have already been processed once.
916 3680826 : if (callback.node() == nullptr) continue;
917 3680826 : callback.Invoke(isolate());
918 3680826 : if (callback.callback()) second_pass_callbacks_.push_back(callback);
919 3680826 : freed_nodes++;
920 : }
921 : }
922 107086 : return freed_nodes;
923 : }
924 :
925 107086 : void GlobalHandles::InvokeOrScheduleSecondPassPhantomCallbacks(
926 20496 : bool synchronous_second_pass) {
927 107086 : if (!second_pass_callbacks_.empty()) {
928 10487 : if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
929 : isolate()->heap()->CallGCPrologueCallbacks(
930 9393 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
931 9393 : InvokeSecondPassPhantomCallbacks();
932 : isolate()->heap()->CallGCEpilogueCallbacks(
933 9393 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
934 1094 : } else if (!second_pass_callbacks_task_posted_) {
935 855 : second_pass_callbacks_task_posted_ = true;
936 855 : auto taskrunner = V8::GetCurrentPlatform()->GetForegroundTaskRunner(
937 1710 : reinterpret_cast<v8::Isolate*>(isolate()));
938 855 : taskrunner->PostTask(MakeCancelableTask(
939 5985 : isolate(), [this] { InvokeSecondPassPhantomCallbacksFromTask(); }));
940 : }
941 : }
942 107086 : }
943 :
944 6916791 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
945 : Data::Callback* callback_addr = nullptr;
946 10597617 : if (node_ != nullptr) {
947 : // Initialize for first pass callback.
948 : DCHECK(node_->state() == Node::NEAR_DEATH);
949 3680826 : callback_addr = &callback_;
950 : }
951 : Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
952 6916791 : embedder_fields_, callback_addr);
953 6916791 : Data::Callback callback = callback_;
954 6916791 : callback_ = nullptr;
955 6916791 : callback(data);
956 6916791 : if (node_ != nullptr) {
957 : // Transition to second pass. It is required that the first pass callback
958 : // resets the handle using |v8::PersistentBase::Reset|. Also see comments on
959 : // |v8::WeakCallbackInfo|.
960 3680826 : CHECK_WITH_MSG(Node::FREE == node_->state(),
961 : "Handle not reset in first callback. See comments on "
962 : "|v8::WeakCallbackInfo|.");
963 3680826 : node_ = nullptr;
964 : }
965 6916791 : }
966 :
967 107086 : int GlobalHandles::PostGarbageCollectionProcessing(
968 : GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
969 : // Process weak global handle callbacks. This must be done after the
970 : // GC is completely done, because the callbacks may invoke arbitrary
971 : // API functions.
972 : DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
973 107086 : const int initial_post_gc_processing_count = ++post_gc_processing_count_;
974 : int freed_nodes = 0;
975 : bool synchronous_second_pass =
976 214172 : isolate_->heap()->IsTearingDown() ||
977 107086 : (gc_callback_flags &
978 : (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
979 : kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
980 107086 : InvokeOrScheduleSecondPassPhantomCallbacks(synchronous_second_pass);
981 107086 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
982 : // If the callbacks caused a nested GC, then return. See comment in
983 : // PostScavengeProcessing.
984 : return freed_nodes;
985 : }
986 107086 : if (Heap::IsYoungGenerationCollector(collector)) {
987 23594 : freed_nodes += PostScavengeProcessing(initial_post_gc_processing_count);
988 : } else {
989 83492 : freed_nodes += PostMarkSweepProcessing(initial_post_gc_processing_count);
990 : }
991 107086 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
992 : // If the callbacks caused a nested GC, then return. See comment in
993 : // PostScavengeProcessing.
994 : return freed_nodes;
995 : }
996 107086 : if (initial_post_gc_processing_count == post_gc_processing_count_) {
997 107086 : UpdateListOfNewSpaceNodes();
998 : }
999 107086 : return freed_nodes;
1000 : }
1001 :
1002 135795 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
1003 41109734 : for (Node* node : *regular_nodes_) {
1004 40838144 : if (node->IsStrongRetainer()) {
1005 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1006 7575154 : node->location());
1007 : }
1008 : }
1009 135795 : }
1010 :
1011 399 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
1012 102942 : for (Node* node : *regular_nodes_) {
1013 102144 : if (node->IsWeak()) {
1014 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1015 60 : node->location());
1016 : }
1017 : }
1018 399 : }
1019 :
1020 : DISABLE_CFI_PERF
1021 85368 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
1022 27467504 : for (Node* node : *regular_nodes_) {
1023 27296768 : if (node->IsRetainer()) {
1024 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1025 8747218 : node->location());
1026 : }
1027 : }
1028 85368 : }
1029 :
1030 : DISABLE_CFI_PERF
1031 0 : void GlobalHandles::IterateAllNewSpaceRoots(RootVisitor* v) {
1032 0 : for (Node* node : new_space_nodes_) {
1033 0 : if (node->IsRetainer()) {
1034 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1035 0 : node->location());
1036 : }
1037 : }
1038 0 : }
1039 :
1040 : DISABLE_CFI_PERF
1041 0 : void GlobalHandles::IterateNewSpaceRoots(RootVisitor* v, size_t start,
1042 : size_t end) {
1043 0 : for (size_t i = start; i < end; ++i) {
1044 0 : Node* node = new_space_nodes_[i];
1045 0 : if (node->IsRetainer()) {
1046 : v->VisitRootPointer(Root::kGlobalHandles, node->label(),
1047 0 : node->location());
1048 : }
1049 : }
1050 0 : }
1051 :
1052 : DISABLE_CFI_PERF
1053 0 : void GlobalHandles::ApplyPersistentHandleVisitor(
1054 25 : v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
1055 25 : v8::Value* value = ToApi<v8::Value>(node->handle());
1056 : visitor->VisitPersistentHandle(
1057 : reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
1058 50 : node->wrapper_class_id());
1059 0 : }
1060 :
1061 : DISABLE_CFI_PERF
1062 374 : void GlobalHandles::IterateAllRootsWithClassIds(
1063 : v8::PersistentHandleVisitor* visitor) {
1064 97076 : for (Node* node : *regular_nodes_) {
1065 96328 : if (node->IsRetainer() && node->has_wrapper_class_id()) {
1066 : ApplyPersistentHandleVisitor(visitor, node);
1067 : }
1068 : }
1069 374 : }
1070 :
1071 :
1072 : DISABLE_CFI_PERF
1073 5 : void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(
1074 : v8::PersistentHandleVisitor* visitor) {
1075 20 : for (Node* node : new_space_nodes_) {
1076 10 : if (node->IsRetainer() && node->has_wrapper_class_id()) {
1077 : ApplyPersistentHandleVisitor(visitor, node);
1078 : }
1079 : }
1080 5 : }
1081 :
1082 :
1083 : DISABLE_CFI_PERF
1084 0 : void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(
1085 : v8::PersistentHandleVisitor* visitor) {
1086 0 : for (Node* node : new_space_nodes_) {
1087 0 : if (node->has_wrapper_class_id() && node->IsWeak()) {
1088 : ApplyPersistentHandleVisitor(visitor, node);
1089 : }
1090 : }
1091 0 : }
1092 :
1093 15 : void GlobalHandles::RecordStats(HeapStats* stats) {
1094 15 : *stats->global_handle_count = 0;
1095 15 : *stats->weak_global_handle_count = 0;
1096 15 : *stats->pending_global_handle_count = 0;
1097 15 : *stats->near_death_global_handle_count = 0;
1098 15 : *stats->free_global_handle_count = 0;
1099 30 : for (Node* node : *regular_nodes_) {
1100 0 : *stats->global_handle_count += 1;
1101 0 : if (node->state() == Node::WEAK) {
1102 0 : *stats->weak_global_handle_count += 1;
1103 0 : } else if (node->state() == Node::PENDING) {
1104 0 : *stats->pending_global_handle_count += 1;
1105 0 : } else if (node->state() == Node::NEAR_DEATH) {
1106 0 : *stats->near_death_global_handle_count += 1;
1107 0 : } else if (node->state() == Node::FREE) {
1108 0 : *stats->free_global_handle_count += 1;
1109 : }
1110 : }
1111 15 : }
1112 :
1113 : #ifdef DEBUG
1114 :
1115 : void GlobalHandles::PrintStats() {
1116 : int total = 0;
1117 : int weak = 0;
1118 : int pending = 0;
1119 : int near_death = 0;
1120 : int destroyed = 0;
1121 :
1122 : for (Node* node : *regular_nodes_) {
1123 : total++;
1124 : if (node->state() == Node::WEAK) weak++;
1125 : if (node->state() == Node::PENDING) pending++;
1126 : if (node->state() == Node::NEAR_DEATH) near_death++;
1127 : if (node->state() == Node::FREE) destroyed++;
1128 : }
1129 :
1130 : PrintF("Global Handle Statistics:\n");
1131 : PrintF(" allocated memory = %" PRIuS "B\n", total * sizeof(Node));
1132 : PrintF(" # weak = %d\n", weak);
1133 : PrintF(" # pending = %d\n", pending);
1134 : PrintF(" # near_death = %d\n", near_death);
1135 : PrintF(" # free = %d\n", destroyed);
1136 : PrintF(" # total = %d\n", total);
1137 : }
1138 :
1139 :
1140 : void GlobalHandles::Print() {
1141 : PrintF("Global handles:\n");
1142 : for (Node* node : *regular_nodes_) {
1143 : PrintF(" handle %p to %p%s\n", node->location().ToVoidPtr(),
1144 : reinterpret_cast<void*>(node->object()->ptr()),
1145 : node->IsWeak() ? " (weak)" : "");
1146 : }
1147 : }
1148 :
1149 : #endif
1150 :
1151 62867 : void GlobalHandles::TearDown() {}
1152 :
1153 125766 : EternalHandles::EternalHandles() : size_(0) {}
1154 :
1155 62867 : EternalHandles::~EternalHandles() {
1156 125819 : for (Address* block : blocks_) delete[] block;
1157 62867 : }
1158 :
1159 220764 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
1160 220764 : int limit = size_;
1161 441937 : for (Address* block : blocks_) {
1162 : DCHECK_GT(limit, 0);
1163 : visitor->VisitRootPointers(Root::kEternalHandles, nullptr,
1164 : FullObjectSlot(block),
1165 1227 : FullObjectSlot(block + Min(limit, kSize)));
1166 409 : limit -= kSize;
1167 : }
1168 220764 : }
1169 :
1170 23594 : void EternalHandles::IterateNewSpaceRoots(RootVisitor* visitor) {
1171 62228 : for (int index : new_space_indices_) {
1172 : visitor->VisitRootPointer(Root::kEternalHandles, nullptr,
1173 30080 : FullObjectSlot(GetLocation(index)));
1174 : }
1175 23594 : }
1176 :
1177 107086 : void EternalHandles::PostGarbageCollectionProcessing() {
1178 : size_t last = 0;
1179 255063 : for (int index : new_space_indices_) {
1180 81782 : if (Heap::InNewSpace(Object(*GetLocation(index)))) {
1181 40842 : new_space_indices_[last++] = index;
1182 : }
1183 : }
1184 : DCHECK_LE(last, new_space_indices_.size());
1185 107086 : new_space_indices_.resize(last);
1186 107086 : }
1187 :
1188 20480 : void EternalHandles::Create(Isolate* isolate, Object object, int* index) {
1189 : DCHECK_EQ(kInvalidIndex, *index);
1190 40960 : if (object == Object()) return;
1191 : Object the_hole = ReadOnlyRoots(isolate).the_hole_value();
1192 : DCHECK_NE(the_hole, object);
1193 20480 : int block = size_ >> kShift;
1194 20480 : int offset = size_ & kMask;
1195 : // Need to resize.
1196 20480 : if (offset == 0) {
1197 85 : Address* next_block = new Address[kSize];
1198 : MemsetPointer(FullObjectSlot(next_block), the_hole, kSize);
1199 20565 : blocks_.push_back(next_block);
1200 : }
1201 : DCHECK_EQ(the_hole->ptr(), blocks_[block][offset]);
1202 40960 : blocks_[block][offset] = object->ptr();
1203 20480 : if (Heap::InNewSpace(object)) {
1204 20475 : new_space_indices_.push_back(size_);
1205 : }
1206 20480 : *index = size_++;
1207 : }
1208 :
1209 : } // namespace internal
1210 183867 : } // namespace v8
|