OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 | 98 |
99 void Initialize(int index, Node** first_free) { | 99 void Initialize(int index, Node** first_free) { |
100 index_ = static_cast<uint8_t>(index); | 100 index_ = static_cast<uint8_t>(index); |
101 ASSERT(static_cast<int>(index_) == index); | 101 ASSERT(static_cast<int>(index_) == index); |
102 set_state(FREE); | 102 set_state(FREE); |
103 set_in_new_space_list(false); | 103 set_in_new_space_list(false); |
104 parameter_or_next_free_.next_free = *first_free; | 104 parameter_or_next_free_.next_free = *first_free; |
105 *first_free = this; | 105 *first_free = this; |
106 } | 106 } |
107 | 107 |
108 void Acquire(Object* object, GlobalHandles* global_handles) { | 108 void Acquire(Object* object) { |
109 ASSERT(state() == FREE); | 109 ASSERT(state() == FREE); |
110 object_ = object; | 110 object_ = object; |
111 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 111 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
112 set_independent(false); | 112 set_independent(false); |
113 set_partially_dependent(false); | 113 set_partially_dependent(false); |
114 set_state(NORMAL); | 114 set_state(NORMAL); |
115 parameter_or_next_free_.parameter = NULL; | 115 parameter_or_next_free_.parameter = NULL; |
116 near_death_callback_ = NULL; | 116 near_death_callback_ = NULL; |
117 IncreaseBlockUses(global_handles); | 117 IncreaseBlockUses(); |
118 } | 118 } |
119 | 119 |
120 void Release(GlobalHandles* global_handles) { | 120 void Release() { |
121 ASSERT(state() != FREE); | 121 ASSERT(state() != FREE); |
122 set_state(FREE); | 122 set_state(FREE); |
123 #ifdef ENABLE_EXTRA_CHECKS | 123 #ifdef ENABLE_EXTRA_CHECKS |
124 // Zap the values for eager trapping. | 124 // Zap the values for eager trapping. |
125 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); | 125 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); |
126 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; | 126 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; |
127 set_independent(false); | 127 set_independent(false); |
128 set_partially_dependent(false); | 128 set_partially_dependent(false); |
129 near_death_callback_ = NULL; | 129 near_death_callback_ = NULL; |
130 #endif | 130 #endif |
131 parameter_or_next_free_.next_free = global_handles->first_free_; | 131 DecreaseBlockUses(); |
132 global_handles->first_free_ = this; | |
133 DecreaseBlockUses(global_handles); | |
134 } | 132 } |
135 | 133 |
136 // Object slot accessors. | 134 // Object slot accessors. |
137 Object* object() const { return object_; } | 135 Object* object() const { return object_; } |
138 Object** location() { return &object_; } | 136 Object** location() { return &object_; } |
139 Handle<Object> handle() { return Handle<Object>(location()); } | 137 Handle<Object> handle() { return Handle<Object>(location()); } |
140 | 138 |
141 // Wrapper class ID accessors. | 139 // Wrapper class ID accessors. |
142 bool has_wrapper_class_id() const { | 140 bool has_wrapper_class_id() const { |
143 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; | 141 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 near_death_callback_ = near_death_callback; | 247 near_death_callback_ = near_death_callback; |
250 } | 248 } |
251 } | 249 } |
252 | 250 |
253 void ClearWeakness(GlobalHandles* global_handles) { | 251 void ClearWeakness(GlobalHandles* global_handles) { |
254 ASSERT(state() != FREE); | 252 ASSERT(state() != FREE); |
255 set_state(NORMAL); | 253 set_state(NORMAL); |
256 set_parameter(NULL); | 254 set_parameter(NULL); |
257 } | 255 } |
258 | 256 |
259 bool PostGarbageCollectionProcessing(Isolate* isolate, | 257 bool PostGarbageCollectionProcessing(Isolate* isolate) { |
260 GlobalHandles* global_handles) { | |
261 if (state() != Node::PENDING) return false; | 258 if (state() != Node::PENDING) return false; |
262 if (near_death_callback_ == NULL) { | 259 if (near_death_callback_ == NULL) { |
263 Release(global_handles); | 260 Release(); |
264 return false; | 261 return false; |
265 } | 262 } |
266 void* par = parameter(); | 263 void* par = parameter(); |
267 set_state(NEAR_DEATH); | 264 set_state(NEAR_DEATH); |
268 set_parameter(NULL); | 265 set_parameter(NULL); |
269 | 266 |
270 v8::Persistent<v8::Value> object = ToApi<v8::Value>(handle()); | 267 v8::Persistent<v8::Value> object = ToApi<v8::Value>(handle()); |
271 { | 268 { |
272 // Check that we are not passing a finalized external string to | 269 // Check that we are not passing a finalized external string to |
273 // the callback. | 270 // the callback. |
(...skipping 18 matching lines...) Expand all Loading... |
292 } | 289 } |
293 } | 290 } |
294 // Absence of explicit cleanup or revival of weak handle | 291 // Absence of explicit cleanup or revival of weak handle |
295 // in most of the cases would lead to memory leak. | 292 // in most of the cases would lead to memory leak. |
296 ASSERT(state() != NEAR_DEATH); | 293 ASSERT(state() != NEAR_DEATH); |
297 return true; | 294 return true; |
298 } | 295 } |
299 | 296 |
300 private: | 297 private: |
301 inline NodeBlock* FindBlock(); | 298 inline NodeBlock* FindBlock(); |
302 inline void IncreaseBlockUses(GlobalHandles* global_handles); | 299 inline void IncreaseBlockUses(); |
303 inline void DecreaseBlockUses(GlobalHandles* global_handles); | 300 inline void DecreaseBlockUses(); |
304 | 301 |
305 // Storage for object pointer. | 302 // Storage for object pointer. |
306 // Placed first to avoid offset computation. | 303 // Placed first to avoid offset computation. |
307 Object* object_; | 304 Object* object_; |
308 | 305 |
309 // Next word stores class_id, index, state, and independent. | 306 // Next word stores class_id, index, state, and independent. |
310 // Note: the most aligned fields should go first. | 307 // Note: the most aligned fields should go first. |
311 | 308 |
312 // Wrapper class ID. | 309 // Wrapper class ID. |
313 uint16_t class_id_; | 310 uint16_t class_id_; |
(...skipping 22 matching lines...) Expand all Loading... |
336 } parameter_or_next_free_; | 333 } parameter_or_next_free_; |
337 | 334 |
338 DISALLOW_COPY_AND_ASSIGN(Node); | 335 DISALLOW_COPY_AND_ASSIGN(Node); |
339 }; | 336 }; |
340 | 337 |
341 | 338 |
342 class GlobalHandles::NodeBlock { | 339 class GlobalHandles::NodeBlock { |
343 public: | 340 public: |
344 static const int kSize = 256; | 341 static const int kSize = 256; |
345 | 342 |
346 explicit NodeBlock(NodeBlock* next) | 343 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) |
347 : next_(next), used_nodes_(0), next_used_(NULL), prev_used_(NULL) {} | 344 : next_(next), |
| 345 used_nodes_(0), |
| 346 next_used_(NULL), |
| 347 prev_used_(NULL), |
| 348 global_handles_(global_handles) {} |
348 | 349 |
349 void PutNodesOnFreeList(Node** first_free) { | 350 void PutNodesOnFreeList(Node** first_free) { |
350 for (int i = kSize - 1; i >= 0; --i) { | 351 for (int i = kSize - 1; i >= 0; --i) { |
351 nodes_[i].Initialize(i, first_free); | 352 nodes_[i].Initialize(i, first_free); |
352 } | 353 } |
353 } | 354 } |
354 | 355 |
355 Node* node_at(int index) { | 356 Node* node_at(int index) { |
356 ASSERT(0 <= index && index < kSize); | 357 ASSERT(0 <= index && index < kSize); |
357 return &nodes_[index]; | 358 return &nodes_[index]; |
358 } | 359 } |
359 | 360 |
360 void IncreaseUses(GlobalHandles* global_handles) { | 361 void IncreaseUses() { |
361 ASSERT(used_nodes_ < kSize); | 362 ASSERT(used_nodes_ < kSize); |
362 if (used_nodes_++ == 0) { | 363 if (used_nodes_++ == 0) { |
363 NodeBlock* old_first = global_handles->first_used_block_; | 364 NodeBlock* old_first = global_handles_->first_used_block_; |
364 global_handles->first_used_block_ = this; | 365 global_handles_->first_used_block_ = this; |
365 next_used_ = old_first; | 366 next_used_ = old_first; |
366 prev_used_ = NULL; | 367 prev_used_ = NULL; |
367 if (old_first == NULL) return; | 368 if (old_first == NULL) return; |
368 old_first->prev_used_ = this; | 369 old_first->prev_used_ = this; |
369 } | 370 } |
370 } | 371 } |
371 | 372 |
372 void DecreaseUses(GlobalHandles* global_handles) { | 373 void DecreaseUses() { |
373 ASSERT(used_nodes_ > 0); | 374 ASSERT(used_nodes_ > 0); |
374 if (--used_nodes_ == 0) { | 375 if (--used_nodes_ == 0) { |
375 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_; | 376 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_; |
376 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_; | 377 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_; |
377 if (this == global_handles->first_used_block_) { | 378 if (this == global_handles_->first_used_block_) { |
378 global_handles->first_used_block_ = next_used_; | 379 global_handles_->first_used_block_ = next_used_; |
379 } | 380 } |
380 } | 381 } |
381 } | 382 } |
382 | 383 |
| 384 GlobalHandles* global_handles() { return global_handles_; } |
| 385 |
383 // Next block in the list of all blocks. | 386 // Next block in the list of all blocks. |
384 NodeBlock* next() const { return next_; } | 387 NodeBlock* next() const { return next_; } |
385 | 388 |
386 // Next/previous block in the list of blocks with used nodes. | 389 // Next/previous block in the list of blocks with used nodes. |
387 NodeBlock* next_used() const { return next_used_; } | 390 NodeBlock* next_used() const { return next_used_; } |
388 NodeBlock* prev_used() const { return prev_used_; } | 391 NodeBlock* prev_used() const { return prev_used_; } |
389 | 392 |
390 private: | 393 private: |
391 Node nodes_[kSize]; | 394 Node nodes_[kSize]; |
392 NodeBlock* const next_; | 395 NodeBlock* const next_; |
393 int used_nodes_; | 396 int used_nodes_; |
394 NodeBlock* next_used_; | 397 NodeBlock* next_used_; |
395 NodeBlock* prev_used_; | 398 NodeBlock* prev_used_; |
| 399 GlobalHandles* global_handles_; |
396 }; | 400 }; |
397 | 401 |
398 | 402 |
399 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { | 403 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { |
400 intptr_t ptr = reinterpret_cast<intptr_t>(this); | 404 intptr_t ptr = reinterpret_cast<intptr_t>(this); |
401 ptr = ptr - index_ * sizeof(Node); | 405 ptr = ptr - index_ * sizeof(Node); |
402 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); | 406 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); |
403 ASSERT(block->node_at(index_) == this); | 407 ASSERT(block->node_at(index_) == this); |
404 return block; | 408 return block; |
405 } | 409 } |
406 | 410 |
407 | 411 |
408 void GlobalHandles::Node::IncreaseBlockUses(GlobalHandles* global_handles) { | 412 void GlobalHandles::Node::IncreaseBlockUses() { |
409 FindBlock()->IncreaseUses(global_handles); | 413 NodeBlock* node_block = FindBlock(); |
| 414 node_block->IncreaseUses(); |
| 415 GlobalHandles* global_handles = node_block->global_handles(); |
| 416 global_handles->isolate()->counters()->global_handles()->Increment(); |
| 417 global_handles->number_of_global_handles_++; |
410 } | 418 } |
411 | 419 |
412 | 420 |
413 void GlobalHandles::Node::DecreaseBlockUses(GlobalHandles* global_handles) { | 421 void GlobalHandles::Node::DecreaseBlockUses() { |
414 FindBlock()->DecreaseUses(global_handles); | 422 NodeBlock* node_block = FindBlock(); |
| 423 GlobalHandles* global_handles = node_block->global_handles(); |
| 424 parameter_or_next_free_.next_free = global_handles->first_free_; |
| 425 global_handles->first_free_ = this; |
| 426 node_block->DecreaseUses(); |
| 427 global_handles->isolate()->counters()->global_handles()->Decrement(); |
| 428 global_handles->number_of_global_handles_--; |
415 } | 429 } |
416 | 430 |
417 | 431 |
418 class GlobalHandles::NodeIterator { | 432 class GlobalHandles::NodeIterator { |
419 public: | 433 public: |
420 explicit NodeIterator(GlobalHandles* global_handles) | 434 explicit NodeIterator(GlobalHandles* global_handles) |
421 : block_(global_handles->first_used_block_), | 435 : block_(global_handles->first_used_block_), |
422 index_(0) {} | 436 index_(0) {} |
423 | 437 |
424 bool done() const { return block_ == NULL; } | 438 bool done() const { return block_ == NULL; } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 while (block != NULL) { | 472 while (block != NULL) { |
459 NodeBlock* tmp = block->next(); | 473 NodeBlock* tmp = block->next(); |
460 delete block; | 474 delete block; |
461 block = tmp; | 475 block = tmp; |
462 } | 476 } |
463 first_block_ = NULL; | 477 first_block_ = NULL; |
464 } | 478 } |
465 | 479 |
466 | 480 |
467 Handle<Object> GlobalHandles::Create(Object* value) { | 481 Handle<Object> GlobalHandles::Create(Object* value) { |
468 isolate_->counters()->global_handles()->Increment(); | |
469 number_of_global_handles_++; | |
470 if (first_free_ == NULL) { | 482 if (first_free_ == NULL) { |
471 first_block_ = new NodeBlock(first_block_); | 483 first_block_ = new NodeBlock(this, first_block_); |
472 first_block_->PutNodesOnFreeList(&first_free_); | 484 first_block_->PutNodesOnFreeList(&first_free_); |
473 } | 485 } |
474 ASSERT(first_free_ != NULL); | 486 ASSERT(first_free_ != NULL); |
475 // Take the first node in the free list. | 487 // Take the first node in the free list. |
476 Node* result = first_free_; | 488 Node* result = first_free_; |
477 first_free_ = result->next_free(); | 489 first_free_ = result->next_free(); |
478 result->Acquire(value, this); | 490 result->Acquire(value); |
479 if (isolate_->heap()->InNewSpace(value) && | 491 if (isolate_->heap()->InNewSpace(value) && |
480 !result->is_in_new_space_list()) { | 492 !result->is_in_new_space_list()) { |
481 new_space_nodes_.Add(result); | 493 new_space_nodes_.Add(result); |
482 result->set_in_new_space_list(true); | 494 result->set_in_new_space_list(true); |
483 } | 495 } |
484 return result->handle(); | 496 return result->handle(); |
485 } | 497 } |
486 | 498 |
487 | 499 |
488 void GlobalHandles::Destroy(Object** location) { | 500 void GlobalHandles::Destroy(Object** location) { |
489 isolate_->counters()->global_handles()->Decrement(); | 501 if (location != NULL) Node::FromLocation(location)->Release(); |
490 number_of_global_handles_--; | |
491 if (location == NULL) return; | |
492 Node::FromLocation(location)->Release(this); | |
493 } | 502 } |
494 | 503 |
495 | 504 |
496 void GlobalHandles::MakeWeak(Object** location, | 505 void GlobalHandles::MakeWeak(Object** location, |
497 void* parameter, | 506 void* parameter, |
498 RevivableCallback weak_reference_callback, | 507 RevivableCallback weak_reference_callback, |
499 NearDeathCallback near_death_callback) { | 508 NearDeathCallback near_death_callback) { |
500 ASSERT((weak_reference_callback == NULL) != (near_death_callback == NULL)); | 509 ASSERT((weak_reference_callback == NULL) != (near_death_callback == NULL)); |
501 Node::FromLocation(location)->MakeWeak(this, | 510 Node::FromLocation(location)->MakeWeak(this, |
502 parameter, | 511 parameter, |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 for (int i = 0; i < new_space_nodes_.length(); ++i) { | 655 for (int i = 0; i < new_space_nodes_.length(); ++i) { |
647 Node* node = new_space_nodes_[i]; | 656 Node* node = new_space_nodes_[i]; |
648 ASSERT(node->is_in_new_space_list()); | 657 ASSERT(node->is_in_new_space_list()); |
649 // Skip dependent handles. Their weak callbacks might expect to be | 658 // Skip dependent handles. Their weak callbacks might expect to be |
650 // called between two global garbage collection callbacks which | 659 // called between two global garbage collection callbacks which |
651 // are not called for minor collections. | 660 // are not called for minor collections. |
652 if (!node->is_independent() && !node->is_partially_dependent()) { | 661 if (!node->is_independent() && !node->is_partially_dependent()) { |
653 continue; | 662 continue; |
654 } | 663 } |
655 node->clear_partially_dependent(); | 664 node->clear_partially_dependent(); |
656 if (node->PostGarbageCollectionProcessing(isolate_, this)) { | 665 if (node->PostGarbageCollectionProcessing(isolate_)) { |
657 if (initial_post_gc_processing_count != post_gc_processing_count_) { | 666 if (initial_post_gc_processing_count != post_gc_processing_count_) { |
658 // Weak callback triggered another GC and another round of | 667 // Weak callback triggered another GC and another round of |
659 // PostGarbageCollection processing. The current node might | 668 // PostGarbageCollection processing. The current node might |
660 // have been deleted in that round, so we need to bail out (or | 669 // have been deleted in that round, so we need to bail out (or |
661 // restart the processing). | 670 // restart the processing). |
662 return next_gc_likely_to_collect_more; | 671 return next_gc_likely_to_collect_more; |
663 } | 672 } |
664 } | 673 } |
665 if (!node->IsRetainer()) { | 674 if (!node->IsRetainer()) { |
666 next_gc_likely_to_collect_more = true; | 675 next_gc_likely_to_collect_more = true; |
667 } | 676 } |
668 } | 677 } |
669 } else { | 678 } else { |
670 for (NodeIterator it(this); !it.done(); it.Advance()) { | 679 for (NodeIterator it(this); !it.done(); it.Advance()) { |
671 it.node()->clear_partially_dependent(); | 680 it.node()->clear_partially_dependent(); |
672 if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) { | 681 if (it.node()->PostGarbageCollectionProcessing(isolate_)) { |
673 if (initial_post_gc_processing_count != post_gc_processing_count_) { | 682 if (initial_post_gc_processing_count != post_gc_processing_count_) { |
674 // See the comment above. | 683 // See the comment above. |
675 return next_gc_likely_to_collect_more; | 684 return next_gc_likely_to_collect_more; |
676 } | 685 } |
677 } | 686 } |
678 if (!it.node()->IsRetainer()) { | 687 if (!it.node()->IsRetainer()) { |
679 next_gc_likely_to_collect_more = true; | 688 next_gc_likely_to_collect_more = true; |
680 } | 689 } |
681 } | 690 } |
682 } | 691 } |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 } | 1021 } |
1013 } | 1022 } |
1014 object_group_connections_.Clear(); | 1023 object_group_connections_.Clear(); |
1015 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); | 1024 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); |
1016 retainer_infos_.Clear(); | 1025 retainer_infos_.Clear(); |
1017 implicit_ref_connections_.Clear(); | 1026 implicit_ref_connections_.Clear(); |
1018 } | 1027 } |
1019 | 1028 |
1020 | 1029 |
1021 } } // namespace v8::internal | 1030 } } // namespace v8::internal |
OLD | NEW |