Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(274)

Side by Side Diff: src/global-handles.cc

Issue 21042004: Make GlobalHandle::NodeBlock deletable (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: added weak callbacks to test Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 class GlobalHandles::Node { 50 class GlobalHandles::Node {
51 public: 51 public:
52 // State transition diagram: 52 // State transition diagram:
53 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE } 53 // FREE -> NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, FREE }
54 enum State { 54 enum State {
55 FREE = 0, 55 FREE = 0,
56 NORMAL, // Normal global handle. 56 NORMAL, // Normal global handle.
57 WEAK, // Flagged as weak but not yet finalized. 57 WEAK, // Flagged as weak but not yet finalized.
58 PENDING, // Has been recognized as only reachable by weak handles. 58 PENDING, // Has been recognized as only reachable by weak handles.
59 NEAR_DEATH // Callback has informed the handle is near death. 59 NEAR_DEATH, // Callback has informed the handle is near death.
60
61 LAST_STATE = NEAR_DEATH
Michael Starzinger 2013/08/01 12:29:02 Let just rename this to STATE_COUNT or NUMBER_OF_S
60 }; 62 };
61 63
62 // Maps handle location (slot) to the containing node. 64 // Maps handle location (slot) to the containing node.
63 static Node* FromLocation(Object** location) { 65 static Node* FromLocation(Object** location) {
64 ASSERT(OFFSET_OF(Node, object_) == 0); 66 ASSERT(OFFSET_OF(Node, object_) == 0);
65 return reinterpret_cast<Node*>(location); 67 return reinterpret_cast<Node*>(location);
66 } 68 }
67 69
68 Node() { 70 Node() {
69 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset); 71 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
(...skipping 16 matching lines...) Expand all
86 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 88 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
87 index_ = 0; 89 index_ = 0;
88 set_independent(false); 90 set_independent(false);
89 set_partially_dependent(false); 91 set_partially_dependent(false);
90 set_in_new_space_list(false); 92 set_in_new_space_list(false);
91 parameter_or_next_free_.next_free = NULL; 93 parameter_or_next_free_.next_free = NULL;
92 weak_reference_callback_ = NULL; 94 weak_reference_callback_ = NULL;
93 } 95 }
94 #endif 96 #endif
95 97
96 void Initialize(int index, Node** first_free) { 98 void Initialize(int index, Node* first_free) {
97 index_ = static_cast<uint8_t>(index); 99 index_ = static_cast<uint8_t>(index);
98 ASSERT(static_cast<int>(index_) == index); 100 ASSERT(static_cast<int>(index_) == index);
99 set_state(FREE); 101 set_state(FREE);
100 set_in_new_space_list(false); 102 set_in_new_space_list(false);
101 parameter_or_next_free_.next_free = *first_free; 103 parameter_or_next_free_.next_free = first_free;
102 *first_free = this;
103 } 104 }
104 105
105 void Acquire(Object* object) { 106 void Acquire(Object* object) {
106 ASSERT(state() == FREE); 107 ASSERT(state() == FREE);
107 object_ = object; 108 object_ = object;
108 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 109 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
109 set_independent(false); 110 set_independent(false);
110 set_partially_dependent(false); 111 set_partially_dependent(false);
111 set_state(NORMAL); 112 set_state(NORMAL);
112 parameter_or_next_free_.parameter = NULL; 113 parameter_or_next_free_.parameter = NULL;
113 weak_reference_callback_ = NULL; 114 weak_reference_callback_ = NULL;
114 IncreaseBlockUses();
115 } 115 }
116 116
117 void Release() { 117 void Release() {
118 ASSERT(state() != FREE); 118 ASSERT(state() != FREE);
119 set_state(FREE); 119 set_state(FREE);
120 #ifdef ENABLE_EXTRA_CHECKS 120 #ifdef ENABLE_EXTRA_CHECKS
121 // Zap the values for eager trapping. 121 // Zap the values for eager trapping.
122 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); 122 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
123 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 123 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
124 set_independent(false); 124 set_independent(false);
125 set_partially_dependent(false); 125 set_partially_dependent(false);
126 weak_reference_callback_ = NULL; 126 weak_reference_callback_ = NULL;
127 #endif 127 #endif
128 DecreaseBlockUses(); 128 ReleaseFromBlock();
129 } 129 }
130 130
131 // Object slot accessors. 131 // Object slot accessors.
132 Object* object() const { return object_; } 132 Object* object() const { return object_; }
133 Object** location() { return &object_; } 133 Object** location() { return &object_; }
134 Handle<Object> handle() { return Handle<Object>(location()); } 134 Handle<Object> handle() { return Handle<Object>(location()); }
135 135
136 // Wrapper class ID accessors. 136 // Wrapper class ID accessors.
137 bool has_wrapper_class_id() const { 137 bool has_wrapper_class_id() const {
138 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; 138 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 } 197 }
198 198
199 void MarkPartiallyDependent() { 199 void MarkPartiallyDependent() {
200 ASSERT(state() != FREE); 200 ASSERT(state() != FREE);
201 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) { 201 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
202 set_partially_dependent(true); 202 set_partially_dependent(true);
203 } 203 }
204 } 204 }
205 void clear_partially_dependent() { set_partially_dependent(false); } 205 void clear_partially_dependent() { set_partially_dependent(false); }
206 206
207 // Callback accessor.
208 // TODO(svenpanne) Re-enable or nuke later.
209 // WeakReferenceCallback callback() { return callback_; }
210
211 // Callback parameter accessors. 207 // Callback parameter accessors.
212 void set_parameter(void* parameter) { 208 void set_parameter(void* parameter) {
213 ASSERT(state() != FREE); 209 ASSERT(state() != FREE);
214 parameter_or_next_free_.parameter = parameter; 210 parameter_or_next_free_.parameter = parameter;
215 } 211 }
216 void* parameter() const { 212 void* parameter() const {
217 ASSERT(state() != FREE); 213 ASSERT(state() != FREE);
218 return parameter_or_next_free_.parameter; 214 return parameter_or_next_free_.parameter;
219 } 215 }
220 216
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 } 265 }
270 // Absence of explicit cleanup or revival of weak handle 266 // Absence of explicit cleanup or revival of weak handle
271 // in most of the cases would lead to memory leak. 267 // in most of the cases would lead to memory leak.
272 ASSERT(state() != NEAR_DEATH); 268 ASSERT(state() != NEAR_DEATH);
273 return true; 269 return true;
274 } 270 }
275 271
276 private: 272 private:
277 inline NodeBlock* FindBlock(); 273 inline NodeBlock* FindBlock();
278 inline GlobalHandles* GetGlobalHandles(); 274 inline GlobalHandles* GetGlobalHandles();
279 inline void IncreaseBlockUses(); 275 inline void ReleaseFromBlock();
280 inline void DecreaseBlockUses();
281 276
282 // Storage for object pointer. 277 // Storage for object pointer.
283 // Placed first to avoid offset computation. 278 // Placed first to avoid offset computation.
284 Object* object_; 279 Object* object_;
285 280
286 // Next word stores class_id, index, state, and independent. 281 // Next word stores class_id, index, state, and independent.
287 // Note: the most aligned fields should go first. 282 // Note: the most aligned fields should go first.
288 283
289 // Wrapper class ID. 284 // Wrapper class ID.
290 uint16_t class_id_; 285 uint16_t class_id_;
(...skipping 21 matching lines...) Expand all
312 } parameter_or_next_free_; 307 } parameter_or_next_free_;
313 308
314 DISALLOW_COPY_AND_ASSIGN(Node); 309 DISALLOW_COPY_AND_ASSIGN(Node);
315 }; 310 };
316 311
317 312
318 class GlobalHandles::NodeBlock { 313 class GlobalHandles::NodeBlock {
319 public: 314 public:
320 static const int kSize = 256; 315 static const int kSize = 256;
321 316
322 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) 317 explicit NodeBlock(GlobalHandles* global_handles)
323 : next_(next), 318 : used_nodes_(0),
324 used_nodes_(0), 319 first_free_(NULL),
325 next_used_(NULL), 320 next_block_(NULL),
326 prev_used_(NULL), 321 prev_block_(NULL),
327 global_handles_(global_handles) {} 322 global_handles_(global_handles) {
328 323 // Initialize nodes
329 void PutNodesOnFreeList(Node** first_free) { 324 Node* first_free = first_free_;
330 for (int i = kSize - 1; i >= 0; --i) { 325 for (int i = kSize - 1; i >= 0; --i) {
331 nodes_[i].Initialize(i, first_free); 326 nodes_[i].Initialize(i, first_free);
332 } 327 first_free = &nodes_[i];
333 } 328 }
329 first_free_ = first_free;
330 // Link into global_handles
331 ASSERT(global_handles->first_non_full_block_ == NULL);
332 global_handles->first_non_full_block_ = this;
333 global_handles->number_of_blocks_++;
334 if (global_handles->first_block_ == NULL) {
335 ASSERT(global_handles->last_block_ == NULL);
336 global_handles->first_block_ = this;
337 global_handles->last_block_ = this;
338 return;
339 }
340 ASSERT(global_handles->last_block_ != NULL);
341 prev_block_ = global_handles->last_block_;
342 prev_block_->next_block_ = this;
343 global_handles->last_block_ = this;
344 }
345
346 Node* Acquire(Object* o) {
347 ASSERT(used_nodes_ < kSize);
348 ASSERT(first_free_ != NULL);
349 ASSERT(global_handles_->first_non_full_block_ == this);
350 // Remove from free list
351 Node* node = first_free_;
352 first_free_ = node->next_free();
353 // Increment counters
354 global_handles_->isolate()->counters()->global_handles()->Increment();
355 global_handles_->number_of_global_handles_++;
356 // Initialize node with value
357 node->Acquire(o);
358 // Move block out of first_non_full_block_ if it becomes full
359 bool now_full = ++used_nodes_ == kSize;
360 if (now_full) {
361 global_handles_->first_non_full_block_ = next_block_;
362 }
363 return node;
364 }
365
366 void Release(Node* node) {
367 ASSERT(used_nodes_ > 0);
368 // Add to free list
369 node->set_next_free(first_free_);
370 first_free_ = node;
371 // Decrement counters
372 global_handles_->isolate()->counters()->global_handles()->Decrement();
373 global_handles_->number_of_global_handles_--;
374 // Move this block to first_non_full_block_ if necessary
375 bool was_full = used_nodes_-- == kSize;
376 if (!was_full) return;
377 ASSERT(first_free_->next_free() == NULL);
378 ASSERT(global_handles_->first_non_full_block_ != this);
379 // Simple case: last block becomes non full. Just mark.
380 if (next_block_ == NULL) {
381 ASSERT(global_handles_->last_block_ == this);
382 ASSERT(global_handles_->first_non_full_block_ == NULL);
383 global_handles_->first_non_full_block_ = this;
384 return;
385 }
386 ASSERT(global_handles_->last_block_ != this);
387 // Unlink prev_block_ and next_block_
388 if (prev_block_ == NULL) {
389 // First block becomes non full
390 ASSERT(global_handles_->first_block_ == this);
391 global_handles_->first_block_ = next_block_;
392 next_block_->prev_block_ = NULL;
393 } else {
394 ASSERT(global_handles_->first_block_ != this);
395 prev_block_->next_block_ = next_block_;
396 next_block_->prev_block_ = prev_block_;
397 }
398 // Relink into first_non_full_block_ position
399 if (global_handles_->first_non_full_block_ == NULL) {
400 // Link into last position.
401 next_block_ = NULL;
402 prev_block_ = global_handles_->last_block_;
403 ASSERT(prev_block_->next_block_ == NULL);
404 prev_block_->next_block_ = this;
405 global_handles_->last_block_ = this;
406 } else {
407 next_block_ = global_handles_->first_non_full_block_;
408 prev_block_ = next_block_->prev_block_;
409 next_block_->prev_block_ = this;
410 if (prev_block_ == NULL) {
411 // link into first position
412 ASSERT(global_handles_->first_block_ == next_block_);
413 global_handles_->first_block_ = this;
414 } else {
415 ASSERT(global_handles_->first_block_ != next_block_);
416 prev_block_->next_block_ = this;
417 }
418 }
419 // Update first_non_full_block_
420 global_handles_->first_non_full_block_ = this;
421 }
422
423 static void SortBlocks(GlobalHandles* global_handles);
424 static void PruneBlocks(GlobalHandles* global_handles);
425 // Needed for quicksort
426 static int CompareBlocks(const void* a, const void* b);
334 427
335 Node* node_at(int index) { 428 Node* node_at(int index) {
336 ASSERT(0 <= index && index < kSize); 429 ASSERT(0 <= index && index < kSize);
337 return &nodes_[index]; 430 return &nodes_[index];
338 } 431 }
339 432
340 void IncreaseUses() { 433 #ifdef DEBUG
341 ASSERT(used_nodes_ < kSize); 434 int LengthOfFreeList() {
342 if (used_nodes_++ == 0) { 435 int count = 0;
343 NodeBlock* old_first = global_handles_->first_used_block_; 436 Node* node = first_free_;
344 global_handles_->first_used_block_ = this; 437 while (node != NULL) {
345 next_used_ = old_first; 438 count++;
346 prev_used_ = NULL; 439 node = node->next_free();
347 if (old_first == NULL) return; 440 }
348 old_first->prev_used_ = this; 441 return count;
349 } 442 }
350 } 443 #endif
351 444
352 void DecreaseUses() { 445 bool IsUnused() { return used_nodes_ == 0; }
353 ASSERT(used_nodes_ > 0);
354 if (--used_nodes_ == 0) {
355 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
356 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
357 if (this == global_handles_->first_used_block_) {
358 global_handles_->first_used_block_ = next_used_;
359 }
360 }
361 }
362 446
363 GlobalHandles* global_handles() { return global_handles_; } 447 GlobalHandles* global_handles() { return global_handles_; }
364 448 int used_nodes() const { return used_nodes_; }
365 // Next block in the list of all blocks. 449 NodeBlock* next_block() const { return next_block_; }
366 NodeBlock* next() const { return next_; } 450 NodeBlock* prev_block() const { return prev_block_; }
367
368 // Next/previous block in the list of blocks with used nodes.
369 NodeBlock* next_used() const { return next_used_; }
370 NodeBlock* prev_used() const { return prev_used_; }
371 451
372 private: 452 private:
373 Node nodes_[kSize]; 453 Node nodes_[kSize];
374 NodeBlock* const next_;
375 int used_nodes_; 454 int used_nodes_;
376 NodeBlock* next_used_; 455 Node* first_free_;
377 NodeBlock* prev_used_; 456 NodeBlock* next_block_;
457 NodeBlock* prev_block_;
378 GlobalHandles* global_handles_; 458 GlobalHandles* global_handles_;
379 }; 459 };
380 460
381 461
462 #ifdef DEBUG
463 void GlobalHandles::VerifyBlockInvariants() {
464 int number_of_blocks = 0;
465 int number_of_handles = 0;
466 NodeBlock* first_non_full_block = NULL;
467 NodeBlock* block = first_block_;
468 NodeBlock* prev_block = NULL;
469 while (block != NULL) {
470 number_of_blocks++;
471 int used_nodes = block->used_nodes();
472 number_of_handles += used_nodes;
473 int unused_nodes = block->LengthOfFreeList();
474 ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize);
475 if (first_non_full_block != NULL) {
476 ASSERT_LT(used_nodes, NodeBlock::kSize);
477 } else if (used_nodes < NodeBlock::kSize) {
478 first_non_full_block = block;
479 } else {
480 ASSERT_EQ(used_nodes, NodeBlock::kSize);
481 }
482 prev_block = block;
483 block = block->next_block();
484 }
485 ASSERT_EQ(prev_block, last_block_);
486 ASSERT_EQ(number_of_handles, number_of_global_handles_);
487 ASSERT_EQ(number_of_blocks, number_of_blocks_);
488 ASSERT_EQ(first_non_full_block, first_non_full_block_);
489 }
490 #endif
491
492
493 int GlobalHandles::NodeBlock::CompareBlocks(const void* a, const void* b) {
494 const NodeBlock* block_a =
495 *reinterpret_cast<const NodeBlock**>(reinterpret_cast<uintptr_t>(a));
496 const NodeBlock* block_b =
497 *reinterpret_cast<const NodeBlock**>(reinterpret_cast<uintptr_t>(b));
498 if (block_a->used_nodes_ > block_b->used_nodes_) return -1;
499 if (block_a->used_nodes_ == block_b->used_nodes_) return 0;
500 return 1;
501 }
502
503
504 void GlobalHandles::NodeBlock::SortBlocks(GlobalHandles* global_handles) {
505 int number_of_blocks = global_handles->number_of_blocks_;
506 // Always sort at least 2 blocks
507 if (number_of_blocks <= 1) return;
508 // Build array of blocks
509 ScopedVector<NodeBlock*> blocks(number_of_blocks);
510 {
511 NodeBlock* block = global_handles->first_block_;
512 for (int i = 0; block != NULL; i++) {
513 blocks[i] = block;
514 block = block->next_block();
515 }
516 }
517 // Sort blocks
518 qsort(blocks.start(), number_of_blocks, sizeof(blocks[0]), CompareBlocks);
519 // Relink blocks
520 NodeBlock* first_non_full_block = NULL;
521 {
522 NodeBlock* first_block = blocks[0];
523 global_handles->first_block_ = first_block;
524 first_block->prev_block_ = NULL;
525 first_block->next_block_ = blocks[1];
526 if (first_block->used_nodes_ < kSize) first_non_full_block = first_block;
527 }
528 for (int i = 1; i < number_of_blocks-1; i++) {
529 NodeBlock* block = blocks[i];
530 block->prev_block_ = blocks[i-1];
531 block->next_block_ = blocks[i+1];
532 if (first_non_full_block == NULL && block->used_nodes_ < kSize) {
533 first_non_full_block = block;
534 }
535 }
536 {
537 NodeBlock* last_block = blocks[number_of_blocks-1];
538 global_handles->last_block_ = last_block;
539 last_block->prev_block_ = blocks[number_of_blocks-2];
540 last_block->next_block_ = NULL;
541 if (first_non_full_block == NULL && last_block->used_nodes_ < kSize) {
542 first_non_full_block = last_block;
543 }
544 }
545 global_handles->first_non_full_block_ = first_non_full_block;
546 }
547
548
549 void GlobalHandles::NodeBlock::PruneBlocks(GlobalHandles* global_handles) {
550 static const double kUnusedPercentage = 0.30;
551 static const double kUsedPercentage = 1.30;
552 ASSERT(global_handles->last_block_ != NULL);
553 // Have at least one block available for deletion.
554 int total_slots = global_handles->number_of_blocks_*NodeBlock::kSize;
Michael Starzinger 2013/08/01 12:29:02 nit: Whitespace around operators. Here and several
555 const int total_used = global_handles->number_of_global_handles_;
556 const int target_unused = static_cast<int>(Max(
557 total_used*kUsedPercentage,
558 total_slots*kUnusedPercentage));
559 NodeBlock* block = global_handles->last_block_;
560 int blocks_deleted = 0;
561 while (block->IsUnused()) {
562 // Not worth deleting
563 if (total_slots - total_used < target_unused) break;
564 // Don't delete only remaining block
565 if (block->prev_block() == NULL) break;
566 // Delete
567 NodeBlock* tmp = block;
568 block = block->prev_block();
569 total_slots -= NodeBlock::kSize;
570 delete tmp;
571 blocks_deleted++;
572 }
573 if (blocks_deleted == 0) return;
574 block->next_block_ = NULL;
575 global_handles->last_block_ = block;
576 global_handles->number_of_blocks_ -= blocks_deleted;
577 }
578
579
580 void GlobalHandles::SortBlocks(bool shouldPrune) {
581 #ifdef DEBUG
582 VerifyBlockInvariants();
583 #endif
584 // Nothing to sort or prune
585 if (first_non_full_block_ == NULL || first_block_ == last_block_) return;
586 NodeBlock::SortBlocks(this);
587 #ifdef DEBUG
588 VerifyBlockInvariants();
589 #endif
590 if (!shouldPrune) return;
591 NodeBlock::PruneBlocks(this);
592 #ifdef DEBUG
593 VerifyBlockInvariants();
594 #endif
595 }
596
597
382 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { 598 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
383 return FindBlock()->global_handles(); 599 return FindBlock()->global_handles();
384 } 600 }
385 601
386 602
387 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { 603 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
388 intptr_t ptr = reinterpret_cast<intptr_t>(this); 604 intptr_t ptr = reinterpret_cast<intptr_t>(this);
389 ptr = ptr - index_ * sizeof(Node); 605 ptr = ptr - index_ * sizeof(Node);
390 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); 606 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
391 ASSERT(block->node_at(index_) == this); 607 ASSERT(block->node_at(index_) == this);
392 return block; 608 return block;
393 } 609 }
394 610
395 611
396 void GlobalHandles::Node::IncreaseBlockUses() { 612 void GlobalHandles::Node::ReleaseFromBlock() {
397 NodeBlock* node_block = FindBlock(); 613 FindBlock()->Release(this);
398 node_block->IncreaseUses();
399 GlobalHandles* global_handles = node_block->global_handles();
400 global_handles->isolate()->counters()->global_handles()->Increment();
401 global_handles->number_of_global_handles_++;
402 }
403
404
405 void GlobalHandles::Node::DecreaseBlockUses() {
406 NodeBlock* node_block = FindBlock();
407 GlobalHandles* global_handles = node_block->global_handles();
408 parameter_or_next_free_.next_free = global_handles->first_free_;
409 global_handles->first_free_ = this;
410 node_block->DecreaseUses();
411 global_handles->isolate()->counters()->global_handles()->Decrement();
412 global_handles->number_of_global_handles_--;
413 } 614 }
414 615
415 616
416 class GlobalHandles::NodeIterator { 617 class GlobalHandles::NodeIterator {
417 public: 618 public:
418 explicit NodeIterator(GlobalHandles* global_handles) 619 explicit NodeIterator(GlobalHandles* global_handles)
419 : block_(global_handles->first_used_block_), 620 : block_(global_handles->first_block_),
420 index_(0) {} 621 index_(0) {
622 SkipUnused();
623 }
421 624
422 bool done() const { return block_ == NULL; } 625 bool done() const { return block_ == NULL; }
423 626
424 Node* node() const { 627 Node* node() const {
425 ASSERT(!done()); 628 ASSERT(!done());
426 return block_->node_at(index_); 629 return block_->node_at(index_);
427 } 630 }
428 631
429 void Advance() { 632 void Advance() {
430 ASSERT(!done()); 633 ASSERT(!done());
431 if (++index_ < NodeBlock::kSize) return; 634 if (++index_ < NodeBlock::kSize) return;
432 index_ = 0; 635 index_ = 0;
433 block_ = block_->next_used(); 636 block_ = block_->next_block();
637 SkipUnused();
434 } 638 }
435 639
640 static const int kCountArraySize = Node::LAST_STATE + 1;
Michael Starzinger 2013/08/01 12:29:02 This constant is obsolete, see comment at the top
641 typedef int CountArray[kCountArraySize];
642 static int CollectStats(GlobalHandles* global_handles, CountArray counts);
643
436 private: 644 private:
645 inline void SkipUnused() {
646 while (block_ != NULL && block_->IsUnused()) block_ = block_->next_block();
647 }
648
437 NodeBlock* block_; 649 NodeBlock* block_;
438 int index_; 650 int index_;
439 651
440 DISALLOW_COPY_AND_ASSIGN(NodeIterator); 652 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
441 }; 653 };
442 654
443 655
656 int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles,
657 CountArray counts) {
658 for (int i = 0; i < kCountArraySize; i++) {
659 counts[i] = 0;
660 }
661 int total = 0;
662 for (NodeIterator it(global_handles); !it.done(); it.Advance()) {
663 total++;
664 Node::State state = it.node()->state();
665 ASSERT(state >= 0 && state < kCountArraySize);
666 counts[state]++;
667 }
668 // NodeIterator skips empty blocks
669 int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total;
670 total += skipped;
671 counts[Node::FREE] += total;
672 return total;
673 }
674
675
444 GlobalHandles::GlobalHandles(Isolate* isolate) 676 GlobalHandles::GlobalHandles(Isolate* isolate)
445 : isolate_(isolate), 677 : isolate_(isolate),
678 number_of_blocks_(0),
446 number_of_global_handles_(0), 679 number_of_global_handles_(0),
447 first_block_(NULL), 680 first_block_(NULL),
448 first_used_block_(NULL), 681 last_block_(NULL),
449 first_free_(NULL), 682 first_non_full_block_(NULL),
450 post_gc_processing_count_(0), 683 post_gc_processing_count_(0),
451 object_group_connections_(kObjectGroupConnectionsCapacity) {} 684 object_group_connections_(kObjectGroupConnectionsCapacity) {}
452 685
453 686
454 GlobalHandles::~GlobalHandles() { 687 GlobalHandles::~GlobalHandles() {
455 NodeBlock* block = first_block_; 688 NodeBlock* block = first_block_;
456 while (block != NULL) { 689 while (block != NULL) {
457 NodeBlock* tmp = block->next(); 690 NodeBlock* tmp = block->next_block();
458 delete block; 691 delete block;
459 block = tmp; 692 block = tmp;
460 } 693 }
461 first_block_ = NULL; 694 first_block_ = NULL;
462 } 695 }
463 696
464 697
465 Handle<Object> GlobalHandles::Create(Object* value) { 698 Handle<Object> GlobalHandles::Create(Object* value) {
466 if (first_free_ == NULL) { 699 if (first_non_full_block_ == NULL) new NodeBlock(this);
467 first_block_ = new NodeBlock(this, first_block_); 700 ASSERT(first_non_full_block_ != NULL);
468 first_block_->PutNodesOnFreeList(&first_free_);
469 }
470 ASSERT(first_free_ != NULL);
471 // Take the first node in the free list. 701 // Take the first node in the free list.
472 Node* result = first_free_; 702 Node* result = first_non_full_block_->Acquire(value);
473 first_free_ = result->next_free();
474 result->Acquire(value);
475 if (isolate_->heap()->InNewSpace(value) && 703 if (isolate_->heap()->InNewSpace(value) &&
476 !result->is_in_new_space_list()) { 704 !result->is_in_new_space_list()) {
477 new_space_nodes_.Add(result); 705 new_space_nodes_.Add(result);
478 result->set_in_new_space_list(true); 706 result->set_in_new_space_list(true);
479 } 707 }
480 return result->handle(); 708 return result->handle();
481 } 709 }
482 710
483 711
484 void GlobalHandles::Destroy(Object** location) { 712 void GlobalHandles::Destroy(Object** location) {
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 } else { 919 } else {
692 node->set_in_new_space_list(false); 920 node->set_in_new_space_list(false);
693 tracer->increment_nodes_promoted(); 921 tracer->increment_nodes_promoted();
694 } 922 }
695 } else { 923 } else {
696 node->set_in_new_space_list(false); 924 node->set_in_new_space_list(false);
697 tracer->increment_nodes_died_in_new_space(); 925 tracer->increment_nodes_died_in_new_space();
698 } 926 }
699 } 927 }
700 new_space_nodes_.Rewind(last); 928 new_space_nodes_.Rewind(last);
929 bool shouldPruneBlocks = collector != SCAVENGER;
930 SortBlocks(shouldPruneBlocks);
701 return next_gc_likely_to_collect_more; 931 return next_gc_likely_to_collect_more;
702 } 932 }
703 933
704 934
705 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { 935 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
706 for (NodeIterator it(this); !it.done(); it.Advance()) { 936 for (NodeIterator it(this); !it.done(); it.Advance()) {
707 if (it.node()->IsStrongRetainer()) { 937 if (it.node()->IsStrongRetainer()) {
708 v->VisitPointer(it.node()->location()); 938 v->VisitPointer(it.node()->location());
709 } 939 }
710 } 940 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 if (it.node()->IsWeakRetainer() && 988 if (it.node()->IsWeakRetainer() &&
759 it.node()->object()->IsJSGlobalObject()) { 989 it.node()->object()->IsJSGlobalObject()) {
760 count++; 990 count++;
761 } 991 }
762 } 992 }
763 return count; 993 return count;
764 } 994 }
765 995
766 996
767 void GlobalHandles::RecordStats(HeapStats* stats) { 997 void GlobalHandles::RecordStats(HeapStats* stats) {
768 *stats->global_handle_count = 0; 998 NodeIterator::CountArray counts;
769 *stats->weak_global_handle_count = 0; 999 int total = NodeIterator::CollectStats(this, counts);
770 *stats->pending_global_handle_count = 0; 1000 *stats->global_handle_count = total;
771 *stats->near_death_global_handle_count = 0; 1001 *stats->weak_global_handle_count = counts[Node::WEAK];
772 *stats->free_global_handle_count = 0; 1002 *stats->pending_global_handle_count = counts[Node::PENDING];
773 for (NodeIterator it(this); !it.done(); it.Advance()) { 1003 *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH];
774 *stats->global_handle_count += 1; 1004 *stats->free_global_handle_count = counts[Node::FREE];
775 if (it.node()->state() == Node::WEAK) {
776 *stats->weak_global_handle_count += 1;
777 } else if (it.node()->state() == Node::PENDING) {
778 *stats->pending_global_handle_count += 1;
779 } else if (it.node()->state() == Node::NEAR_DEATH) {
780 *stats->near_death_global_handle_count += 1;
781 } else if (it.node()->state() == Node::FREE) {
782 *stats->free_global_handle_count += 1;
783 }
784 }
785 } 1005 }
786 1006
1007
787 #ifdef DEBUG 1008 #ifdef DEBUG
788 1009
789 void GlobalHandles::PrintStats() { 1010 void GlobalHandles::PrintStats() {
790 int total = 0; 1011 NodeIterator::CountArray counts;
791 int weak = 0; 1012 int total = NodeIterator::CollectStats(this, counts);
792 int pending = 0; 1013 size_t total_consumed = sizeof(NodeBlock) * number_of_blocks_;
793 int near_death = 0;
794 int destroyed = 0;
795
796 for (NodeIterator it(this); !it.done(); it.Advance()) {
797 total++;
798 if (it.node()->state() == Node::WEAK) weak++;
799 if (it.node()->state() == Node::PENDING) pending++;
800 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
801 if (it.node()->state() == Node::FREE) destroyed++;
802 }
803
804 PrintF("Global Handle Statistics:\n"); 1014 PrintF("Global Handle Statistics:\n");
805 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); 1015 PrintF(" allocated blocks = %d\n", number_of_blocks_);
806 PrintF(" # weak = %d\n", weak); 1016 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed);
807 PrintF(" # pending = %d\n", pending); 1017 PrintF(" # normal = %d\n", counts[Node::NORMAL]);
808 PrintF(" # near_death = %d\n", near_death); 1018 PrintF(" # weak = %d\n", counts[Node::WEAK]);
809 PrintF(" # free = %d\n", destroyed); 1019 PrintF(" # pending = %d\n", counts[Node::PENDING]);
1020 PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]);
1021 PrintF(" # free = %d\n", counts[Node::FREE]);
810 PrintF(" # total = %d\n", total); 1022 PrintF(" # total = %d\n", total);
811 } 1023 }
812 1024
813 1025
814 void GlobalHandles::Print() { 1026 void GlobalHandles::Print() {
815 PrintF("Global handles:\n"); 1027 PrintF("Global handles:\n");
816 for (NodeIterator it(this); !it.done(); it.Advance()) { 1028 for (NodeIterator it(this); !it.done(); it.Advance()) {
817 PrintF(" handle %p to %p%s\n", 1029 PrintF(" handle %p to %p%s\n",
818 reinterpret_cast<void*>(it.node()->location()), 1030 reinterpret_cast<void*>(it.node()->location()),
819 reinterpret_cast<void*>(it.node()->object()), 1031 reinterpret_cast<void*>(it.node()->object()),
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 } 1224 }
1013 } 1225 }
1014 object_group_connections_.Clear(); 1226 object_group_connections_.Clear();
1015 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); 1227 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
1016 retainer_infos_.Clear(); 1228 retainer_infos_.Clear();
1017 implicit_ref_connections_.Clear(); 1229 implicit_ref_connections_.Clear();
1018 } 1230 }
1019 1231
1020 1232
1021 } } // namespace v8::internal 1233 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698