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.h"
8 : #include "src/cancelable-task.h"
9 : #include "src/objects-inl.h"
10 : #include "src/v8.h"
11 : #include "src/visitors.h"
12 : #include "src/vm-state-inl.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 : class GlobalHandles::Node {
18 : public:
19 : // State transition diagram:
20 : // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
21 : enum State {
22 : FREE = 0,
23 : NORMAL, // Normal global handle.
24 : WEAK, // Flagged as weak but not yet finalized.
25 : PENDING, // Has been recognized as only reachable by weak handles.
26 : NEAR_DEATH, // Callback has informed the handle is near death.
27 : NUMBER_OF_NODE_STATES
28 : };
29 :
30 : // Maps handle location (slot) to the containing node.
31 : static Node* FromLocation(Object** location) {
32 : DCHECK_EQ(offsetof(Node, object_), 0);
33 : return reinterpret_cast<Node*>(location);
34 : }
35 :
36 : Node() {
37 : DCHECK_EQ(offsetof(Node, class_id_), Internals::kNodeClassIdOffset);
38 : DCHECK_EQ(offsetof(Node, flags_), Internals::kNodeFlagsOffset);
39 : STATIC_ASSERT(static_cast<int>(NodeState::kMask) ==
40 : Internals::kNodeStateMask);
41 : STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue);
42 : STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue);
43 : STATIC_ASSERT(NEAR_DEATH == Internals::kNodeStateIsNearDeathValue);
44 : STATIC_ASSERT(static_cast<int>(IsIndependent::kShift) ==
45 : Internals::kNodeIsIndependentShift);
46 : STATIC_ASSERT(static_cast<int>(IsActive::kShift) ==
47 : Internals::kNodeIsActiveShift);
48 : }
49 :
50 : #ifdef ENABLE_HANDLE_ZAPPING
51 : ~Node() {
52 : // TODO(1428): if it's a weak handle we should have invoked its callback.
53 : // Zap the values for eager trapping.
54 10978048 : object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
55 10978048 : class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
56 10978048 : index_ = 0;
57 : set_independent(false);
58 : set_active(false);
59 : set_in_new_space_list(false);
60 10978048 : parameter_or_next_free_.next_free = nullptr;
61 10978048 : weak_callback_ = nullptr;
62 : }
63 : #endif
64 :
65 : void Initialize(int index, Node** first_free) {
66 11398144 : object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
67 11398144 : index_ = static_cast<uint8_t>(index);
68 : DCHECK(static_cast<int>(index_) == index);
69 : set_state(FREE);
70 : set_in_new_space_list(false);
71 11398144 : parameter_or_next_free_.next_free = *first_free;
72 11398144 : *first_free = this;
73 : }
74 :
75 3446567 : void Acquire(Object* object) {
76 : DCHECK(state() == FREE);
77 3446567 : object_ = object;
78 3446567 : class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
79 : set_independent(false);
80 : set_active(false);
81 : set_state(NORMAL);
82 3446567 : parameter_or_next_free_.parameter = nullptr;
83 3446567 : weak_callback_ = nullptr;
84 3446567 : IncreaseBlockUses();
85 3446566 : }
86 :
87 : void Zap() {
88 : DCHECK(IsInUse());
89 : // Zap the values for eager trapping.
90 : object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
91 : }
92 :
93 2976461 : void Release() {
94 : DCHECK(IsInUse());
95 : set_state(FREE);
96 : // Zap the values for eager trapping.
97 2976461 : object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
98 2976461 : class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
99 : set_independent(false);
100 : set_active(false);
101 2976461 : weak_callback_ = nullptr;
102 2976461 : DecreaseBlockUses();
103 2976461 : }
104 :
105 : // Object slot accessors.
106 : Object* object() const { return object_; }
107 : Object** location() { return &object_; }
108 3446566 : Handle<Object> handle() { return Handle<Object>(location()); }
109 :
110 : // Wrapper class ID accessors.
111 : bool has_wrapper_class_id() const {
112 : return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
113 : }
114 :
115 : uint16_t wrapper_class_id() const { return class_id_; }
116 :
117 : // State and flag accessors.
118 :
119 : State state() const {
120 : return NodeState::decode(flags_);
121 : }
122 : void set_state(State state) {
123 38063298 : flags_ = NodeState::update(flags_, state);
124 : }
125 :
126 : bool is_independent() {
127 : return IsIndependent::decode(flags_);
128 : }
129 : void set_independent(bool v) {
130 34802152 : flags_ = IsIndependent::update(flags_, v);
131 : }
132 :
133 : bool is_active() {
134 : return IsActive::decode(flags_);
135 : }
136 : void set_active(bool v) {
137 38644454 : flags_ = IsActive::update(flags_, v);
138 : }
139 :
140 : bool is_in_new_space_list() {
141 : return IsInNewSpaceList::decode(flags_);
142 : }
143 : void set_in_new_space_list(bool v) {
144 46728496 : flags_ = IsInNewSpaceList::update(flags_, v);
145 : }
146 :
147 : WeaknessType weakness_type() const {
148 : return NodeWeaknessType::decode(flags_);
149 : }
150 : void set_weakness_type(WeaknessType weakness_type) {
151 1155893 : flags_ = NodeWeaknessType::update(flags_, weakness_type);
152 : }
153 :
154 40 : bool IsNearDeath() const {
155 : // Check for PENDING to ensure correct answer when processing callbacks.
156 40 : return state() == PENDING || state() == NEAR_DEATH;
157 : }
158 :
159 11615801 : bool IsWeak() const { return state() == WEAK; }
160 :
161 : bool IsInUse() const { return state() != FREE; }
162 :
163 : bool IsPendingPhantomCallback() const {
164 589492 : return state() == PENDING &&
165 113479 : (weakness_type() == PHANTOM_WEAK ||
166 : weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
167 : }
168 :
169 : bool IsPendingPhantomResetHandle() const {
170 589514 : return state() == PENDING && weakness_type() == PHANTOM_WEAK_RESET_HANDLE;
171 : }
172 :
173 25182163 : bool IsRetainer() const {
174 25182163 : return state() != FREE &&
175 120100 : !(state() == NEAR_DEATH && weakness_type() != FINALIZER_WEAK);
176 : }
177 :
178 17637129 : bool IsStrongRetainer() const { return state() == NORMAL; }
179 :
180 11051776 : bool IsWeakRetainer() const {
181 11640908 : return state() == WEAK || state() == PENDING ||
182 0 : (state() == NEAR_DEATH && weakness_type() == FINALIZER_WEAK);
183 : }
184 :
185 : void MarkPending() {
186 : DCHECK(state() == WEAK);
187 : set_state(PENDING);
188 : }
189 :
190 : // Independent flag accessors.
191 : void MarkIndependent() {
192 : DCHECK(IsInUse());
193 : set_independent(true);
194 : }
195 :
196 : // Callback parameter accessors.
197 : void set_parameter(void* parameter) {
198 : DCHECK(IsInUse());
199 740552 : parameter_or_next_free_.parameter = parameter;
200 : }
201 : void* parameter() const {
202 : DCHECK(IsInUse());
203 : return parameter_or_next_free_.parameter;
204 : }
205 :
206 : // Accessors for next free node in the free list.
207 : Node* next_free() {
208 : DCHECK(state() == FREE);
209 : return parameter_or_next_free_.next_free;
210 : }
211 : void set_next_free(Node* value) {
212 : DCHECK(state() == FREE);
213 : parameter_or_next_free_.next_free = value;
214 : }
215 :
216 740516 : void MakeWeak(void* parameter,
217 : WeakCallbackInfo<void>::Callback phantom_callback,
218 : v8::WeakCallbackType type) {
219 : DCHECK_NOT_NULL(phantom_callback);
220 : DCHECK(IsInUse());
221 740516 : CHECK_NE(object_, reinterpret_cast<Object*>(kGlobalHandleZapValue));
222 : set_state(WEAK);
223 740516 : switch (type) {
224 : case v8::WeakCallbackType::kParameter:
225 : set_weakness_type(PHANTOM_WEAK);
226 : break;
227 : case v8::WeakCallbackType::kInternalFields:
228 : set_weakness_type(PHANTOM_WEAK_2_EMBEDDER_FIELDS);
229 : break;
230 : case v8::WeakCallbackType::kFinalizer:
231 : set_weakness_type(FINALIZER_WEAK);
232 : break;
233 : }
234 : set_parameter(parameter);
235 740516 : weak_callback_ = phantom_callback;
236 740516 : }
237 :
238 11 : void MakeWeak(Object*** location_addr) {
239 : DCHECK(IsInUse());
240 11 : CHECK_NE(object_, reinterpret_cast<Object*>(kGlobalHandleZapValue));
241 : set_state(WEAK);
242 : set_weakness_type(PHANTOM_WEAK_RESET_HANDLE);
243 : set_parameter(location_addr);
244 11 : weak_callback_ = nullptr;
245 11 : }
246 :
247 25 : void* ClearWeakness() {
248 : DCHECK(IsInUse());
249 : void* p = parameter();
250 : set_state(NORMAL);
251 : set_parameter(nullptr);
252 : return p;
253 : }
254 :
255 122694 : void CollectPhantomCallbackData(
256 : Isolate* isolate,
257 247820 : std::vector<PendingPhantomCallback>* pending_phantom_callbacks) {
258 : DCHECK(weakness_type() == PHANTOM_WEAK ||
259 : weakness_type() == PHANTOM_WEAK_2_EMBEDDER_FIELDS);
260 : DCHECK(state() == PENDING);
261 : DCHECK_NOT_NULL(weak_callback_);
262 :
263 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
264 122694 : nullptr};
265 123910 : if (weakness_type() != PHANTOM_WEAK && object()->IsJSObject()) {
266 : auto jsobject = JSObject::cast(object());
267 1216 : int field_count = jsobject->GetEmbedderFieldCount();
268 2455 : for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
269 2432 : if (field_count == i) break;
270 : auto field = jsobject->GetEmbedderField(i);
271 1239 : if (field->IsSmi()) embedder_fields[i] = field;
272 : }
273 : }
274 :
275 : // Zap with something dangerous.
276 122694 : *location() = reinterpret_cast<Object*>(0x6057ca11);
277 :
278 : typedef v8::WeakCallbackInfo<void> Data;
279 122694 : auto callback = reinterpret_cast<Data::Callback>(weak_callback_);
280 : pending_phantom_callbacks->push_back(
281 122694 : PendingPhantomCallback(this, callback, parameter(), embedder_fields));
282 : DCHECK(IsInUse());
283 : set_state(NEAR_DEATH);
284 122694 : }
285 :
286 11 : void ResetPhantomHandle() {
287 : DCHECK(weakness_type() == PHANTOM_WEAK_RESET_HANDLE);
288 : DCHECK(state() == PENDING);
289 : DCHECK_NULL(weak_callback_);
290 : Object*** handle = reinterpret_cast<Object***>(parameter());
291 11 : *handle = nullptr;
292 11 : Release();
293 : }
294 :
295 1431723 : bool PostGarbageCollectionProcessing(Isolate* isolate) {
296 : // Handles only weak handles (not phantom) that are dying.
297 1207197 : if (state() != Node::PENDING) return false;
298 112263 : if (weak_callback_ == nullptr) {
299 0 : Release();
300 0 : return false;
301 : }
302 : set_state(NEAR_DEATH);
303 :
304 : // Check that we are not passing a finalized external string to
305 : // the callback.
306 : DCHECK(!object_->IsExternalOneByteString() ||
307 : ExternalOneByteString::cast(object_)->resource() != nullptr);
308 : DCHECK(!object_->IsExternalTwoByteString() ||
309 : ExternalTwoByteString::cast(object_)->resource() != nullptr);
310 112263 : if (weakness_type() != FINALIZER_WEAK) {
311 : return false;
312 : }
313 :
314 : // Leaving V8.
315 112263 : VMState<EXTERNAL> vmstate(isolate);
316 : HandleScope handle_scope(isolate);
317 : void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
318 112263 : nullptr};
319 : v8::WeakCallbackInfo<void> data(reinterpret_cast<v8::Isolate*>(isolate),
320 : parameter(), embedder_fields, nullptr);
321 112263 : weak_callback_(data);
322 :
323 : // Absence of explicit cleanup or revival of weak handle
324 : // in most of the cases would lead to memory leak.
325 112263 : CHECK(state() != NEAR_DEATH);
326 112263 : return true;
327 : }
328 :
329 : inline GlobalHandles* GetGlobalHandles();
330 :
331 : private:
332 : inline NodeBlock* FindBlock();
333 : inline void IncreaseBlockUses();
334 : inline void DecreaseBlockUses();
335 :
336 : // Storage for object pointer.
337 : // Placed first to avoid offset computation.
338 : Object* object_;
339 :
340 : // Next word stores class_id, index, state, and independent.
341 : // Note: the most aligned fields should go first.
342 :
343 : // Wrapper class ID.
344 : uint16_t class_id_;
345 :
346 : // Index in the containing handle block.
347 : uint8_t index_;
348 :
349 : // This stores three flags (independent, partially_dependent and
350 : // in_new_space_list) and a State.
351 : class NodeState : public BitField<State, 0, 3> {};
352 : class IsIndependent : public BitField<bool, 3, 1> {};
353 : // The following two fields are mutually exclusive
354 : class IsActive : public BitField<bool, 4, 1> {};
355 : class IsInNewSpaceList : public BitField<bool, 5, 1> {};
356 : class NodeWeaknessType : public BitField<WeaknessType, 6, 2> {};
357 :
358 : uint8_t flags_;
359 :
360 : // Handle specific callback - might be a weak reference in disguise.
361 : WeakCallbackInfo<void>::Callback weak_callback_;
362 :
363 : // Provided data for callback. In FREE state, this is used for
364 : // the free list link.
365 : union {
366 : void* parameter;
367 : Node* next_free;
368 : } parameter_or_next_free_;
369 :
370 : DISALLOW_COPY_AND_ASSIGN(Node);
371 : };
372 :
373 :
374 85766 : class GlobalHandles::NodeBlock {
375 : public:
376 : static const int kSize = 256;
377 :
378 : explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
379 : : next_(next),
380 : used_nodes_(0),
381 : next_used_(nullptr),
382 : prev_used_(nullptr),
383 44524 : global_handles_(global_handles) {}
384 :
385 : void PutNodesOnFreeList(Node** first_free) {
386 11398144 : for (int i = kSize - 1; i >= 0; --i) {
387 11398144 : nodes_[i].Initialize(i, first_free);
388 : }
389 : }
390 :
391 : Node* node_at(int index) {
392 : DCHECK(0 <= index && index < kSize);
393 : return &nodes_[index];
394 : }
395 :
396 : void IncreaseUses() {
397 : DCHECK_LT(used_nodes_, kSize);
398 3446567 : if (used_nodes_++ == 0) {
399 65672 : NodeBlock* old_first = global_handles_->first_used_block_;
400 65672 : global_handles_->first_used_block_ = this;
401 65672 : next_used_ = old_first;
402 65672 : prev_used_ = nullptr;
403 65672 : if (old_first == nullptr) return;
404 4595 : old_first->prev_used_ = this;
405 : }
406 : }
407 :
408 2976461 : void DecreaseUses() {
409 : DCHECK_GT(used_nodes_, 0);
410 2976461 : if (--used_nodes_ == 0) {
411 55714 : if (next_used_ != nullptr) next_used_->prev_used_ = prev_used_;
412 55714 : if (prev_used_ != nullptr) prev_used_->next_used_ = next_used_;
413 55714 : if (this == global_handles_->first_used_block_) {
414 53622 : global_handles_->first_used_block_ = next_used_;
415 : }
416 : }
417 2976461 : }
418 :
419 : GlobalHandles* global_handles() { return global_handles_; }
420 :
421 : // Next block in the list of all blocks.
422 : NodeBlock* next() const { return next_; }
423 :
424 : // Next/previous block in the list of blocks with used nodes.
425 : NodeBlock* next_used() const { return next_used_; }
426 : NodeBlock* prev_used() const { return prev_used_; }
427 :
428 : private:
429 : Node nodes_[kSize];
430 : NodeBlock* const next_;
431 : int used_nodes_;
432 : NodeBlock* next_used_;
433 : NodeBlock* prev_used_;
434 : GlobalHandles* global_handles_;
435 : };
436 :
437 :
438 : GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
439 10 : return FindBlock()->global_handles();
440 : }
441 :
442 :
443 : GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
444 : intptr_t ptr = reinterpret_cast<intptr_t>(this);
445 6423038 : ptr = ptr - index_ * sizeof(Node);
446 6423038 : NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
447 : DCHECK(block->node_at(index_) == this);
448 : return block;
449 : }
450 :
451 :
452 3446567 : void GlobalHandles::Node::IncreaseBlockUses() {
453 3446567 : NodeBlock* node_block = FindBlock();
454 : node_block->IncreaseUses();
455 3446567 : GlobalHandles* global_handles = node_block->global_handles();
456 3446567 : global_handles->isolate()->counters()->global_handles()->Increment();
457 3446566 : global_handles->number_of_global_handles_++;
458 3446566 : }
459 :
460 :
461 2976461 : void GlobalHandles::Node::DecreaseBlockUses() {
462 2976461 : NodeBlock* node_block = FindBlock();
463 2976461 : GlobalHandles* global_handles = node_block->global_handles();
464 2976461 : parameter_or_next_free_.next_free = global_handles->first_free_;
465 2976461 : global_handles->first_free_ = this;
466 2976461 : node_block->DecreaseUses();
467 2976461 : global_handles->isolate()->counters()->global_handles()->Decrement();
468 2976461 : global_handles->number_of_global_handles_--;
469 2976461 : }
470 :
471 :
472 : class GlobalHandles::NodeIterator {
473 : public:
474 : explicit NodeIterator(GlobalHandles* global_handles)
475 : : block_(global_handles->first_used_block_),
476 373671 : index_(0) {}
477 :
478 : bool done() const { return block_ == nullptr; }
479 :
480 : Node* node() const {
481 : DCHECK(!done());
482 : return block_->node_at(index_);
483 : }
484 :
485 : void Advance() {
486 : DCHECK(!done());
487 61828864 : if (++index_ < NodeBlock::kSize) return;
488 : index_ = 0;
489 241519 : block_ = block_->next_used();
490 : }
491 :
492 : private:
493 : NodeBlock* block_;
494 : int index_;
495 :
496 : DISALLOW_COPY_AND_ASSIGN(NodeIterator);
497 : };
498 :
499 216 : class GlobalHandles::PendingPhantomCallbacksSecondPassTask
500 : : public v8::internal::CancelableTask {
501 : public:
502 : // Takes ownership of the contents of pending_phantom_callbacks, leaving it in
503 : // the same state it would be after a call to Clear().
504 72 : PendingPhantomCallbacksSecondPassTask(
505 : std::vector<PendingPhantomCallback>* pending_phantom_callbacks,
506 : Isolate* isolate)
507 72 : : CancelableTask(isolate), isolate_(isolate) {
508 : pending_phantom_callbacks_.swap(*pending_phantom_callbacks);
509 72 : }
510 :
511 288 : void RunInternal() override {
512 144 : TRACE_EVENT0("v8", "V8.GCPhantomHandleProcessingCallback");
513 : isolate()->heap()->CallGCPrologueCallbacks(
514 72 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
515 72 : InvokeSecondPassPhantomCallbacks(&pending_phantom_callbacks_, isolate());
516 : isolate()->heap()->CallGCEpilogueCallbacks(
517 72 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
518 72 : }
519 :
520 : Isolate* isolate() { return isolate_; }
521 :
522 : private:
523 : Isolate* isolate_;
524 : std::vector<PendingPhantomCallback> pending_phantom_callbacks_;
525 :
526 : DISALLOW_COPY_AND_ASSIGN(PendingPhantomCallbacksSecondPassTask);
527 : };
528 :
529 54999 : GlobalHandles::GlobalHandles(Isolate* isolate)
530 : : isolate_(isolate),
531 : number_of_global_handles_(0),
532 : first_block_(nullptr),
533 : first_used_block_(nullptr),
534 : first_free_(nullptr),
535 : post_gc_processing_count_(0),
536 164997 : number_of_phantom_handle_resets_(0) {}
537 :
538 53365 : GlobalHandles::~GlobalHandles() {
539 96248 : NodeBlock* block = first_block_;
540 149613 : while (block != nullptr) {
541 : NodeBlock* tmp = block->next();
542 42883 : delete block;
543 : block = tmp;
544 : }
545 53365 : first_block_ = nullptr;
546 53365 : }
547 :
548 :
549 3446567 : Handle<Object> GlobalHandles::Create(Object* value) {
550 3446567 : if (first_free_ == nullptr) {
551 89048 : first_block_ = new NodeBlock(this, first_block_);
552 : first_block_->PutNodesOnFreeList(&first_free_);
553 : }
554 : DCHECK_NOT_NULL(first_free_);
555 : // Take the first node in the free list.
556 3446567 : Node* result = first_free_;
557 4143169 : first_free_ = result->next_free();
558 3446567 : result->Acquire(value);
559 4143168 : if (isolate_->heap()->InNewSpace(value) &&
560 696602 : !result->is_in_new_space_list()) {
561 590381 : new_space_nodes_.push_back(result);
562 590381 : result->set_in_new_space_list(true);
563 : }
564 6893132 : return result->handle();
565 : }
566 :
567 :
568 10 : Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
569 : DCHECK_NOT_NULL(location);
570 20 : return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
571 : }
572 :
573 :
574 2976450 : void GlobalHandles::Destroy(Object** location) {
575 2976450 : if (location != nullptr) Node::FromLocation(location)->Release();
576 2976450 : }
577 :
578 :
579 : typedef v8::WeakCallbackInfo<void>::Callback GenericCallback;
580 :
581 :
582 740516 : void GlobalHandles::MakeWeak(Object** location, void* parameter,
583 : GenericCallback phantom_callback,
584 : v8::WeakCallbackType type) {
585 740516 : Node::FromLocation(location)->MakeWeak(parameter, phantom_callback, type);
586 740516 : }
587 :
588 11 : void GlobalHandles::MakeWeak(Object*** location_addr) {
589 11 : Node::FromLocation(*location_addr)->MakeWeak(location_addr);
590 11 : }
591 :
592 25 : void* GlobalHandles::ClearWeakness(Object** location) {
593 25 : return Node::FromLocation(location)->ClearWeakness();
594 : }
595 :
596 :
597 0 : void GlobalHandles::MarkIndependent(Object** location) {
598 : Node::FromLocation(location)->MarkIndependent();
599 0 : }
600 :
601 0 : bool GlobalHandles::IsIndependent(Object** location) {
602 0 : return Node::FromLocation(location)->is_independent();
603 : }
604 :
605 :
606 40 : bool GlobalHandles::IsNearDeath(Object** location) {
607 40 : return Node::FromLocation(location)->IsNearDeath();
608 : }
609 :
610 :
611 24 : bool GlobalHandles::IsWeak(Object** location) {
612 24 : return Node::FromLocation(location)->IsWeak();
613 : }
614 :
615 : DISABLE_CFI_PERF
616 176900 : void GlobalHandles::IterateWeakRoots(RootVisitor* v) {
617 11108576 : for (NodeIterator it(this); !it.done(); it.Advance()) {
618 11051776 : Node* node = it.node();
619 11051776 : if (node->IsWeakRetainer()) {
620 : // Pending weak phantom handles die immediately. Everything else survives.
621 337543 : if (node->IsPendingPhantomResetHandle()) {
622 : node->ResetPhantomHandle();
623 11 : ++number_of_phantom_handle_resets_;
624 337532 : } else if (node->IsPendingPhantomCallback()) {
625 : node->CollectPhantomCallbackData(isolate(),
626 240200 : &pending_phantom_callbacks_);
627 : } else {
628 217432 : v->VisitRootPointer(Root::kGlobalHandles, node->location());
629 : }
630 : }
631 : }
632 56800 : }
633 :
634 :
635 56800 : void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
636 11108576 : for (NodeIterator it(this); !it.done(); it.Advance()) {
637 22103552 : if (it.node()->IsWeak() && f(it.node()->location())) {
638 : it.node()->MarkPending();
639 : }
640 : }
641 56800 : }
642 :
643 29652 : void GlobalHandles::IterateNewSpaceStrongAndDependentRoots(RootVisitor* v) {
644 623281 : for (Node* node : new_space_nodes_) {
645 1542540 : if (node->IsStrongRetainer() ||
646 795870 : (node->IsWeakRetainer() && !node->is_independent() &&
647 : node->is_active())) {
648 538822 : v->VisitRootPointer(Root::kGlobalHandles, node->location());
649 : }
650 : }
651 29652 : }
652 :
653 0 : void GlobalHandles::IterateNewSpaceStrongAndDependentRootsAndIdentifyUnmodified(
654 : RootVisitor* v, size_t start, size_t end) {
655 0 : for (size_t i = start; i < end; ++i) {
656 0 : Node* node = new_space_nodes_[i];
657 0 : if (node->IsWeak() && !JSObject::IsUnmodifiedApiObject(node->location())) {
658 : node->set_active(true);
659 : }
660 0 : if (node->IsStrongRetainer() ||
661 0 : (node->IsWeakRetainer() && !node->is_independent() &&
662 : node->is_active())) {
663 0 : v->VisitRootPointer(Root::kGlobalHandles, node->location());
664 : }
665 : }
666 0 : }
667 :
668 29652 : void GlobalHandles::IdentifyWeakUnmodifiedObjects(
669 : WeakSlotCallback is_unmodified) {
670 623281 : for (Node* node : new_space_nodes_) {
671 563977 : if (node->IsWeak() && !is_unmodified(node->location())) {
672 : node->set_active(true);
673 : }
674 : }
675 29652 : }
676 :
677 :
678 29652 : void GlobalHandles::MarkNewSpaceWeakUnmodifiedObjectsPending(
679 : WeakSlotCallbackWithHeap is_unscavenged) {
680 623281 : for (Node* node : new_space_nodes_) {
681 : DCHECK(node->is_in_new_space_list());
682 1302505 : if ((node->is_independent() || !node->is_active()) && node->IsWeak() &&
683 17003 : is_unscavenged(isolate_->heap(), node->location())) {
684 : node->MarkPending();
685 : }
686 : }
687 29652 : }
688 :
689 32246 : void GlobalHandles::IterateNewSpaceWeakUnmodifiedRoots(RootVisitor* v) {
690 623281 : for (Node* node : new_space_nodes_) {
691 : DCHECK(node->is_in_new_space_list());
692 1285502 : if ((node->is_independent() || !node->is_active()) &&
693 : node->IsWeakRetainer()) {
694 : // Pending weak phantom handles die immediately. Everything else survives.
695 17003 : if (node->IsPendingPhantomResetHandle()) {
696 : node->ResetPhantomHandle();
697 0 : ++number_of_phantom_handle_resets_;
698 17003 : } else if (node->IsPendingPhantomCallback()) {
699 : node->CollectPhantomCallbackData(isolate(),
700 5188 : &pending_phantom_callbacks_);
701 : } else {
702 14409 : v->VisitRootPointer(Root::kGlobalHandles, node->location());
703 : }
704 : }
705 : }
706 29652 : }
707 :
708 87 : void GlobalHandles::InvokeSecondPassPhantomCallbacks(
709 : std::vector<PendingPhantomCallback>* callbacks, Isolate* isolate) {
710 451 : while (!callbacks->empty()) {
711 277 : auto callback = callbacks->back();
712 : callbacks->pop_back();
713 : DCHECK_NULL(callback.node());
714 : // Fire second pass callback
715 277 : callback.Invoke(isolate);
716 : }
717 87 : }
718 :
719 :
720 29652 : int GlobalHandles::PostScavengeProcessing(
721 : const int initial_post_gc_processing_count) {
722 : int freed_nodes = 0;
723 623281 : for (Node* node : new_space_nodes_) {
724 : DCHECK(node->is_in_new_space_list());
725 563977 : if (!node->IsRetainer()) {
726 : // Free nodes do not have weak callbacks. Do not use them to compute
727 : // the freed_nodes.
728 : continue;
729 : }
730 : // Skip dependent or unmodified handles. Their weak callbacks might expect
731 : // to be
732 : // called between two global garbage collection callbacks which
733 : // are not called for minor collections.
734 1092053 : if (!node->is_independent() && (node->is_active())) {
735 : node->set_active(false);
736 : continue;
737 : }
738 : node->set_active(false);
739 :
740 163800 : if (node->PostGarbageCollectionProcessing(isolate_)) {
741 0 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
742 : // Weak callback triggered another GC and another round of
743 : // PostGarbageCollection processing. The current node might
744 : // have been deleted in that round, so we need to bail out (or
745 : // restart the processing).
746 : return freed_nodes;
747 : }
748 : }
749 163800 : if (!node->IsRetainer()) {
750 0 : freed_nodes++;
751 : }
752 : }
753 : return freed_nodes;
754 : }
755 :
756 :
757 56800 : int GlobalHandles::PostMarkSweepProcessing(
758 : const int initial_post_gc_processing_count) {
759 : int freed_nodes = 0;
760 11058656 : for (NodeIterator it(this); !it.done(); it.Advance()) {
761 22003712 : if (!it.node()->IsRetainer()) {
762 : // Free nodes do not have weak callbacks. Do not use them to compute
763 : // the freed_nodes.
764 : continue;
765 : }
766 : it.node()->set_active(false);
767 1043397 : if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
768 112263 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
769 : // See the comment above.
770 : return freed_nodes;
771 : }
772 : }
773 1043397 : if (!it.node()->IsRetainer()) {
774 112258 : freed_nodes++;
775 : }
776 : }
777 56800 : return freed_nodes;
778 : }
779 :
780 :
781 86452 : void GlobalHandles::UpdateListOfNewSpaceNodes() {
782 : size_t last = 0;
783 1565361 : for (Node* node : new_space_nodes_) {
784 : DCHECK(node->is_in_new_space_list());
785 758824 : if (node->IsRetainer()) {
786 633633 : if (isolate_->heap()->InNewSpace(node->object())) {
787 722298 : new_space_nodes_[last++] = node;
788 361149 : isolate_->heap()->IncrementNodesCopiedInNewSpace();
789 : } else {
790 : node->set_in_new_space_list(false);
791 272484 : isolate_->heap()->IncrementNodesPromoted();
792 : }
793 : } else {
794 : node->set_in_new_space_list(false);
795 125191 : isolate_->heap()->IncrementNodesDiedInNewSpace();
796 : }
797 : }
798 : DCHECK_LE(last, new_space_nodes_.size());
799 86452 : new_space_nodes_.resize(last);
800 : new_space_nodes_.shrink_to_fit();
801 86452 : }
802 :
803 :
804 86452 : int GlobalHandles::DispatchPendingPhantomCallbacks(
805 122883 : bool synchronous_second_pass) {
806 : int freed_nodes = 0;
807 : std::vector<PendingPhantomCallback> second_pass_callbacks;
808 : {
809 : // The initial pass callbacks must simply clear the nodes.
810 295598 : for (auto callback : pending_phantom_callbacks_) {
811 : // Skip callbacks that have already been processed once.
812 122694 : if (callback.node() == nullptr) continue;
813 122694 : callback.Invoke(isolate());
814 122694 : if (callback.callback()) second_pass_callbacks.push_back(callback);
815 122694 : freed_nodes++;
816 : }
817 : }
818 : pending_phantom_callbacks_.clear();
819 86452 : if (!second_pass_callbacks.empty()) {
820 87 : if (FLAG_optimize_for_size || FLAG_predictable || synchronous_second_pass) {
821 : isolate()->heap()->CallGCPrologueCallbacks(
822 15 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
823 15 : InvokeSecondPassPhantomCallbacks(&second_pass_callbacks, isolate());
824 : isolate()->heap()->CallGCEpilogueCallbacks(
825 15 : GCType::kGCTypeProcessWeakCallbacks, kNoGCCallbackFlags);
826 : } else {
827 : auto task = new PendingPhantomCallbacksSecondPassTask(
828 72 : &second_pass_callbacks, isolate());
829 72 : V8::GetCurrentPlatform()->CallOnForegroundThread(
830 144 : reinterpret_cast<v8::Isolate*>(isolate()), task);
831 : }
832 : }
833 86451 : return freed_nodes;
834 : }
835 :
836 :
837 122971 : void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
838 : Data::Callback* callback_addr = nullptr;
839 122971 : if (node_ != nullptr) {
840 : // Initialize for first pass callback.
841 : DCHECK(node_->state() == Node::NEAR_DEATH);
842 122694 : callback_addr = &callback_;
843 : }
844 : Data data(reinterpret_cast<v8::Isolate*>(isolate), parameter_,
845 122971 : embedder_fields_, callback_addr);
846 122971 : Data::Callback callback = callback_;
847 122971 : callback_ = nullptr;
848 122971 : callback(data);
849 122971 : if (node_ != nullptr) {
850 : // Transition to second pass state.
851 : DCHECK(node_->state() == Node::FREE);
852 122694 : node_ = nullptr;
853 : }
854 122971 : }
855 :
856 :
857 86452 : int GlobalHandles::PostGarbageCollectionProcessing(
858 : GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
859 : // Process weak global handle callbacks. This must be done after the
860 : // GC is completely done, because the callbacks may invoke arbitrary
861 : // API functions.
862 : DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
863 86452 : const int initial_post_gc_processing_count = ++post_gc_processing_count_;
864 : int freed_nodes = 0;
865 : bool synchronous_second_pass =
866 86452 : (gc_callback_flags &
867 : (kGCCallbackFlagForced | kGCCallbackFlagCollectAllAvailableGarbage |
868 86452 : kGCCallbackFlagSynchronousPhantomCallbackProcessing)) != 0;
869 86452 : freed_nodes += DispatchPendingPhantomCallbacks(synchronous_second_pass);
870 86451 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
871 : // If the callbacks caused a nested GC, then return. See comment in
872 : // PostScavengeProcessing.
873 : return freed_nodes;
874 : }
875 86451 : if (Heap::IsYoungGenerationCollector(collector)) {
876 29652 : freed_nodes += PostScavengeProcessing(initial_post_gc_processing_count);
877 : } else {
878 56799 : freed_nodes += PostMarkSweepProcessing(initial_post_gc_processing_count);
879 : }
880 86452 : if (initial_post_gc_processing_count != post_gc_processing_count_) {
881 : // If the callbacks caused a nested GC, then return. See comment in
882 : // PostScavengeProcessing.
883 : return freed_nodes;
884 : }
885 86452 : if (initial_post_gc_processing_count == post_gc_processing_count_) {
886 86452 : UpdateListOfNewSpaceNodes();
887 : }
888 86452 : return freed_nodes;
889 : }
890 :
891 144144 : void GlobalHandles::IterateStrongRoots(RootVisitor* v) {
892 17217296 : for (NodeIterator it(this); !it.done(); it.Advance()) {
893 34146304 : if (it.node()->IsStrongRetainer()) {
894 1487881 : v->VisitRootPointer(Root::kGlobalHandles, it.node()->location());
895 : }
896 : }
897 144144 : }
898 :
899 :
900 : DISABLE_CFI_PERF
901 58785 : void GlobalHandles::IterateAllRoots(RootVisitor* v) {
902 11626145 : for (NodeIterator it(this); !it.done(); it.Advance()) {
903 23134720 : if (it.node()->IsRetainer()) {
904 1085244 : v->VisitRootPointer(Root::kGlobalHandles, it.node()->location());
905 : }
906 : }
907 58785 : }
908 :
909 : DISABLE_CFI_PERF
910 0 : void GlobalHandles::IterateAllNewSpaceRoots(RootVisitor* v) {
911 0 : for (Node* node : new_space_nodes_) {
912 0 : if (node->IsRetainer()) {
913 0 : v->VisitRootPointer(Root::kGlobalHandles, node->location());
914 : }
915 : }
916 0 : }
917 :
918 : DISABLE_CFI_PERF
919 0 : void GlobalHandles::IterateNewSpaceRoots(RootVisitor* v, size_t start,
920 : size_t end) {
921 0 : for (size_t i = start; i < end; ++i) {
922 0 : Node* node = new_space_nodes_[i];
923 0 : if (node->IsRetainer()) {
924 0 : v->VisitRootPointer(Root::kGlobalHandles, node->location());
925 : }
926 : }
927 0 : }
928 :
929 : DISABLE_CFI_PERF
930 0 : void GlobalHandles::ApplyPersistentHandleVisitor(
931 25 : v8::PersistentHandleVisitor* visitor, GlobalHandles::Node* node) {
932 25 : v8::Value* value = ToApi<v8::Value>(Handle<Object>(node->location()));
933 : visitor->VisitPersistentHandle(
934 : reinterpret_cast<v8::Persistent<v8::Value>*>(&value),
935 50 : node->wrapper_class_id());
936 0 : }
937 :
938 : DISABLE_CFI_PERF
939 324 : void GlobalHandles::IterateAllRootsWithClassIds(
940 : v8::PersistentHandleVisitor* visitor) {
941 83268 : for (NodeIterator it(this); !it.done(); it.Advance()) {
942 165888 : if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
943 : ApplyPersistentHandleVisitor(visitor, it.node());
944 : }
945 : }
946 324 : }
947 :
948 :
949 : DISABLE_CFI_PERF
950 5 : void GlobalHandles::IterateAllRootsInNewSpaceWithClassIds(
951 : v8::PersistentHandleVisitor* visitor) {
952 20 : for (Node* node : new_space_nodes_) {
953 10 : if (node->IsRetainer() && node->has_wrapper_class_id()) {
954 : ApplyPersistentHandleVisitor(visitor, node);
955 : }
956 : }
957 5 : }
958 :
959 :
960 : DISABLE_CFI_PERF
961 0 : void GlobalHandles::IterateWeakRootsInNewSpaceWithClassIds(
962 : v8::PersistentHandleVisitor* visitor) {
963 0 : for (Node* node : new_space_nodes_) {
964 0 : if (node->has_wrapper_class_id() && node->IsWeak()) {
965 : ApplyPersistentHandleVisitor(visitor, node);
966 : }
967 : }
968 0 : }
969 :
970 18 : void GlobalHandles::RecordStats(HeapStats* stats) {
971 18 : *stats->global_handle_count = 0;
972 18 : *stats->weak_global_handle_count = 0;
973 18 : *stats->pending_global_handle_count = 0;
974 18 : *stats->near_death_global_handle_count = 0;
975 18 : *stats->free_global_handle_count = 0;
976 18 : for (NodeIterator it(this); !it.done(); it.Advance()) {
977 0 : *stats->global_handle_count += 1;
978 0 : if (it.node()->state() == Node::WEAK) {
979 0 : *stats->weak_global_handle_count += 1;
980 0 : } else if (it.node()->state() == Node::PENDING) {
981 0 : *stats->pending_global_handle_count += 1;
982 0 : } else if (it.node()->state() == Node::NEAR_DEATH) {
983 0 : *stats->near_death_global_handle_count += 1;
984 0 : } else if (it.node()->state() == Node::FREE) {
985 0 : *stats->free_global_handle_count += 1;
986 : }
987 : }
988 18 : }
989 :
990 : #ifdef DEBUG
991 :
992 : void GlobalHandles::PrintStats() {
993 : int total = 0;
994 : int weak = 0;
995 : int pending = 0;
996 : int near_death = 0;
997 : int destroyed = 0;
998 :
999 : for (NodeIterator it(this); !it.done(); it.Advance()) {
1000 : total++;
1001 : if (it.node()->state() == Node::WEAK) weak++;
1002 : if (it.node()->state() == Node::PENDING) pending++;
1003 : if (it.node()->state() == Node::NEAR_DEATH) near_death++;
1004 : if (it.node()->state() == Node::FREE) destroyed++;
1005 : }
1006 :
1007 : PrintF("Global Handle Statistics:\n");
1008 : PrintF(" allocated memory = %" PRIuS "B\n", total * sizeof(Node));
1009 : PrintF(" # weak = %d\n", weak);
1010 : PrintF(" # pending = %d\n", pending);
1011 : PrintF(" # near_death = %d\n", near_death);
1012 : PrintF(" # free = %d\n", destroyed);
1013 : PrintF(" # total = %d\n", total);
1014 : }
1015 :
1016 :
1017 : void GlobalHandles::Print() {
1018 : PrintF("Global handles:\n");
1019 : for (NodeIterator it(this); !it.done(); it.Advance()) {
1020 : PrintF(" handle %p to %p%s\n",
1021 : reinterpret_cast<void*>(it.node()->location()),
1022 : reinterpret_cast<void*>(it.node()->object()),
1023 : it.node()->IsWeak() ? " (weak)" : "");
1024 : }
1025 : }
1026 :
1027 : #endif
1028 :
1029 53365 : void GlobalHandles::TearDown() {}
1030 :
1031 54999 : EternalHandles::EternalHandles() : size_(0) {
1032 109998 : for (unsigned i = 0; i < arraysize(singleton_handles_); i++) {
1033 54999 : singleton_handles_[i] = kInvalidIndex;
1034 : }
1035 54999 : }
1036 :
1037 :
1038 53365 : EternalHandles::~EternalHandles() {
1039 106893 : for (Object** block : blocks_) delete[] block;
1040 53365 : }
1041 :
1042 202771 : void EternalHandles::IterateAllRoots(RootVisitor* visitor) {
1043 202771 : int limit = size_;
1044 406066 : for (Object** block : blocks_) {
1045 : DCHECK_GT(limit, 0);
1046 : visitor->VisitRootPointers(Root::kEternalHandles, block,
1047 1048 : block + Min(limit, kSize));
1048 524 : limit -= kSize;
1049 : }
1050 202771 : }
1051 :
1052 29652 : void EternalHandles::IterateNewSpaceRoots(RootVisitor* visitor) {
1053 74244 : for (int index : new_space_indices_) {
1054 29880 : visitor->VisitRootPointer(Root::kEternalHandles, GetLocation(index));
1055 : }
1056 29652 : }
1057 :
1058 :
1059 86452 : void EternalHandles::PostGarbageCollectionProcessing(Heap* heap) {
1060 : size_t last = 0;
1061 213795 : for (int index : new_space_indices_) {
1062 81782 : if (heap->InNewSpace(*GetLocation(index))) {
1063 40842 : new_space_indices_[last++] = index;
1064 : }
1065 : }
1066 : DCHECK_LE(last, new_space_indices_.size());
1067 86452 : new_space_indices_.resize(last);
1068 86452 : }
1069 :
1070 :
1071 20558 : void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
1072 : DCHECK_EQ(kInvalidIndex, *index);
1073 41116 : if (object == nullptr) return;
1074 : DCHECK_NE(isolate->heap()->the_hole_value(), object);
1075 20558 : int block = size_ >> kShift;
1076 20558 : int offset = size_ & kMask;
1077 : // need to resize
1078 20558 : if (offset == 0) {
1079 163 : Object** next_block = new Object*[kSize];
1080 163 : Object* the_hole = isolate->heap()->the_hole_value();
1081 : MemsetPointer(next_block, the_hole, kSize);
1082 20721 : blocks_.push_back(next_block);
1083 : }
1084 : DCHECK_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
1085 41116 : blocks_[block][offset] = object;
1086 20558 : if (isolate->heap()->InNewSpace(object)) {
1087 20475 : new_space_indices_.push_back(size_);
1088 : }
1089 20558 : *index = size_++;
1090 : }
1091 :
1092 :
1093 : } // namespace internal
1094 : } // namespace v8
|