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

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: addressed comments 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
« no previous file with comments | « src/global-handles.h ('k') | test/cctest/cctest.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 NUMBER_OF_STATES
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 17 matching lines...) Expand all
308 // the free list link. 303 // the free list link.
309 union { 304 union {
310 void* parameter; 305 void* parameter;
311 Node* next_free; 306 Node* next_free;
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::BlockListIterator {
314 public:
315 explicit inline BlockListIterator(BlockList* anchor)
316 : anchor_(anchor), current_(anchor->next()) {
317 ASSERT(anchor->IsAnchor());
318 }
319 inline BlockList* block() const {
320 ASSERT(!done());
321 return current_;
322 }
323 inline bool done() const {
324 ASSERT_EQ(anchor_ == current_, current_->IsAnchor());
325 return anchor_ == current_;
326 }
327 inline void Advance() {
328 ASSERT(!done());
329 current_ = current_->next();
330 }
331
332 private:
333 BlockList* const anchor_;
334 BlockList* current_;
335 DISALLOW_COPY_AND_ASSIGN(BlockListIterator);
336 };
337
338
339 GlobalHandles::BlockList::BlockList()
340 : prev_block_(this),
341 next_block_(this),
342 first_free_(NULL),
343 used_nodes_(0) {}
344
345
346 void GlobalHandles::BlockList::InsertAsNext(BlockList* const block) {
347 ASSERT(block != this);
348 ASSERT(!block->IsAnchor());
349 ASSERT(block->IsDetached());
350 block->prev_block_ = this;
351 block->next_block_ = next_block_;
352 next_block_->prev_block_ = block;
353 next_block_ = block;
354 ASSERT(!IsDetached());
355 ASSERT(!block->IsDetached());
356 }
357
358
359 void GlobalHandles::BlockList::Detach() {
360 ASSERT(!IsAnchor());
361 ASSERT(!IsDetached());
362 prev_block_->next_block_ = next_block_;
363 next_block_->prev_block_ = prev_block_;
364 prev_block_ = this;
365 next_block_ = this;
366 ASSERT(IsDetached());
367 }
368
369
370 bool GlobalHandles::BlockList::HasAtLeastLength(int length) {
371 ASSERT(IsAnchor());
372 ASSERT(length > 0);
373 for (BlockListIterator it(this); !it.done(); it.Advance()) {
374 if (--length <= 0) return true;
375 }
376 return false;
377 }
378
379
380 #ifdef DEBUG
381 int GlobalHandles::BlockList::LengthOfFreeList() {
382 int count = 0;
383 Node* node = first_free_;
384 while (node != NULL) {
385 count++;
386 node = node->next_free();
387 }
388 return count;
389 }
390 #endif
391
392
393 int GlobalHandles::BlockList::CompareBlocks(const void* a, const void* b) {
394 const BlockList* block_a =
395 *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(a));
396 const BlockList* block_b =
397 *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(b));
398 if (block_a->used_nodes() > block_b->used_nodes()) return -1;
399 if (block_a->used_nodes() == block_b->used_nodes()) return 0;
400 return 1;
401 }
402
403
404 class GlobalHandles::NodeBlock : public BlockList {
319 public: 405 public:
320 static const int kSize = 256; 406 static const int kSize = 256;
321 407
322 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next) 408 explicit NodeBlock(GlobalHandles* global_handles)
323 : next_(next), 409 : global_handles_(global_handles) {
324 used_nodes_(0), 410 // Initialize nodes
325 next_used_(NULL), 411 Node* first_free = first_free_;
326 prev_used_(NULL),
327 global_handles_(global_handles) {}
328
329 void PutNodesOnFreeList(Node** first_free) {
330 for (int i = kSize - 1; i >= 0; --i) { 412 for (int i = kSize - 1; i >= 0; --i) {
331 nodes_[i].Initialize(i, first_free); 413 nodes_[i].Initialize(i, first_free);
414 first_free = &nodes_[i];
415 }
416 first_free_ = first_free;
417 ASSERT(!IsAnchor());
418 // Link into global_handles
419 ASSERT(global_handles->non_full_blocks_.IsDetached());
420 global_handles->non_full_blocks_.InsertAsHead(this);
421 global_handles->number_of_blocks_++;
422 }
423
424 Node* Acquire(Object* o) {
425 ASSERT(used_nodes_ < kSize);
426 ASSERT(first_free_ != NULL);
427 ASSERT(global_handles_->non_full_blocks_.next() == this);
428 // Remove from free list
429 Node* node = first_free_;
430 first_free_ = node->next_free();
431 // Increment counters
432 global_handles_->isolate()->counters()->global_handles()->Increment();
433 global_handles_->number_of_global_handles_++;
434 // Initialize node with value
435 node->Acquire(o);
436 bool now_full = ++used_nodes_ == kSize;
437 ASSERT_EQ(now_full, first_free_ == NULL);
438 if (now_full) {
439 // Move block to tail of non_full_blocks_
440 Detach();
441 global_handles_->full_blocks_.InsertAsTail(this);
442 }
443 return node;
444 }
445
446 void Release(Node* node) {
447 ASSERT(used_nodes_ > 0);
448 // Add to free list
449 node->set_next_free(first_free_);
450 first_free_ = node;
451 // Decrement counters
452 global_handles_->isolate()->counters()->global_handles()->Decrement();
453 global_handles_->number_of_global_handles_--;
454 bool was_full = used_nodes_-- == kSize;
455 ASSERT_EQ(was_full, first_free_->next_free() == NULL);
456 if (was_full) {
457 // Move this block to head of non_full_blocks_
458 Detach();
459 global_handles_->non_full_blocks_.InsertAsHead(this);
332 } 460 }
333 } 461 }
334 462
335 Node* node_at(int index) { 463 Node* node_at(int index) {
336 ASSERT(0 <= index && index < kSize); 464 ASSERT(0 <= index && index < kSize);
337 return &nodes_[index]; 465 return &nodes_[index];
338 } 466 }
339 467
340 void IncreaseUses() {
341 ASSERT(used_nodes_ < kSize);
342 if (used_nodes_++ == 0) {
343 NodeBlock* old_first = global_handles_->first_used_block_;
344 global_handles_->first_used_block_ = this;
345 next_used_ = old_first;
346 prev_used_ = NULL;
347 if (old_first == NULL) return;
348 old_first->prev_used_ = this;
349 }
350 }
351
352 void DecreaseUses() {
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
363 GlobalHandles* global_handles() { return global_handles_; } 468 GlobalHandles* global_handles() { return global_handles_; }
364 469
365 // Next block in the list of all blocks. 470 static NodeBlock* Cast(BlockList* block_list) {
366 NodeBlock* next() const { return next_; } 471 ASSERT(!block_list->IsAnchor());
367 472 return static_cast<NodeBlock*>(block_list);
368 // Next/previous block in the list of blocks with used nodes. 473 }
369 NodeBlock* next_used() const { return next_used_; } 474
370 NodeBlock* prev_used() const { return prev_used_; } 475 static NodeBlock* From(Node* node, uint8_t index) {
476 uintptr_t ptr = reinterpret_cast<uintptr_t>(node - index);
477 ptr -= OFFSET_OF(NodeBlock, nodes_);
478 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
479 ASSERT(block->node_at(index) == node);
480 return block;
481 }
371 482
372 private: 483 private:
373 Node nodes_[kSize]; 484 Node nodes_[kSize];
374 NodeBlock* const next_;
375 int used_nodes_;
376 NodeBlock* next_used_;
377 NodeBlock* prev_used_;
378 GlobalHandles* global_handles_; 485 GlobalHandles* global_handles_;
379 }; 486 };
380 487
381 488
489 void GlobalHandles::BlockList::SortBlocks(GlobalHandles* global_handles,
490 bool prune) {
491 // Always sort at least 2 blocks
492 if (!global_handles->non_full_blocks_.HasAtLeastLength(2)) return;
493 // build a vector that could contain the upper bound of the block count
494 int number_of_blocks = global_handles->block_count();
495 // Build array of blocks and update number_of_blocks to actual count
496 ScopedVector<BlockList*> blocks(number_of_blocks);
497 {
498 int i = 0;
499 BlockList* anchor = &global_handles->non_full_blocks_;
500 for (BlockListIterator it(anchor); !it.done(); it.Advance()) {
501 blocks[i++] = it.block();
502 }
503 number_of_blocks = i;
504 }
505 // Nothing to do.
506 if (number_of_blocks <= 1) return;
507 // Sort blocks
508 qsort(blocks.start(), number_of_blocks, sizeof(blocks[0]), CompareBlocks);
509 // Prune empties
510 if (prune) {
511 static const double kUnusedPercentage = 0.30;
512 static const double kUsedPercentage = 1.30;
513 int total_slots = global_handles->number_of_blocks_ * NodeBlock::kSize;
514 const int total_used = global_handles->number_of_global_handles_;
515 const int target_unused = static_cast<int>(Max(
516 total_used * kUsedPercentage,
517 total_slots * kUnusedPercentage));
518 // Reverse through empty blocks. Note: always leave one block free.
519 int blocks_deleted = 0;
520 for (int i = number_of_blocks - 1; i > 0 && blocks[i]->IsUnused(); i--) {
521 // Not worth deleting
522 if (total_slots - total_used < target_unused) break;
523 blocks[i]->Detach();
524 delete blocks[i];
525 blocks_deleted++;
526 total_slots -= NodeBlock::kSize;
527 }
528 global_handles->number_of_blocks_ -= blocks_deleted;
529 number_of_blocks -= blocks_deleted;
530 }
531 // Relink all blocks
532 for (int i = 0; i < number_of_blocks; i++) {
533 blocks[i]->Detach();
534 global_handles->non_full_blocks_.InsertAsTail(blocks[i]);
535 }
536 #ifdef DEBUG
537 // Check sorting
538 BlockList* anchor = &global_handles->non_full_blocks_;
539 int last_size = NodeBlock::kSize;
540 for (BlockListIterator it(anchor); !it.done(); it.Advance()) {
541 ASSERT(it.block()->used_nodes() <= last_size);
542 last_size = it.block()->used_nodes();
543 }
544 #endif
545 }
546
547
548 #ifdef DEBUG
549 void GlobalHandles::VerifyBlockInvariants() {
550 int number_of_blocks = 0;
551 int number_of_handles = 0;
552 for (int i = 0; i < kAllAnchorsSize; i++) {
553 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) {
554 BlockList* block = it.block();
555 number_of_blocks++;
556 int used_nodes = block->used_nodes();
557 number_of_handles += used_nodes;
558 int unused_nodes = block->LengthOfFreeList();
559 ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize);
560 if (all_anchors_[i] == &full_blocks_) {
561 ASSERT_EQ(NodeBlock::kSize, used_nodes);
562 } else {
563 ASSERT_NE(NodeBlock::kSize, used_nodes);
564 }
565 }
566 }
567 ASSERT_EQ(number_of_handles, number_of_global_handles_);
568 ASSERT_EQ(number_of_blocks, number_of_blocks_);
569 }
570 #endif
571
572
573 void GlobalHandles::SortBlocks(bool shouldPrune) {
574 #ifdef DEBUG
575 VerifyBlockInvariants();
576 #endif
577 BlockList::SortBlocks(this, shouldPrune);
578 #ifdef DEBUG
579 VerifyBlockInvariants();
580 #endif
581 }
582
583
382 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { 584 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
383 return FindBlock()->global_handles(); 585 return FindBlock()->global_handles();
384 } 586 }
385 587
386 588
387 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { 589 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
388 intptr_t ptr = reinterpret_cast<intptr_t>(this); 590 return NodeBlock::From(this, index_);
389 ptr = ptr - index_ * sizeof(Node); 591 }
390 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr); 592
391 ASSERT(block->node_at(index_) == this); 593
392 return block; 594 void GlobalHandles::Node::ReleaseFromBlock() {
393 } 595 FindBlock()->Release(this);
394
395
396 void GlobalHandles::Node::IncreaseBlockUses() {
397 NodeBlock* node_block = FindBlock();
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 } 596 }
414 597
415 598
416 class GlobalHandles::NodeIterator { 599 class GlobalHandles::NodeIterator {
417 public: 600 public:
418 explicit NodeIterator(GlobalHandles* global_handles) 601 explicit NodeIterator(GlobalHandles* global_handles)
419 : block_(global_handles->first_used_block_), 602 : all_anchors_(global_handles->all_anchors_),
420 index_(0) {} 603 block_(all_anchors_[0]),
421 604 anchor_index_(0),
422 bool done() const { return block_ == NULL; } 605 node_index_(0) {
606 AdvanceBlock();
607 }
608
609 bool done() const {
610 return anchor_index_ == kAllAnchorsSize;
611 }
423 612
424 Node* node() const { 613 Node* node() const {
425 ASSERT(!done()); 614 ASSERT(!done());
426 return block_->node_at(index_); 615 return NodeBlock::Cast(block_)->node_at(node_index_);
427 } 616 }
428 617
429 void Advance() { 618 void Advance() {
430 ASSERT(!done()); 619 ASSERT(!done());
431 if (++index_ < NodeBlock::kSize) return; 620 if (++node_index_ < NodeBlock::kSize) return;
432 index_ = 0; 621 node_index_ = 0;
433 block_ = block_->next_used(); 622 AdvanceBlock();
434 } 623 }
624
625 typedef int CountArray[Node::NUMBER_OF_STATES];
626 static int CollectStats(GlobalHandles* global_handles, CountArray counts);
435 627
436 private: 628 private:
437 NodeBlock* block_; 629 void AdvanceBlock() {
438 int index_; 630 ASSERT(!done());
631 while (true) {
632 block_ = block_->next();
633 // block is valid
634 if (block_ != all_anchors_[anchor_index_]) {
635 ASSERT(!done());
636 ASSERT(!block_->IsAnchor());
637 // skip empty blocks
638 if (block_->IsUnused()) continue;
639 return;
640 }
641 // jump lists
642 anchor_index_++;
643 if (anchor_index_ == kAllAnchorsSize) break;
644 block_ = all_anchors_[anchor_index_];
645 }
646 ASSERT(done());
647 }
648
649 BlockList* const * const all_anchors_;
650 BlockList* block_;
651 int anchor_index_;
652 int node_index_;
439 653
440 DISALLOW_COPY_AND_ASSIGN(NodeIterator); 654 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
441 }; 655 };
442 656
443 657
658 int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles,
659 CountArray counts) {
660 static const int kSize = Node::NUMBER_OF_STATES;
661 for (int i = 0; i < kSize; i++) {
662 counts[i] = 0;
663 }
664 int total = 0;
665 for (NodeIterator it(global_handles); !it.done(); it.Advance()) {
666 total++;
667 Node::State state = it.node()->state();
668 ASSERT(state >= 0 && state < kSize);
669 counts[state]++;
670 }
671 // NodeIterator skips empty blocks
672 int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total;
673 total += skipped;
674 counts[Node::FREE] += total;
675 return total;
676 }
677
678
444 GlobalHandles::GlobalHandles(Isolate* isolate) 679 GlobalHandles::GlobalHandles(Isolate* isolate)
445 : isolate_(isolate), 680 : isolate_(isolate),
681 number_of_blocks_(0),
446 number_of_global_handles_(0), 682 number_of_global_handles_(0),
447 first_block_(NULL),
448 first_used_block_(NULL),
449 first_free_(NULL),
450 post_gc_processing_count_(0), 683 post_gc_processing_count_(0),
451 object_group_connections_(kObjectGroupConnectionsCapacity) {} 684 object_group_connections_(kObjectGroupConnectionsCapacity) {
685 all_anchors_[0] = &full_blocks_;
686 all_anchors_[1] = &non_full_blocks_;
687 }
452 688
453 689
454 GlobalHandles::~GlobalHandles() { 690 GlobalHandles::~GlobalHandles() {
455 NodeBlock* block = first_block_; 691 for (int i = 0; i < kAllAnchorsSize; i++) {
456 while (block != NULL) { 692 BlockList* block = all_anchors_[i]->next();
457 NodeBlock* tmp = block->next(); 693 while (block != all_anchors_[i]) {
458 delete block; 694 BlockList* tmp = block->next();
459 block = tmp; 695 block->Detach();
460 } 696 delete NodeBlock::Cast(block);
461 first_block_ = NULL; 697 block = tmp;
698 }
699 }
462 } 700 }
463 701
464 702
465 Handle<Object> GlobalHandles::Create(Object* value) { 703 Handle<Object> GlobalHandles::Create(Object* value) {
466 if (first_free_ == NULL) { 704 if (non_full_blocks_.IsDetached()) {
467 first_block_ = new NodeBlock(this, first_block_); 705 new NodeBlock(this);
468 first_block_->PutNodesOnFreeList(&first_free_); 706 ASSERT(!non_full_blocks_.IsDetached());
469 } 707 }
470 ASSERT(first_free_ != NULL); 708 ASSERT(non_full_blocks_.IsAnchor());
471 // Take the first node in the free list. 709 ASSERT(!non_full_blocks_.next()->IsAnchor());
472 Node* result = first_free_; 710 Node* result = NodeBlock::Cast(non_full_blocks_.next())->Acquire(value);
473 first_free_ = result->next_free();
474 result->Acquire(value);
475 if (isolate_->heap()->InNewSpace(value) && 711 if (isolate_->heap()->InNewSpace(value) &&
476 !result->is_in_new_space_list()) { 712 !result->is_in_new_space_list()) {
477 new_space_nodes_.Add(result); 713 new_space_nodes_.Add(result);
478 result->set_in_new_space_list(true); 714 result->set_in_new_space_list(true);
479 } 715 }
480 return result->handle(); 716 return result->handle();
481 } 717 }
482 718
483 719
484 void GlobalHandles::Destroy(Object** location) { 720 void GlobalHandles::Destroy(Object** location) {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
654 // have been deleted in that round, so we need to bail out (or 890 // have been deleted in that round, so we need to bail out (or
655 // restart the processing). 891 // restart the processing).
656 return next_gc_likely_to_collect_more; 892 return next_gc_likely_to_collect_more;
657 } 893 }
658 } 894 }
659 if (!node->IsRetainer()) { 895 if (!node->IsRetainer()) {
660 next_gc_likely_to_collect_more = true; 896 next_gc_likely_to_collect_more = true;
661 } 897 }
662 } 898 }
663 } else { 899 } else {
664 for (NodeIterator it(this); !it.done(); it.Advance()) { 900 // Must cache all blocks, as NodeIterator can't survive mutation.
665 if (!it.node()->IsRetainer()) { 901 List<NodeBlock*> blocks(number_of_blocks_);
666 // Free nodes do not have weak callbacks. Do not use them to compute 902 for (int i = 0; i < kAllAnchorsSize; i++) {
667 // the next_gc_likely_to_collect_more. 903 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) {
668 continue; 904 blocks.Add(NodeBlock::Cast(it.block()));
669 } 905 }
670 it.node()->clear_partially_dependent(); 906 }
671 if (it.node()->PostGarbageCollectionProcessing(isolate_)) { 907 for (int block_index = 0; block_index < blocks.length(); block_index++) {
672 if (initial_post_gc_processing_count != post_gc_processing_count_) { 908 NodeBlock* block = blocks[block_index];
673 // See the comment above. 909 for (int node_index = 0; node_index < NodeBlock::kSize; node_index++) {
674 return next_gc_likely_to_collect_more; 910 Node* node = block->node_at(node_index);
911 if (!node->IsRetainer()) {
912 // Free nodes do not have weak callbacks. Do not use them to compute
913 // the next_gc_likely_to_collect_more.
914 continue;
675 } 915 }
676 } 916 node->clear_partially_dependent();
677 if (!it.node()->IsRetainer()) { 917 if (node->PostGarbageCollectionProcessing(isolate_)) {
678 next_gc_likely_to_collect_more = true; 918 if (initial_post_gc_processing_count != post_gc_processing_count_) {
919 // See the comment above.
920 return next_gc_likely_to_collect_more;
921 }
922 }
923 if (!node->IsRetainer()) {
924 next_gc_likely_to_collect_more = true;
925 }
679 } 926 }
680 } 927 }
681 } 928 }
682 // Update the list of new space nodes. 929 // Update the list of new space nodes.
683 int last = 0; 930 int last = 0;
684 for (int i = 0; i < new_space_nodes_.length(); ++i) { 931 for (int i = 0; i < new_space_nodes_.length(); ++i) {
685 Node* node = new_space_nodes_[i]; 932 Node* node = new_space_nodes_[i];
686 ASSERT(node->is_in_new_space_list()); 933 ASSERT(node->is_in_new_space_list());
687 if (node->IsRetainer()) { 934 if (node->IsRetainer()) {
688 if (isolate_->heap()->InNewSpace(node->object())) { 935 if (isolate_->heap()->InNewSpace(node->object())) {
689 new_space_nodes_[last++] = node; 936 new_space_nodes_[last++] = node;
690 tracer->increment_nodes_copied_in_new_space(); 937 tracer->increment_nodes_copied_in_new_space();
691 } else { 938 } else {
692 node->set_in_new_space_list(false); 939 node->set_in_new_space_list(false);
693 tracer->increment_nodes_promoted(); 940 tracer->increment_nodes_promoted();
694 } 941 }
695 } else { 942 } else {
696 node->set_in_new_space_list(false); 943 node->set_in_new_space_list(false);
697 tracer->increment_nodes_died_in_new_space(); 944 tracer->increment_nodes_died_in_new_space();
698 } 945 }
699 } 946 }
700 new_space_nodes_.Rewind(last); 947 new_space_nodes_.Rewind(last);
948 bool shouldPruneBlocks = collector != SCAVENGER;
949 SortBlocks(shouldPruneBlocks);
701 return next_gc_likely_to_collect_more; 950 return next_gc_likely_to_collect_more;
702 } 951 }
703 952
704 953
705 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { 954 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
706 for (NodeIterator it(this); !it.done(); it.Advance()) { 955 for (NodeIterator it(this); !it.done(); it.Advance()) {
707 if (it.node()->IsStrongRetainer()) { 956 if (it.node()->IsStrongRetainer()) {
708 v->VisitPointer(it.node()->location()); 957 v->VisitPointer(it.node()->location());
709 } 958 }
710 } 959 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 if (it.node()->IsWeakRetainer() && 1007 if (it.node()->IsWeakRetainer() &&
759 it.node()->object()->IsJSGlobalObject()) { 1008 it.node()->object()->IsJSGlobalObject()) {
760 count++; 1009 count++;
761 } 1010 }
762 } 1011 }
763 return count; 1012 return count;
764 } 1013 }
765 1014
766 1015
767 void GlobalHandles::RecordStats(HeapStats* stats) { 1016 void GlobalHandles::RecordStats(HeapStats* stats) {
768 *stats->global_handle_count = 0; 1017 NodeIterator::CountArray counts;
769 *stats->weak_global_handle_count = 0; 1018 int total = NodeIterator::CollectStats(this, counts);
770 *stats->pending_global_handle_count = 0; 1019 *stats->global_handle_count = total;
771 *stats->near_death_global_handle_count = 0; 1020 *stats->weak_global_handle_count = counts[Node::WEAK];
772 *stats->free_global_handle_count = 0; 1021 *stats->pending_global_handle_count = counts[Node::PENDING];
773 for (NodeIterator it(this); !it.done(); it.Advance()) { 1022 *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH];
774 *stats->global_handle_count += 1; 1023 *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 } 1024 }
786 1025
1026
787 #ifdef DEBUG 1027 #ifdef DEBUG
788 1028
789 void GlobalHandles::PrintStats() { 1029 void GlobalHandles::PrintStats() {
790 int total = 0; 1030 NodeIterator::CountArray counts;
791 int weak = 0; 1031 int total = NodeIterator::CollectStats(this, counts);
792 int pending = 0; 1032 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"); 1033 PrintF("Global Handle Statistics:\n");
805 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); 1034 PrintF(" allocated blocks = %d\n", number_of_blocks_);
806 PrintF(" # weak = %d\n", weak); 1035 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed);
807 PrintF(" # pending = %d\n", pending); 1036 PrintF(" # normal = %d\n", counts[Node::NORMAL]);
808 PrintF(" # near_death = %d\n", near_death); 1037 PrintF(" # weak = %d\n", counts[Node::WEAK]);
809 PrintF(" # free = %d\n", destroyed); 1038 PrintF(" # pending = %d\n", counts[Node::PENDING]);
1039 PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]);
1040 PrintF(" # free = %d\n", counts[Node::FREE]);
810 PrintF(" # total = %d\n", total); 1041 PrintF(" # total = %d\n", total);
811 } 1042 }
812 1043
813 1044
814 void GlobalHandles::Print() { 1045 void GlobalHandles::Print() {
815 PrintF("Global handles:\n"); 1046 PrintF("Global handles:\n");
816 for (NodeIterator it(this); !it.done(); it.Advance()) { 1047 for (NodeIterator it(this); !it.done(); it.Advance()) {
817 PrintF(" handle %p to %p%s\n", 1048 PrintF(" handle %p to %p%s\n",
818 reinterpret_cast<void*>(it.node()->location()), 1049 reinterpret_cast<void*>(it.node()->location()),
819 reinterpret_cast<void*>(it.node()->object()), 1050 reinterpret_cast<void*>(it.node()->object()),
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 } 1243 }
1013 } 1244 }
1014 object_group_connections_.Clear(); 1245 object_group_connections_.Clear();
1015 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity); 1246 object_group_connections_.Initialize(kObjectGroupConnectionsCapacity);
1016 retainer_infos_.Clear(); 1247 retainer_infos_.Clear();
1017 implicit_ref_connections_.Clear(); 1248 implicit_ref_connections_.Clear();
1018 } 1249 }
1019 1250
1020 1251
1021 } } // namespace v8::internal 1252 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/global-handles.h ('k') | test/cctest/cctest.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698