OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |