Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/scavenger.h" | 5 #include "vm/scavenger.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 } | 71 } |
| 72 | 72 |
| 73 private: | 73 private: |
| 74 bool* _addr; | 74 bool* _addr; |
| 75 bool _value; | 75 bool _value; |
| 76 }; | 76 }; |
| 77 | 77 |
| 78 | 78 |
| 79 class ScavengerVisitor : public ObjectPointerVisitor { | 79 class ScavengerVisitor : public ObjectPointerVisitor { |
| 80 public: | 80 public: |
| 81 explicit ScavengerVisitor(Isolate* isolate, Scavenger* scavenger) | 81 explicit ScavengerVisitor(Isolate* isolate, |
| 82 Scavenger* scavenger, | |
| 83 SemiSpace* from) | |
| 82 : ObjectPointerVisitor(isolate), | 84 : ObjectPointerVisitor(isolate), |
| 83 thread_(Thread::Current()), | 85 thread_(Thread::Current()), |
| 84 scavenger_(scavenger), | 86 scavenger_(scavenger), |
| 85 from_start_(scavenger_->from_->start()), | 87 from_(from), |
| 86 from_size_(scavenger_->from_->end() - scavenger_->from_->start()), | |
| 87 heap_(scavenger->heap_), | 88 heap_(scavenger->heap_), |
| 88 vm_heap_(Dart::vm_isolate()->heap()), | 89 vm_heap_(Dart::vm_isolate()->heap()), |
| 89 page_space_(scavenger->heap_->old_space()), | 90 page_space_(scavenger->heap_->old_space()), |
| 90 delayed_weak_stack_(), | 91 delayed_weak_stack_(), |
| 91 bytes_promoted_(0), | 92 bytes_promoted_(0), |
| 92 visiting_old_object_(NULL), | 93 visiting_old_object_(NULL), |
| 93 in_scavenge_pointer_(false) { } | 94 in_scavenge_pointer_(false) { } |
| 94 | 95 |
| 95 void VisitPointers(RawObject** first, RawObject** last) { | 96 void VisitPointers(RawObject** first, RawObject** last) { |
| 96 for (RawObject** current = first; current <= last; current++) { | 97 for (RawObject** current = first; current <= last; current++) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 BoolScope bs(&in_scavenge_pointer_, true); | 151 BoolScope bs(&in_scavenge_pointer_, true); |
| 151 #endif | 152 #endif |
| 152 | 153 |
| 153 RawObject* raw_obj = *p; | 154 RawObject* raw_obj = *p; |
| 154 | 155 |
| 155 if (raw_obj->IsSmiOrOldObject()) { | 156 if (raw_obj->IsSmiOrOldObject()) { |
| 156 return; | 157 return; |
| 157 } | 158 } |
| 158 | 159 |
| 159 // The scavenger is only interested in objects located in the from space. | 160 // The scavenger is only interested in objects located in the from space. |
| 160 // | 161 ASSERT(from_->Contains(RawObject::ToAddr(raw_obj))); |
|
koda
2015/08/12 01:22:33
You could rearrange and use "raw_addr" here; it mi
Ivan Posva
2015/08/14 20:19:32
Done.
| |
| 161 // We are using address math here and relying on the unsigned underflow | |
| 162 // in the code below to avoid having two checks. | |
| 163 uword obj_offset = reinterpret_cast<uword>(raw_obj) - from_start_; | |
| 164 if (obj_offset > from_size_) { | |
| 165 ASSERT(scavenger_->to_->Contains(RawObject::ToAddr(raw_obj))); | |
| 166 return; | |
| 167 } | |
| 168 | 162 |
| 169 uword raw_addr = RawObject::ToAddr(raw_obj); | 163 uword raw_addr = RawObject::ToAddr(raw_obj); |
| 170 // Read the header word of the object and determine if the object has | 164 // Read the header word of the object and determine if the object has |
| 171 // already been copied. | 165 // already been copied. |
| 172 uword header = *reinterpret_cast<uword*>(raw_addr); | 166 uword header = *reinterpret_cast<uword*>(raw_addr); |
| 173 uword new_addr = 0; | 167 uword new_addr = 0; |
| 174 if (IsForwarding(header)) { | 168 if (IsForwarding(header)) { |
| 175 // Get the new location of the object. | 169 // Get the new location of the object. |
| 176 new_addr = ForwardedAddr(header); | 170 new_addr = ForwardedAddr(header); |
| 177 } else { | 171 } else { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 *p = new_obj; | 229 *p = new_obj; |
| 236 // Update the store buffer as needed. | 230 // Update the store buffer as needed. |
| 237 if (visiting_old_object_ != NULL) { | 231 if (visiting_old_object_ != NULL) { |
| 238 VerifiedMemory::Accept(reinterpret_cast<uword>(p), sizeof(*p)); | 232 VerifiedMemory::Accept(reinterpret_cast<uword>(p), sizeof(*p)); |
| 239 UpdateStoreBuffer(p, new_obj); | 233 UpdateStoreBuffer(p, new_obj); |
| 240 } | 234 } |
| 241 } | 235 } |
| 242 | 236 |
| 243 Thread* thread_; | 237 Thread* thread_; |
| 244 Scavenger* scavenger_; | 238 Scavenger* scavenger_; |
| 245 uword from_start_; | 239 SemiSpace* from_; |
| 246 uword from_size_; | |
| 247 Heap* heap_; | 240 Heap* heap_; |
| 248 Heap* vm_heap_; | 241 Heap* vm_heap_; |
| 249 PageSpace* page_space_; | 242 PageSpace* page_space_; |
| 250 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; | 243 typedef std::multimap<RawObject*, RawWeakProperty*> DelaySet; |
| 251 DelaySet delay_set_; | 244 DelaySet delay_set_; |
| 252 GrowableArray<RawObject*> delayed_weak_stack_; | 245 GrowableArray<RawObject*> delayed_weak_stack_; |
| 253 // TODO(cshapiro): use this value to compute survival statistics for | 246 // TODO(cshapiro): use this value to compute survival statistics for |
| 254 // new space growth policy. | 247 // new space growth policy. |
| 255 intptr_t bytes_promoted_; | 248 intptr_t bytes_promoted_; |
| 256 RawObject* visiting_old_object_; | 249 RawObject* visiting_old_object_; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 // going to use for forwarding pointers. | 408 // going to use for forwarding pointers. |
| 416 ASSERT(Object::tags_offset() == 0); | 409 ASSERT(Object::tags_offset() == 0); |
| 417 | 410 |
| 418 // Set initial size resulting in a total of three different levels. | 411 // Set initial size resulting in a total of three different levels. |
| 419 const intptr_t initial_semi_capacity_in_words = max_semi_capacity_in_words / | 412 const intptr_t initial_semi_capacity_in_words = max_semi_capacity_in_words / |
| 420 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); | 413 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); |
| 421 to_ = SemiSpace::New(initial_semi_capacity_in_words); | 414 to_ = SemiSpace::New(initial_semi_capacity_in_words); |
| 422 if (to_ == NULL) { | 415 if (to_ == NULL) { |
| 423 FATAL("Out of memory.\n"); | 416 FATAL("Out of memory.\n"); |
| 424 } | 417 } |
| 425 from_ = NULL; | |
| 426 | 418 |
| 427 // Setup local fields. | 419 // Setup local fields. |
| 428 top_ = FirstObjectStart(); | 420 top_ = FirstObjectStart(); |
| 429 resolved_top_ = top_; | 421 resolved_top_ = top_; |
| 430 end_ = to_->end(); | 422 end_ = to_->end(); |
| 431 | 423 |
| 432 survivor_end_ = FirstObjectStart(); | 424 survivor_end_ = FirstObjectStart(); |
| 433 } | 425 } |
| 434 | 426 |
| 435 | 427 |
| 436 Scavenger::~Scavenger() { | 428 Scavenger::~Scavenger() { |
| 437 ASSERT(!scavenging_); | 429 ASSERT(!scavenging_); |
| 438 ASSERT(from_ == NULL); | |
| 439 to_->Delete(); | 430 to_->Delete(); |
| 440 } | 431 } |
| 441 | 432 |
| 442 | 433 |
| 443 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { | 434 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { |
| 444 if (stats_history_.Size() == 0) { | 435 if (stats_history_.Size() == 0) { |
| 445 return old_size_in_words; | 436 return old_size_in_words; |
| 446 } | 437 } |
| 447 double garbage = stats_history_.Get(0).GarbageFraction(); | 438 double garbage = stats_history_.Get(0).GarbageFraction(); |
| 448 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 439 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { |
| 449 return Utils::Minimum(max_semi_capacity_in_words_, | 440 return Utils::Minimum(max_semi_capacity_in_words_, |
| 450 old_size_in_words * FLAG_new_gen_growth_factor); | 441 old_size_in_words * FLAG_new_gen_growth_factor); |
| 451 } else { | 442 } else { |
| 452 return old_size_in_words; | 443 return old_size_in_words; |
| 453 } | 444 } |
| 454 } | 445 } |
| 455 | 446 |
| 456 | 447 |
| 457 void Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { | 448 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { |
| 458 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { | 449 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { |
| 459 (isolate->gc_prologue_callback())(); | 450 (isolate->gc_prologue_callback())(); |
| 460 } | 451 } |
| 461 Thread::PrepareForGC(); | 452 Thread::PrepareForGC(); |
| 462 // Flip the two semi-spaces so that to_ is always the space for allocating | 453 // Flip the two semi-spaces so that to_ is always the space for allocating |
| 463 // objects. | 454 // objects. |
| 464 from_ = to_; | 455 SemiSpace* from = to_; |
| 465 to_ = SemiSpace::New(NewSizeInWords(from_->size_in_words())); | 456 to_ = SemiSpace::New(NewSizeInWords(from->size_in_words())); |
| 466 if (to_ == NULL) { | 457 if (to_ == NULL) { |
| 467 // TODO(koda): We could try to recover (collect old space, wait for another | 458 // TODO(koda): We could try to recover (collect old space, wait for another |
| 468 // isolate to finish scavenge, etc.). | 459 // isolate to finish scavenge, etc.). |
| 469 FATAL("Out of memory.\n"); | 460 FATAL("Out of memory.\n"); |
| 470 } | 461 } |
| 471 top_ = FirstObjectStart(); | 462 top_ = FirstObjectStart(); |
| 472 resolved_top_ = top_; | 463 resolved_top_ = top_; |
| 473 end_ = to_->end(); | 464 end_ = to_->end(); |
| 465 return from; | |
| 474 } | 466 } |
| 475 | 467 |
| 476 | 468 |
| 477 void Scavenger::Epilogue(Isolate* isolate, | 469 void Scavenger::Epilogue(Isolate* isolate, |
| 470 SemiSpace* from, | |
| 478 bool invoke_api_callbacks) { | 471 bool invoke_api_callbacks) { |
| 479 // All objects in the to space have been copied from the from space at this | 472 // All objects in the to space have been copied from the from space at this |
| 480 // moment. | 473 // moment. |
| 481 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 474 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); |
| 482 if (stats_history_.Size() >= 2) { | 475 if (stats_history_.Size() >= 2) { |
| 483 // Previous scavenge is only given half as much weight. | 476 // Previous scavenge is only given half as much weight. |
| 484 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); | 477 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); |
| 485 avg_frac /= 1.0 + 0.5; // Normalize. | 478 avg_frac /= 1.0 + 0.5; // Normalize. |
| 486 } | 479 } |
| 487 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { | 480 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 499 // being spawned. | 492 // being spawned. |
| 500 { | 493 { |
| 501 PageSpace* page_space = heap_->old_space(); | 494 PageSpace* page_space = heap_->old_space(); |
| 502 MonitorLocker ml(page_space->tasks_lock()); | 495 MonitorLocker ml(page_space->tasks_lock()); |
| 503 if (page_space->tasks() == 0) { | 496 if (page_space->tasks() == 0) { |
| 504 VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); | 497 VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); |
| 505 heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); | 498 heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); |
| 506 } | 499 } |
| 507 } | 500 } |
| 508 #endif // defined(DEBUG) | 501 #endif // defined(DEBUG) |
| 509 from_->Delete(); | 502 from->Delete(); |
| 510 from_ = NULL; | |
| 511 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { | 503 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |
| 512 (isolate->gc_epilogue_callback())(); | 504 (isolate->gc_epilogue_callback())(); |
| 513 } | 505 } |
| 514 } | 506 } |
| 515 | 507 |
| 516 | 508 |
| 517 void Scavenger::IterateStoreBuffers(Isolate* isolate, | 509 void Scavenger::IterateStoreBuffers(Isolate* isolate, |
| 518 ScavengerVisitor* visitor) { | 510 ScavengerVisitor* visitor) { |
| 519 // Iterating through the store buffers. | 511 // Iterating through the store buffers. |
| 520 // Grab the deduplication sets out of the isolate's consolidated store buffer. | 512 // Grab the deduplication sets out of the isolate's consolidated store buffer. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 576 | 568 |
| 577 bool Scavenger::IsUnreachable(RawObject** p) { | 569 bool Scavenger::IsUnreachable(RawObject** p) { |
| 578 RawObject* raw_obj = *p; | 570 RawObject* raw_obj = *p; |
| 579 if (!raw_obj->IsHeapObject()) { | 571 if (!raw_obj->IsHeapObject()) { |
| 580 return false; | 572 return false; |
| 581 } | 573 } |
| 582 if (!raw_obj->IsNewObject()) { | 574 if (!raw_obj->IsNewObject()) { |
| 583 return false; | 575 return false; |
| 584 } | 576 } |
| 585 uword raw_addr = RawObject::ToAddr(raw_obj); | 577 uword raw_addr = RawObject::ToAddr(raw_obj); |
| 586 if (!from_->Contains(raw_addr)) { | 578 if (to_->Contains(raw_addr)) { |
| 587 return false; | 579 return false; |
| 588 } | 580 } |
| 589 uword header = *reinterpret_cast<uword*>(raw_addr); | 581 uword header = *reinterpret_cast<uword*>(raw_addr); |
| 590 if (IsForwarding(header)) { | 582 if (IsForwarding(header)) { |
| 591 uword new_addr = ForwardedAddr(header); | 583 uword new_addr = ForwardedAddr(header); |
| 592 *p = RawObject::FromAddr(new_addr); | 584 *p = RawObject::FromAddr(new_addr); |
| 593 return false; | 585 return false; |
| 594 } | 586 } |
| 595 return true; | 587 return true; |
| 596 } | 588 } |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 810 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { | 802 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { |
| 811 OS::PrintErr("Verifying before Scavenge..."); | 803 OS::PrintErr("Verifying before Scavenge..."); |
| 812 heap_->Verify(kForbidMarked); | 804 heap_->Verify(kForbidMarked); |
| 813 OS::PrintErr(" done.\n"); | 805 OS::PrintErr(" done.\n"); |
| 814 } | 806 } |
| 815 | 807 |
| 816 // Prepare for a scavenge. | 808 // Prepare for a scavenge. |
| 817 SpaceUsage usage_before = GetCurrentUsage(); | 809 SpaceUsage usage_before = GetCurrentUsage(); |
| 818 intptr_t promo_candidate_words = | 810 intptr_t promo_candidate_words = |
| 819 (survivor_end_ - FirstObjectStart()) / kWordSize; | 811 (survivor_end_ - FirstObjectStart()) / kWordSize; |
| 820 Prologue(isolate, invoke_api_callbacks); | 812 SemiSpace* from = Prologue(isolate, invoke_api_callbacks); |
| 821 // The API prologue/epilogue may create/destroy zones, so we must not | 813 // The API prologue/epilogue may create/destroy zones, so we must not |
| 822 // depend on zone allocations surviving beyond the epilogue callback. | 814 // depend on zone allocations surviving beyond the epilogue callback. |
| 823 { | 815 { |
| 824 StackZone zone(isolate); | 816 StackZone zone(isolate); |
| 825 // Setup the visitor and run the scavenge. | 817 // Setup the visitor and run the scavenge. |
| 826 ScavengerVisitor visitor(isolate, this); | 818 ScavengerVisitor visitor(isolate, this, from); |
| 827 page_space->AcquireDataLock(); | 819 page_space->AcquireDataLock(); |
| 828 const bool prologue_weak_are_strong = !invoke_api_callbacks; | 820 const bool prologue_weak_are_strong = !invoke_api_callbacks; |
| 829 IterateRoots(isolate, &visitor, prologue_weak_are_strong); | 821 IterateRoots(isolate, &visitor, prologue_weak_are_strong); |
| 830 int64_t start = OS::GetCurrentTimeMicros(); | 822 int64_t start = OS::GetCurrentTimeMicros(); |
| 831 ProcessToSpace(&visitor); | 823 ProcessToSpace(&visitor); |
| 832 int64_t middle = OS::GetCurrentTimeMicros(); | 824 int64_t middle = OS::GetCurrentTimeMicros(); |
| 833 IterateWeakReferences(isolate, &visitor); | 825 IterateWeakReferences(isolate, &visitor); |
| 834 ScavengerWeakVisitor weak_visitor(this, prologue_weak_are_strong); | 826 ScavengerWeakVisitor weak_visitor(this, prologue_weak_are_strong); |
| 835 // Include the prologue weak handles, since we must process any promotion. | 827 // Include the prologue weak handles, since we must process any promotion. |
| 836 const bool visit_prologue_weak_handles = true; | 828 const bool visit_prologue_weak_handles = true; |
| 837 IterateWeakRoots(isolate, &weak_visitor, visit_prologue_weak_handles); | 829 IterateWeakRoots(isolate, &weak_visitor, visit_prologue_weak_handles); |
| 838 visitor.Finalize(); | 830 visitor.Finalize(); |
| 839 ProcessWeakTables(); | 831 ProcessWeakTables(); |
| 840 page_space->ReleaseDataLock(); | 832 page_space->ReleaseDataLock(); |
| 841 | 833 |
| 842 // Scavenge finished. Run accounting. | 834 // Scavenge finished. Run accounting. |
| 843 int64_t end = OS::GetCurrentTimeMicros(); | 835 int64_t end = OS::GetCurrentTimeMicros(); |
| 844 heap_->RecordTime(kProcessToSpace, middle - start); | 836 heap_->RecordTime(kProcessToSpace, middle - start); |
| 845 heap_->RecordTime(kIterateWeaks, end - middle); | 837 heap_->RecordTime(kIterateWeaks, end - middle); |
| 846 stats_history_.Add( | 838 stats_history_.Add( |
| 847 ScavengeStats(start, end, | 839 ScavengeStats(start, end, |
| 848 usage_before, GetCurrentUsage(), | 840 usage_before, GetCurrentUsage(), |
| 849 promo_candidate_words, | 841 promo_candidate_words, |
| 850 visitor.bytes_promoted() >> kWordSizeLog2)); | 842 visitor.bytes_promoted() >> kWordSizeLog2)); |
| 851 } | 843 } |
| 852 Epilogue(isolate, invoke_api_callbacks); | 844 Epilogue(isolate, from, invoke_api_callbacks); |
| 853 | 845 |
| 854 // TODO(koda): Make verification more compatible with concurrent sweep. | 846 // TODO(koda): Make verification more compatible with concurrent sweep. |
| 855 if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { | 847 if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { |
| 856 OS::PrintErr("Verifying after Scavenge..."); | 848 OS::PrintErr("Verifying after Scavenge..."); |
| 857 heap_->Verify(kForbidMarked); | 849 heap_->Verify(kForbidMarked); |
| 858 OS::PrintErr(" done.\n"); | 850 OS::PrintErr(" done.\n"); |
| 859 } | 851 } |
| 860 | 852 |
| 861 // Done scavenging. Reset the marker. | 853 // Done scavenging. Reset the marker. |
| 862 ASSERT(scavenging_); | 854 ASSERT(scavenging_); |
| 863 scavenging_ = false; | 855 scavenging_ = false; |
| 864 } | 856 } |
| 865 | 857 |
| 866 | 858 |
| 867 void Scavenger::WriteProtect(bool read_only) { | 859 void Scavenger::WriteProtect(bool read_only) { |
| 868 ASSERT(!scavenging_); | 860 ASSERT(!scavenging_); |
| 869 ASSERT(from_ == NULL); | |
| 870 to_->WriteProtect(read_only); | 861 to_->WriteProtect(read_only); |
| 871 } | 862 } |
| 872 | 863 |
| 873 | 864 |
| 874 void Scavenger::PrintToJSONObject(JSONObject* object) const { | 865 void Scavenger::PrintToJSONObject(JSONObject* object) const { |
| 875 Isolate* isolate = Isolate::Current(); | 866 Isolate* isolate = Isolate::Current(); |
| 876 ASSERT(isolate != NULL); | 867 ASSERT(isolate != NULL); |
| 877 JSONObject space(object, "new"); | 868 JSONObject space(object, "new"); |
| 878 space.AddProperty("type", "HeapSpace"); | 869 space.AddProperty("type", "HeapSpace"); |
| 879 space.AddProperty("name", "new"); | 870 space.AddProperty("name", "new"); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 903 } | 894 } |
| 904 | 895 |
| 905 | 896 |
| 906 void Scavenger::FreeExternal(intptr_t size) { | 897 void Scavenger::FreeExternal(intptr_t size) { |
| 907 ASSERT(size >= 0); | 898 ASSERT(size >= 0); |
| 908 external_size_ -= size; | 899 external_size_ -= size; |
| 909 ASSERT(external_size_ >= 0); | 900 ASSERT(external_size_ >= 0); |
| 910 } | 901 } |
| 911 | 902 |
| 912 } // namespace dart | 903 } // namespace dart |
| OLD | NEW |