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

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

Issue 22970004: Revert "Make GlobalHandle::NodeBlock deletable" (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: 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
62 }; 60 };
63 61
64 // Maps handle location (slot) to the containing node. 62 // Maps handle location (slot) to the containing node.
65 static Node* FromLocation(Object** location) { 63 static Node* FromLocation(Object** location) {
66 ASSERT(OFFSET_OF(Node, object_) == 0); 64 ASSERT(OFFSET_OF(Node, object_) == 0);
67 return reinterpret_cast<Node*>(location); 65 return reinterpret_cast<Node*>(location);
68 } 66 }
69 67
70 Node() { 68 Node() {
71 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset); 69 ASSERT(OFFSET_OF(Node, class_id_) == Internals::kNodeClassIdOffset);
(...skipping 17 matching lines...) Expand all
89 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 87 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
90 index_ = 0; 88 index_ = 0;
91 set_independent(false); 89 set_independent(false);
92 set_partially_dependent(false); 90 set_partially_dependent(false);
93 set_in_new_space_list(false); 91 set_in_new_space_list(false);
94 parameter_or_next_free_.next_free = NULL; 92 parameter_or_next_free_.next_free = NULL;
95 weak_reference_callback_ = NULL; 93 weak_reference_callback_ = NULL;
96 } 94 }
97 #endif 95 #endif
98 96
99 void Initialize(int index, Node* first_free) { 97 void Initialize(int index, Node** first_free) {
100 index_ = static_cast<uint8_t>(index); 98 index_ = static_cast<uint8_t>(index);
101 ASSERT(static_cast<int>(index_) == index); 99 ASSERT(static_cast<int>(index_) == index);
102 set_state(FREE); 100 set_state(FREE);
103 set_in_new_space_list(false); 101 set_in_new_space_list(false);
104 parameter_or_next_free_.next_free = first_free; 102 parameter_or_next_free_.next_free = *first_free;
103 *first_free = this;
105 } 104 }
106 105
107 void Acquire(Object* object) { 106 void Acquire(Object* object) {
108 ASSERT(state() == FREE); 107 ASSERT(state() == FREE);
109 object_ = object; 108 object_ = object;
110 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 109 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
111 set_independent(false); 110 set_independent(false);
112 set_partially_dependent(false); 111 set_partially_dependent(false);
113 set_state(NORMAL); 112 set_state(NORMAL);
114 parameter_or_next_free_.parameter = NULL; 113 parameter_or_next_free_.parameter = NULL;
115 weak_reference_callback_ = NULL; 114 weak_reference_callback_ = NULL;
115 IncreaseBlockUses();
116 } 116 }
117 117
118 void Release() { 118 void Release() {
119 ASSERT(state() != FREE); 119 ASSERT(state() != FREE);
120 set_state(FREE); 120 set_state(FREE);
121 #ifdef ENABLE_EXTRA_CHECKS 121 #ifdef ENABLE_EXTRA_CHECKS
122 // Zap the values for eager trapping. 122 // Zap the values for eager trapping.
123 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue); 123 object_ = reinterpret_cast<Object*>(kGlobalHandleZapValue);
124 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId; 124 class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
125 set_independent(false); 125 set_independent(false);
126 set_partially_dependent(false); 126 set_partially_dependent(false);
127 weak_reference_callback_ = NULL; 127 weak_reference_callback_ = NULL;
128 #endif 128 #endif
129 ReleaseFromBlock(); 129 DecreaseBlockUses();
130 } 130 }
131 131
132 // Object slot accessors. 132 // Object slot accessors.
133 Object* object() const { return object_; } 133 Object* object() const { return object_; }
134 Object** location() { return &object_; } 134 Object** location() { return &object_; }
135 Handle<Object> handle() { return Handle<Object>(location()); } 135 Handle<Object> handle() { return Handle<Object>(location()); }
136 136
137 // Wrapper class ID accessors. 137 // Wrapper class ID accessors.
138 bool has_wrapper_class_id() const { 138 bool has_wrapper_class_id() const {
139 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId; 139 return class_id_ != v8::HeapProfiler::kPersistentHandleNoClassId;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 } 198 }
199 199
200 void MarkPartiallyDependent() { 200 void MarkPartiallyDependent() {
201 ASSERT(state() != FREE); 201 ASSERT(state() != FREE);
202 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) { 202 if (GetGlobalHandles()->isolate()->heap()->InNewSpace(object_)) {
203 set_partially_dependent(true); 203 set_partially_dependent(true);
204 } 204 }
205 } 205 }
206 void clear_partially_dependent() { set_partially_dependent(false); } 206 void clear_partially_dependent() { set_partially_dependent(false); }
207 207
208 // Callback accessor.
209 // TODO(svenpanne) Re-enable or nuke later.
210 // WeakReferenceCallback callback() { return callback_; }
211
208 // Callback parameter accessors. 212 // Callback parameter accessors.
209 void set_parameter(void* parameter) { 213 void set_parameter(void* parameter) {
210 ASSERT(state() != FREE); 214 ASSERT(state() != FREE);
211 parameter_or_next_free_.parameter = parameter; 215 parameter_or_next_free_.parameter = parameter;
212 } 216 }
213 void* parameter() const { 217 void* parameter() const {
214 ASSERT(state() != FREE); 218 ASSERT(state() != FREE);
215 return parameter_or_next_free_.parameter; 219 return parameter_or_next_free_.parameter;
216 } 220 }
217 221
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 } 270 }
267 // Absence of explicit cleanup or revival of weak handle 271 // Absence of explicit cleanup or revival of weak handle
268 // in most of the cases would lead to memory leak. 272 // in most of the cases would lead to memory leak.
269 ASSERT(state() != NEAR_DEATH); 273 ASSERT(state() != NEAR_DEATH);
270 return true; 274 return true;
271 } 275 }
272 276
273 private: 277 private:
274 inline NodeBlock* FindBlock(); 278 inline NodeBlock* FindBlock();
275 inline GlobalHandles* GetGlobalHandles(); 279 inline GlobalHandles* GetGlobalHandles();
276 inline void ReleaseFromBlock(); 280 inline void IncreaseBlockUses();
281 inline void DecreaseBlockUses();
277 282
278 // Storage for object pointer. 283 // Storage for object pointer.
279 // Placed first to avoid offset computation. 284 // Placed first to avoid offset computation.
280 Object* object_; 285 Object* object_;
281 286
282 // Next word stores class_id, index, state, and independent. 287 // Next word stores class_id, index, state, and independent.
283 // Note: the most aligned fields should go first. 288 // Note: the most aligned fields should go first.
284 289
285 // Wrapper class ID. 290 // Wrapper class ID.
286 uint16_t class_id_; 291 uint16_t class_id_;
(...skipping 17 matching lines...) Expand all
304 // the free list link. 309 // the free list link.
305 union { 310 union {
306 void* parameter; 311 void* parameter;
307 Node* next_free; 312 Node* next_free;
308 } parameter_or_next_free_; 313 } parameter_or_next_free_;
309 314
310 DISALLOW_COPY_AND_ASSIGN(Node); 315 DISALLOW_COPY_AND_ASSIGN(Node);
311 }; 316 };
312 317
313 318
314 class GlobalHandles::BlockListIterator { 319 class GlobalHandles::NodeBlock {
315 public:
316 explicit inline BlockListIterator(BlockList* anchor)
317 : anchor_(anchor), current_(anchor->next()) {
318 ASSERT(anchor->IsAnchor());
319 }
320 inline BlockList* block() const {
321 ASSERT(!done());
322 return current_;
323 }
324 inline bool done() const {
325 ASSERT_EQ(anchor_ == current_, current_->IsAnchor());
326 return anchor_ == current_;
327 }
328 inline void Advance() {
329 ASSERT(!done());
330 current_ = current_->next();
331 }
332
333 private:
334 BlockList* const anchor_;
335 BlockList* current_;
336 DISALLOW_COPY_AND_ASSIGN(BlockListIterator);
337 };
338
339
340 GlobalHandles::BlockList::BlockList()
341 : prev_block_(this),
342 next_block_(this),
343 first_free_(NULL),
344 used_nodes_(0) {}
345
346
347 void GlobalHandles::BlockList::InsertAsNext(BlockList* const block) {
348 ASSERT(block != this);
349 ASSERT(!block->IsAnchor());
350 ASSERT(block->IsDetached());
351 block->prev_block_ = this;
352 block->next_block_ = next_block_;
353 next_block_->prev_block_ = block;
354 next_block_ = block;
355 ASSERT(!IsDetached());
356 ASSERT(!block->IsDetached());
357 }
358
359
360 void GlobalHandles::BlockList::Detach() {
361 ASSERT(!IsAnchor());
362 ASSERT(!IsDetached());
363 prev_block_->next_block_ = next_block_;
364 next_block_->prev_block_ = prev_block_;
365 prev_block_ = this;
366 next_block_ = this;
367 ASSERT(IsDetached());
368 }
369
370
371 bool GlobalHandles::BlockList::HasAtLeastLength(int length) {
372 ASSERT(IsAnchor());
373 ASSERT(length > 0);
374 for (BlockListIterator it(this); !it.done(); it.Advance()) {
375 if (--length <= 0) return true;
376 }
377 return false;
378 }
379
380
381 #ifdef DEBUG
382 int GlobalHandles::BlockList::LengthOfFreeList() {
383 int count = 0;
384 Node* node = first_free_;
385 while (node != NULL) {
386 count++;
387 node = node->next_free();
388 }
389 return count;
390 }
391 #endif
392
393
394 int GlobalHandles::BlockList::CompareBlocks(const void* a, const void* b) {
395 const BlockList* block_a =
396 *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(a));
397 const BlockList* block_b =
398 *reinterpret_cast<const BlockList**>(reinterpret_cast<uintptr_t>(b));
399 if (block_a->used_nodes() > block_b->used_nodes()) return -1;
400 if (block_a->used_nodes() == block_b->used_nodes()) return 0;
401 return 1;
402 }
403
404
405 class GlobalHandles::NodeBlock : public BlockList {
406 public: 320 public:
407 static const int kSize = 256; 321 static const int kSize = 256;
408 322
409 explicit NodeBlock(GlobalHandles* global_handles) 323 explicit NodeBlock(GlobalHandles* global_handles, NodeBlock* next)
410 : global_handles_(global_handles) { 324 : next_(next),
411 // Initialize nodes 325 used_nodes_(0),
412 Node* first_free = first_free_; 326 next_used_(NULL),
327 prev_used_(NULL),
328 global_handles_(global_handles) {}
329
330 void PutNodesOnFreeList(Node** first_free) {
413 for (int i = kSize - 1; i >= 0; --i) { 331 for (int i = kSize - 1; i >= 0; --i) {
414 nodes_[i].Initialize(i, first_free); 332 nodes_[i].Initialize(i, first_free);
415 first_free = &nodes_[i];
416 }
417 first_free_ = first_free;
418 ASSERT(!IsAnchor());
419 // Link into global_handles
420 ASSERT(global_handles->non_full_blocks_.IsDetached());
421 global_handles->non_full_blocks_.InsertAsHead(this);
422 global_handles->number_of_blocks_++;
423 }
424
425 Node* Acquire(Object* o) {
426 ASSERT(used_nodes_ < kSize);
427 ASSERT(first_free_ != NULL);
428 ASSERT(global_handles_->non_full_blocks_.next() == this);
429 // Remove from free list
430 Node* node = first_free_;
431 first_free_ = node->next_free();
432 // Increment counters
433 global_handles_->isolate()->counters()->global_handles()->Increment();
434 global_handles_->number_of_global_handles_++;
435 // Initialize node with value
436 node->Acquire(o);
437 bool now_full = ++used_nodes_ == kSize;
438 ASSERT_EQ(now_full, first_free_ == NULL);
439 if (now_full) {
440 // Move block to tail of non_full_blocks_
441 Detach();
442 global_handles_->full_blocks_.InsertAsTail(this);
443 }
444 return node;
445 }
446
447 void Release(Node* node) {
448 ASSERT(used_nodes_ > 0);
449 // Add to free list
450 node->set_next_free(first_free_);
451 first_free_ = node;
452 // Decrement counters
453 global_handles_->isolate()->counters()->global_handles()->Decrement();
454 global_handles_->number_of_global_handles_--;
455 bool was_full = used_nodes_-- == kSize;
456 ASSERT_EQ(was_full, first_free_->next_free() == NULL);
457 if (was_full) {
458 // Move this block to head of non_full_blocks_
459 Detach();
460 global_handles_->non_full_blocks_.InsertAsHead(this);
461 } 333 }
462 } 334 }
463 335
464 Node* node_at(int index) { 336 Node* node_at(int index) {
465 ASSERT(0 <= index && index < kSize); 337 ASSERT(0 <= index && index < kSize);
466 return &nodes_[index]; 338 return &nodes_[index];
467 } 339 }
468 340
341 void IncreaseUses() {
342 ASSERT(used_nodes_ < kSize);
343 if (used_nodes_++ == 0) {
344 NodeBlock* old_first = global_handles_->first_used_block_;
345 global_handles_->first_used_block_ = this;
346 next_used_ = old_first;
347 prev_used_ = NULL;
348 if (old_first == NULL) return;
349 old_first->prev_used_ = this;
350 }
351 }
352
353 void DecreaseUses() {
354 ASSERT(used_nodes_ > 0);
355 if (--used_nodes_ == 0) {
356 if (next_used_ != NULL) next_used_->prev_used_ = prev_used_;
357 if (prev_used_ != NULL) prev_used_->next_used_ = next_used_;
358 if (this == global_handles_->first_used_block_) {
359 global_handles_->first_used_block_ = next_used_;
360 }
361 }
362 }
363
469 GlobalHandles* global_handles() { return global_handles_; } 364 GlobalHandles* global_handles() { return global_handles_; }
470 365
471 static NodeBlock* Cast(BlockList* block_list) { 366 // Next block in the list of all blocks.
472 ASSERT(!block_list->IsAnchor()); 367 NodeBlock* next() const { return next_; }
473 return static_cast<NodeBlock*>(block_list);
474 }
475 368
476 static NodeBlock* From(Node* node, uint8_t index) { 369 // Next/previous block in the list of blocks with used nodes.
477 uintptr_t ptr = reinterpret_cast<uintptr_t>(node - index); 370 NodeBlock* next_used() const { return next_used_; }
478 ptr -= OFFSET_OF(NodeBlock, nodes_); 371 NodeBlock* prev_used() const { return prev_used_; }
479 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
480 ASSERT(block->node_at(index) == node);
481 return block;
482 }
483 372
484 private: 373 private:
485 Node nodes_[kSize]; 374 Node nodes_[kSize];
375 NodeBlock* const next_;
376 int used_nodes_;
377 NodeBlock* next_used_;
378 NodeBlock* prev_used_;
486 GlobalHandles* global_handles_; 379 GlobalHandles* global_handles_;
487 }; 380 };
488 381
489 382
490 void GlobalHandles::BlockList::SortBlocks(GlobalHandles* global_handles,
491 bool prune) {
492 // Always sort at least 2 blocks
493 if (!global_handles->non_full_blocks_.HasAtLeastLength(2)) return;
494 // build a vector that could contain the upper bound of the block count
495 int number_of_blocks = global_handles->block_count();
496 // Build array of blocks and update number_of_blocks to actual count
497 ScopedVector<BlockList*> blocks(number_of_blocks);
498 {
499 int i = 0;
500 BlockList* anchor = &global_handles->non_full_blocks_;
501 for (BlockListIterator it(anchor); !it.done(); it.Advance()) {
502 blocks[i++] = it.block();
503 }
504 number_of_blocks = i;
505 }
506 // Nothing to do.
507 if (number_of_blocks <= 1) return;
508 // Sort blocks
509 qsort(blocks.start(), number_of_blocks, sizeof(blocks[0]), CompareBlocks);
510 // Prune empties
511 if (prune) {
512 static const double kUnusedPercentage = 0.30;
513 static const double kUsedPercentage = 1.30;
514 int total_slots = global_handles->number_of_blocks_ * NodeBlock::kSize;
515 const int total_used = global_handles->number_of_global_handles_;
516 const int target_unused = static_cast<int>(Max(
517 total_used * kUsedPercentage,
518 total_slots * kUnusedPercentage));
519 // Reverse through empty blocks. Note: always leave one block free.
520 int blocks_deleted = 0;
521 for (int i = number_of_blocks - 1; i > 0 && blocks[i]->IsUnused(); i--) {
522 // Not worth deleting
523 if (total_slots - total_used < target_unused) break;
524 blocks[i]->Detach();
525 delete blocks[i];
526 blocks_deleted++;
527 total_slots -= NodeBlock::kSize;
528 }
529 global_handles->number_of_blocks_ -= blocks_deleted;
530 number_of_blocks -= blocks_deleted;
531 }
532 // Relink all blocks
533 for (int i = 0; i < number_of_blocks; i++) {
534 blocks[i]->Detach();
535 global_handles->non_full_blocks_.InsertAsTail(blocks[i]);
536 }
537 #ifdef DEBUG
538 // Check sorting
539 BlockList* anchor = &global_handles->non_full_blocks_;
540 int last_size = NodeBlock::kSize;
541 for (BlockListIterator it(anchor); !it.done(); it.Advance()) {
542 ASSERT(it.block()->used_nodes() <= last_size);
543 last_size = it.block()->used_nodes();
544 }
545 #endif
546 }
547
548
549 #ifdef DEBUG
550 void GlobalHandles::VerifyBlockInvariants() {
551 int number_of_blocks = 0;
552 int number_of_handles = 0;
553 for (int i = 0; i < kAllAnchorsSize; i++) {
554 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) {
555 BlockList* block = it.block();
556 number_of_blocks++;
557 int used_nodes = block->used_nodes();
558 number_of_handles += used_nodes;
559 int unused_nodes = block->LengthOfFreeList();
560 ASSERT_EQ(used_nodes + unused_nodes, NodeBlock::kSize);
561 if (all_anchors_[i] == &full_blocks_) {
562 ASSERT_EQ(NodeBlock::kSize, used_nodes);
563 } else {
564 ASSERT_NE(NodeBlock::kSize, used_nodes);
565 }
566 }
567 }
568 ASSERT_EQ(number_of_handles, number_of_global_handles_);
569 ASSERT_EQ(number_of_blocks, number_of_blocks_);
570 }
571 #endif
572
573
574 void GlobalHandles::SortBlocks(bool shouldPrune) {
575 #ifdef DEBUG
576 VerifyBlockInvariants();
577 #endif
578 BlockList::SortBlocks(this, shouldPrune);
579 #ifdef DEBUG
580 VerifyBlockInvariants();
581 #endif
582 }
583
584
585 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() { 383 GlobalHandles* GlobalHandles::Node::GetGlobalHandles() {
586 return FindBlock()->global_handles(); 384 return FindBlock()->global_handles();
587 } 385 }
588 386
589 387
590 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() { 388 GlobalHandles::NodeBlock* GlobalHandles::Node::FindBlock() {
591 return NodeBlock::From(this, index_); 389 intptr_t ptr = reinterpret_cast<intptr_t>(this);
390 ptr = ptr - index_ * sizeof(Node);
391 NodeBlock* block = reinterpret_cast<NodeBlock*>(ptr);
392 ASSERT(block->node_at(index_) == this);
393 return block;
592 } 394 }
593 395
594 396
595 void GlobalHandles::Node::ReleaseFromBlock() { 397 void GlobalHandles::Node::IncreaseBlockUses() {
596 FindBlock()->Release(this); 398 NodeBlock* node_block = FindBlock();
399 node_block->IncreaseUses();
400 GlobalHandles* global_handles = node_block->global_handles();
401 global_handles->isolate()->counters()->global_handles()->Increment();
402 global_handles->number_of_global_handles_++;
403 }
404
405
406 void GlobalHandles::Node::DecreaseBlockUses() {
407 NodeBlock* node_block = FindBlock();
408 GlobalHandles* global_handles = node_block->global_handles();
409 parameter_or_next_free_.next_free = global_handles->first_free_;
410 global_handles->first_free_ = this;
411 node_block->DecreaseUses();
412 global_handles->isolate()->counters()->global_handles()->Decrement();
413 global_handles->number_of_global_handles_--;
597 } 414 }
598 415
599 416
600 class GlobalHandles::NodeIterator { 417 class GlobalHandles::NodeIterator {
601 public: 418 public:
602 explicit NodeIterator(GlobalHandles* global_handles) 419 explicit NodeIterator(GlobalHandles* global_handles)
603 : all_anchors_(global_handles->all_anchors_), 420 : block_(global_handles->first_used_block_),
604 block_(all_anchors_[0]), 421 index_(0) {}
605 anchor_index_(0),
606 node_index_(0) {
607 AdvanceBlock();
608 }
609 422
610 bool done() const { 423 bool done() const { return block_ == NULL; }
611 return anchor_index_ == kAllAnchorsSize;
612 }
613 424
614 Node* node() const { 425 Node* node() const {
615 ASSERT(!done()); 426 ASSERT(!done());
616 return NodeBlock::Cast(block_)->node_at(node_index_); 427 return block_->node_at(index_);
617 } 428 }
618 429
619 void Advance() { 430 void Advance() {
620 ASSERT(!done()); 431 ASSERT(!done());
621 if (++node_index_ < NodeBlock::kSize) return; 432 if (++index_ < NodeBlock::kSize) return;
622 node_index_ = 0; 433 index_ = 0;
623 AdvanceBlock(); 434 block_ = block_->next_used();
624 } 435 }
625 436
626 typedef int CountArray[Node::NUMBER_OF_STATES];
627 static int CollectStats(GlobalHandles* global_handles, CountArray counts);
628
629 private: 437 private:
630 void AdvanceBlock() { 438 NodeBlock* block_;
631 ASSERT(!done()); 439 int index_;
632 while (true) {
633 block_ = block_->next();
634 // block is valid
635 if (block_ != all_anchors_[anchor_index_]) {
636 ASSERT(!done());
637 ASSERT(!block_->IsAnchor());
638 // skip empty blocks
639 if (block_->IsUnused()) continue;
640 return;
641 }
642 // jump lists
643 anchor_index_++;
644 if (anchor_index_ == kAllAnchorsSize) break;
645 block_ = all_anchors_[anchor_index_];
646 }
647 ASSERT(done());
648 }
649
650 BlockList* const * const all_anchors_;
651 BlockList* block_;
652 int anchor_index_;
653 int node_index_;
654 440
655 DISALLOW_COPY_AND_ASSIGN(NodeIterator); 441 DISALLOW_COPY_AND_ASSIGN(NodeIterator);
656 }; 442 };
657 443
658 444
659 int GlobalHandles::NodeIterator::CollectStats(GlobalHandles* global_handles,
660 CountArray counts) {
661 static const int kSize = Node::NUMBER_OF_STATES;
662 for (int i = 0; i < kSize; i++) {
663 counts[i] = 0;
664 }
665 int total = 0;
666 for (NodeIterator it(global_handles); !it.done(); it.Advance()) {
667 total++;
668 Node::State state = it.node()->state();
669 ASSERT(state >= 0 && state < kSize);
670 counts[state]++;
671 }
672 // NodeIterator skips empty blocks
673 int skipped = global_handles->number_of_blocks_ * NodeBlock::kSize - total;
674 total += skipped;
675 counts[Node::FREE] += total;
676 return total;
677 }
678
679
680 GlobalHandles::GlobalHandles(Isolate* isolate) 445 GlobalHandles::GlobalHandles(Isolate* isolate)
681 : isolate_(isolate), 446 : isolate_(isolate),
682 number_of_blocks_(0),
683 number_of_global_handles_(0), 447 number_of_global_handles_(0),
448 first_block_(NULL),
449 first_used_block_(NULL),
450 first_free_(NULL),
684 post_gc_processing_count_(0), 451 post_gc_processing_count_(0),
685 object_group_connections_(kObjectGroupConnectionsCapacity) { 452 object_group_connections_(kObjectGroupConnectionsCapacity) {}
686 all_anchors_[0] = &full_blocks_;
687 all_anchors_[1] = &non_full_blocks_;
688 }
689 453
690 454
691 GlobalHandles::~GlobalHandles() { 455 GlobalHandles::~GlobalHandles() {
692 for (int i = 0; i < kAllAnchorsSize; i++) { 456 NodeBlock* block = first_block_;
693 BlockList* block = all_anchors_[i]->next(); 457 while (block != NULL) {
694 while (block != all_anchors_[i]) { 458 NodeBlock* tmp = block->next();
695 BlockList* tmp = block->next(); 459 delete block;
696 block->Detach(); 460 block = tmp;
697 delete NodeBlock::Cast(block);
698 block = tmp;
699 }
700 } 461 }
462 first_block_ = NULL;
701 } 463 }
702 464
703 465
704 Handle<Object> GlobalHandles::Create(Object* value) { 466 Handle<Object> GlobalHandles::Create(Object* value) {
705 if (non_full_blocks_.IsDetached()) { 467 if (first_free_ == NULL) {
706 new NodeBlock(this); 468 first_block_ = new NodeBlock(this, first_block_);
707 ASSERT(!non_full_blocks_.IsDetached()); 469 first_block_->PutNodesOnFreeList(&first_free_);
708 } 470 }
709 ASSERT(non_full_blocks_.IsAnchor()); 471 ASSERT(first_free_ != NULL);
710 ASSERT(!non_full_blocks_.next()->IsAnchor()); 472 // Take the first node in the free list.
711 Node* result = NodeBlock::Cast(non_full_blocks_.next())->Acquire(value); 473 Node* result = first_free_;
474 first_free_ = result->next_free();
475 result->Acquire(value);
712 if (isolate_->heap()->InNewSpace(value) && 476 if (isolate_->heap()->InNewSpace(value) &&
713 !result->is_in_new_space_list()) { 477 !result->is_in_new_space_list()) {
714 new_space_nodes_.Add(result); 478 new_space_nodes_.Add(result);
715 result->set_in_new_space_list(true); 479 result->set_in_new_space_list(true);
716 } 480 }
717 return result->handle(); 481 return result->handle();
718 } 482 }
719 483
720 484
721 void GlobalHandles::Destroy(Object** location) { 485 void GlobalHandles::Destroy(Object** location) {
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
891 // have been deleted in that round, so we need to bail out (or 655 // have been deleted in that round, so we need to bail out (or
892 // restart the processing). 656 // restart the processing).
893 return next_gc_likely_to_collect_more; 657 return next_gc_likely_to_collect_more;
894 } 658 }
895 } 659 }
896 if (!node->IsRetainer()) { 660 if (!node->IsRetainer()) {
897 next_gc_likely_to_collect_more = true; 661 next_gc_likely_to_collect_more = true;
898 } 662 }
899 } 663 }
900 } else { 664 } else {
901 // Must cache all blocks, as NodeIterator can't survive mutation. 665 for (NodeIterator it(this); !it.done(); it.Advance()) {
902 List<NodeBlock*> blocks(number_of_blocks_); 666 if (!it.node()->IsRetainer()) {
903 for (int i = 0; i < kAllAnchorsSize; i++) { 667 // Free nodes do not have weak callbacks. Do not use them to compute
904 for (BlockListIterator it(all_anchors_[i]); !it.done(); it.Advance()) { 668 // the next_gc_likely_to_collect_more.
905 blocks.Add(NodeBlock::Cast(it.block())); 669 continue;
906 } 670 }
907 } 671 it.node()->clear_partially_dependent();
908 for (int block_index = 0; block_index < blocks.length(); block_index++) { 672 if (it.node()->PostGarbageCollectionProcessing(isolate_)) {
909 NodeBlock* block = blocks[block_index]; 673 if (initial_post_gc_processing_count != post_gc_processing_count_) {
910 for (int node_index = 0; node_index < NodeBlock::kSize; node_index++) { 674 // See the comment above.
911 Node* node = block->node_at(node_index); 675 return next_gc_likely_to_collect_more;
912 if (!node->IsRetainer()) {
913 // Free nodes do not have weak callbacks. Do not use them to compute
914 // the next_gc_likely_to_collect_more.
915 continue;
916 } 676 }
917 node->clear_partially_dependent(); 677 }
918 if (node->PostGarbageCollectionProcessing(isolate_)) { 678 if (!it.node()->IsRetainer()) {
919 if (initial_post_gc_processing_count != post_gc_processing_count_) { 679 next_gc_likely_to_collect_more = true;
920 // See the comment above.
921 return next_gc_likely_to_collect_more;
922 }
923 }
924 if (!node->IsRetainer()) {
925 next_gc_likely_to_collect_more = true;
926 }
927 } 680 }
928 } 681 }
929 } 682 }
930 // Update the list of new space nodes. 683 // Update the list of new space nodes.
931 int last = 0; 684 int last = 0;
932 for (int i = 0; i < new_space_nodes_.length(); ++i) { 685 for (int i = 0; i < new_space_nodes_.length(); ++i) {
933 Node* node = new_space_nodes_[i]; 686 Node* node = new_space_nodes_[i];
934 ASSERT(node->is_in_new_space_list()); 687 ASSERT(node->is_in_new_space_list());
935 if (node->IsRetainer()) { 688 if (node->IsRetainer()) {
936 if (isolate_->heap()->InNewSpace(node->object())) { 689 if (isolate_->heap()->InNewSpace(node->object())) {
937 new_space_nodes_[last++] = node; 690 new_space_nodes_[last++] = node;
938 tracer->increment_nodes_copied_in_new_space(); 691 tracer->increment_nodes_copied_in_new_space();
939 } else { 692 } else {
940 node->set_in_new_space_list(false); 693 node->set_in_new_space_list(false);
941 tracer->increment_nodes_promoted(); 694 tracer->increment_nodes_promoted();
942 } 695 }
943 } else { 696 } else {
944 node->set_in_new_space_list(false); 697 node->set_in_new_space_list(false);
945 tracer->increment_nodes_died_in_new_space(); 698 tracer->increment_nodes_died_in_new_space();
946 } 699 }
947 } 700 }
948 new_space_nodes_.Rewind(last); 701 new_space_nodes_.Rewind(last);
949 bool shouldPruneBlocks = collector != SCAVENGER;
950 SortBlocks(shouldPruneBlocks);
951 return next_gc_likely_to_collect_more; 702 return next_gc_likely_to_collect_more;
952 } 703 }
953 704
954 705
955 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) { 706 void GlobalHandles::IterateStrongRoots(ObjectVisitor* v) {
956 for (NodeIterator it(this); !it.done(); it.Advance()) { 707 for (NodeIterator it(this); !it.done(); it.Advance()) {
957 if (it.node()->IsStrongRetainer()) { 708 if (it.node()->IsStrongRetainer()) {
958 v->VisitPointer(it.node()->location()); 709 v->VisitPointer(it.node()->location());
959 } 710 }
960 } 711 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 if (it.node()->IsWeakRetainer() && 759 if (it.node()->IsWeakRetainer() &&
1009 it.node()->object()->IsJSGlobalObject()) { 760 it.node()->object()->IsJSGlobalObject()) {
1010 count++; 761 count++;
1011 } 762 }
1012 } 763 }
1013 return count; 764 return count;
1014 } 765 }
1015 766
1016 767
1017 void GlobalHandles::RecordStats(HeapStats* stats) { 768 void GlobalHandles::RecordStats(HeapStats* stats) {
1018 NodeIterator::CountArray counts; 769 *stats->global_handle_count = 0;
1019 int total = NodeIterator::CollectStats(this, counts); 770 *stats->weak_global_handle_count = 0;
1020 *stats->global_handle_count = total; 771 *stats->pending_global_handle_count = 0;
1021 *stats->weak_global_handle_count = counts[Node::WEAK]; 772 *stats->near_death_global_handle_count = 0;
1022 *stats->pending_global_handle_count = counts[Node::PENDING]; 773 *stats->free_global_handle_count = 0;
1023 *stats->near_death_global_handle_count = counts[Node::NEAR_DEATH]; 774 for (NodeIterator it(this); !it.done(); it.Advance()) {
1024 *stats->free_global_handle_count = counts[Node::FREE]; 775 *stats->global_handle_count += 1;
776 if (it.node()->state() == Node::WEAK) {
777 *stats->weak_global_handle_count += 1;
778 } else if (it.node()->state() == Node::PENDING) {
779 *stats->pending_global_handle_count += 1;
780 } else if (it.node()->state() == Node::NEAR_DEATH) {
781 *stats->near_death_global_handle_count += 1;
782 } else if (it.node()->state() == Node::FREE) {
783 *stats->free_global_handle_count += 1;
784 }
785 }
1025 } 786 }
1026 787
1027
1028 #ifdef DEBUG 788 #ifdef DEBUG
1029 789
1030 void GlobalHandles::PrintStats() { 790 void GlobalHandles::PrintStats() {
1031 NodeIterator::CountArray counts; 791 int total = 0;
1032 int total = NodeIterator::CollectStats(this, counts); 792 int weak = 0;
1033 size_t total_consumed = sizeof(NodeBlock) * number_of_blocks_; 793 int pending = 0;
794 int near_death = 0;
795 int destroyed = 0;
796
797 for (NodeIterator it(this); !it.done(); it.Advance()) {
798 total++;
799 if (it.node()->state() == Node::WEAK) weak++;
800 if (it.node()->state() == Node::PENDING) pending++;
801 if (it.node()->state() == Node::NEAR_DEATH) near_death++;
802 if (it.node()->state() == Node::FREE) destroyed++;
803 }
804
1034 PrintF("Global Handle Statistics:\n"); 805 PrintF("Global Handle Statistics:\n");
1035 PrintF(" allocated blocks = %d\n", number_of_blocks_); 806 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total);
1036 PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", total_consumed); 807 PrintF(" # weak = %d\n", weak);
1037 PrintF(" # normal = %d\n", counts[Node::NORMAL]); 808 PrintF(" # pending = %d\n", pending);
1038 PrintF(" # weak = %d\n", counts[Node::WEAK]); 809 PrintF(" # near_death = %d\n", near_death);
1039 PrintF(" # pending = %d\n", counts[Node::PENDING]); 810 PrintF(" # free = %d\n", destroyed);
1040 PrintF(" # near_death = %d\n", counts[Node::NEAR_DEATH]);
1041 PrintF(" # free = %d\n", counts[Node::FREE]);
1042 PrintF(" # total = %d\n", total); 811 PrintF(" # total = %d\n", total);
1043 } 812 }
1044 813
1045 814
1046 void GlobalHandles::Print() { 815 void GlobalHandles::Print() {
1047 PrintF("Global handles:\n"); 816 PrintF("Global handles:\n");
1048 for (NodeIterator it(this); !it.done(); it.Advance()) { 817 for (NodeIterator it(this); !it.done(); it.Advance()) {
1049 PrintF(" handle %p to %p%s\n", 818 PrintF(" handle %p to %p%s\n",
1050 reinterpret_cast<void*>(it.node()->location()), 819 reinterpret_cast<void*>(it.node()->location()),
1051 reinterpret_cast<void*>(it.node()->object()), 820 reinterpret_cast<void*>(it.node()->object()),
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after
1308 ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]); 1077 ASSERT_EQ(isolate->heap()->the_hole_value(), blocks_[block][offset]);
1309 blocks_[block][offset] = object; 1078 blocks_[block][offset] = object;
1310 if (isolate->heap()->InNewSpace(object)) { 1079 if (isolate->heap()->InNewSpace(object)) {
1311 new_space_indices_.Add(size_); 1080 new_space_indices_.Add(size_);
1312 } 1081 }
1313 return size_++; 1082 return size_++;
1314 } 1083 }
1315 1084
1316 1085
1317 } } // namespace v8::internal 1086 } } // 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