| 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 "vm/dart.h" | 7 #include "vm/dart.h" |
| 8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
| 9 #include "vm/object.h" | 9 #include "vm/object.h" |
| 10 #include "vm/stack_frame.h" | 10 #include "vm/stack_frame.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 | 63 |
| 64 // Fast exit if the raw object is a Smi. | 64 // Fast exit if the raw object is a Smi. |
| 65 if (!raw_obj->IsHeapObject()) return; | 65 if (!raw_obj->IsHeapObject()) return; |
| 66 | 66 |
| 67 uword raw_addr = RawObject::ToAddr(raw_obj); | 67 uword raw_addr = RawObject::ToAddr(raw_obj); |
| 68 // Objects should be contained in the heap. | 68 // Objects should be contained in the heap. |
| 69 // TODO(iposva): Add an appropriate assert here or in the return block | 69 // TODO(iposva): Add an appropriate assert here or in the return block |
| 70 // below. | 70 // below. |
| 71 // The scavenger is only interested in objects located in the from space. | 71 // The scavenger is only interested in objects located in the from space. |
| 72 if (!scavenger_->from_->Contains(raw_addr)) { | 72 if (!scavenger_->from_->Contains(raw_addr)) { |
| 73 // Addresses being visited cannot point in the to space. As this would | |
| 74 // either mean the pointer is being visited twice or this pointer has not | |
| 75 // been evacuated during the last scavenge. Both of these situations are | |
| 76 // an error. | |
| 77 ASSERT(!scavenger_->to_->Contains(raw_addr)); | |
| 78 return; | 73 return; |
| 79 } | 74 } |
| 80 | 75 |
| 81 // Read the header word of the object and determine if the object has | 76 // Read the header word of the object and determine if the object has |
| 82 // already been copied. | 77 // already been copied. |
| 83 uword header = *reinterpret_cast<uword*>(raw_addr); | 78 uword header = *reinterpret_cast<uword*>(raw_addr); |
| 84 uword new_addr = 0; | 79 uword new_addr = 0; |
| 85 if (IsForwarding(header)) { | 80 if (IsForwarding(header)) { |
| 86 // Get the new location of the object. | 81 // Get the new location of the object. |
| 87 new_addr = ForwardedAddr(header); | 82 new_addr = ForwardedAddr(header); |
| 88 } else { | 83 } else { |
| 89 intptr_t size = raw_obj->Size(); | 84 intptr_t size = raw_obj->Size(); |
| 90 // TODO(iposva): Check whether object should be promoted. | 85 // Check whether object should be promoted. |
| 91 new_addr = scavenger_->TryAllocate(size); | 86 if (scavenger_->survivor_end_ <= raw_addr) { |
| 87 // Not a survivor of a previous scavenge. Just copy the object into the |
| 88 // to space. |
| 89 new_addr = scavenger_->TryAllocate(size); |
| 90 } else { |
| 91 // TODO(iposva): Experiment with less aggressive promotion. For example |
| 92 // a coin toss determines if an object is promoted or whether it should |
| 93 // survive in this generation. |
| 94 // |
| 95 // This object is a survivor of a previous scavenge. Attempt to promote |
| 96 // the object. |
| 97 new_addr = heap_->TryAllocate(size, Heap::kOld); |
| 98 if (new_addr != 0) { |
| 99 // If promotion succeeded then we need to remember it so that it can |
| 100 // be traversed later. |
| 101 scavenger_->PushToPromotedStack(new_addr); |
| 102 } else { |
| 103 // Promotion did not succeed. Copy into the to space instead. |
| 104 scavenger_->had_promotion_failure_ = true; |
| 105 new_addr = scavenger_->TryAllocate(size); |
| 106 } |
| 107 } |
| 92 // During a scavenge we always succeed to at least copy all of the | 108 // During a scavenge we always succeed to at least copy all of the |
| 93 // current objects to the to space. | 109 // current objects to the to space. |
| 94 ASSERT(new_addr != 0); | 110 ASSERT(new_addr != 0); |
| 95 // Copy the object to the new location. | 111 // Copy the object to the new location. |
| 96 memmove(reinterpret_cast<void*>(new_addr), | 112 memmove(reinterpret_cast<void*>(new_addr), |
| 97 reinterpret_cast<void*>(raw_addr), | 113 reinterpret_cast<void*>(raw_addr), |
| 98 size); | 114 size); |
| 99 // Remember forwarding address. | 115 // Remember forwarding address. |
| 100 ForwardTo(raw_addr, new_addr); | 116 ForwardTo(raw_addr, new_addr); |
| 101 } | 117 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 uword middle = space_->start() + semi_space_size; | 177 uword middle = space_->start() + semi_space_size; |
| 162 from_ = new MemoryRegion(reinterpret_cast<void*>(middle), semi_space_size); | 178 from_ = new MemoryRegion(reinterpret_cast<void*>(middle), semi_space_size); |
| 163 | 179 |
| 164 // Make sure that the two semi-spaces are aligned properly. | 180 // Make sure that the two semi-spaces are aligned properly. |
| 165 ASSERT(Utils::IsAligned(to_->start(), kObjectAlignment)); | 181 ASSERT(Utils::IsAligned(to_->start(), kObjectAlignment)); |
| 166 ASSERT(Utils::IsAligned(from_->start(), kObjectAlignment)); | 182 ASSERT(Utils::IsAligned(from_->start(), kObjectAlignment)); |
| 167 | 183 |
| 168 // Setup local fields. | 184 // Setup local fields. |
| 169 top_ = FirstObjectStart(); | 185 top_ = FirstObjectStart(); |
| 170 end_ = to_->end(); | 186 end_ = to_->end(); |
| 187 |
| 188 survivor_end_ = FirstObjectStart(); |
| 189 |
| 171 #if defined(DEBUG) | 190 #if defined(DEBUG) |
| 172 memset(to_->pointer(), 0xf3, to_->size()); | 191 memset(to_->pointer(), 0xf3, to_->size()); |
| 173 memset(from_->pointer(), 0xf3, from_->size()); | 192 memset(from_->pointer(), 0xf3, from_->size()); |
| 174 #endif // defined(DEBUG) | 193 #endif // defined(DEBUG) |
| 175 } | 194 } |
| 176 | 195 |
| 177 | 196 |
| 178 Scavenger::~Scavenger() { | 197 Scavenger::~Scavenger() { |
| 179 delete to_; | 198 delete to_; |
| 180 delete from_; | 199 delete from_; |
| 181 delete space_; | 200 delete space_; |
| 182 } | 201 } |
| 183 | 202 |
| 184 | 203 |
| 185 void Scavenger::Prologue() { | 204 void Scavenger::Prologue() { |
| 186 // Flip the two semi-spaces so that to_ is always the space for allocating | 205 // Flip the two semi-spaces so that to_ is always the space for allocating |
| 187 // objects. | 206 // objects. |
| 188 MemoryRegion* temp = from_; | 207 MemoryRegion* temp = from_; |
| 189 from_ = to_; | 208 from_ = to_; |
| 190 to_ = temp; | 209 to_ = temp; |
| 191 top_ = FirstObjectStart(); | 210 top_ = FirstObjectStart(); |
| 192 end_ = to_->end(); | 211 end_ = to_->end(); |
| 193 } | 212 } |
| 194 | 213 |
| 195 | 214 |
| 196 void Scavenger::Epilogue() { | 215 void Scavenger::Epilogue() { |
| 216 // All objects in the to space have been copied from the from space at this |
| 217 // moment. |
| 218 survivor_end_ = top_; |
| 219 |
| 197 #if defined(DEBUG) | 220 #if defined(DEBUG) |
| 198 memset(from_->pointer(), 0xf3, from_->size()); | 221 memset(from_->pointer(), 0xf3, from_->size()); |
| 199 #endif // defined(DEBUG) | 222 #endif // defined(DEBUG) |
| 200 } | 223 } |
| 201 | 224 |
| 202 | 225 |
| 203 void Scavenger::IterateRoots(Isolate* isolate, ObjectPointerVisitor* visitor) { | 226 void Scavenger::IterateRoots(Isolate* isolate, ObjectPointerVisitor* visitor) { |
| 204 isolate->VisitStrongObjectPointers(visitor, | 227 isolate->VisitStrongObjectPointers(visitor, |
| 205 StackFrameIterator::kDontValidateFrames); | 228 StackFrameIterator::kDontValidateFrames); |
| 206 heap_->IterateOldPointers(visitor); | 229 heap_->IterateOldPointers(visitor); |
| 207 } | 230 } |
| 208 | 231 |
| 209 | 232 |
| 210 void Scavenger::IterateWeakRoots(Isolate* isolate, | 233 void Scavenger::IterateWeakRoots(Isolate* isolate, |
| 211 ObjectPointerVisitor* visitor) { | 234 ObjectPointerVisitor* visitor) { |
| 212 isolate->VisitWeakObjectPointers(visitor); | 235 isolate->VisitWeakObjectPointers(visitor); |
| 213 } | 236 } |
| 214 | 237 |
| 215 | 238 |
| 216 void Scavenger::ProcessToSpace(ObjectPointerVisitor* visitor) { | 239 void Scavenger::ProcessToSpace(ObjectPointerVisitor* visitor) { |
| 217 uword resolved_top = FirstObjectStart(); | 240 uword resolved_top = FirstObjectStart(); |
| 218 // Iterate until all work has been drained. | 241 // Iterate until all work has been drained. |
| 219 while (resolved_top < top_) { | 242 while ((resolved_top < top_) || PromotedStackHasMore()) { |
| 220 RawObject* raw_obj = RawObject::FromAddr(resolved_top); | 243 while (resolved_top < top_) { |
| 221 resolved_top += raw_obj->VisitPointers(visitor); | 244 RawObject* raw_obj = RawObject::FromAddr(resolved_top); |
| 245 resolved_top += raw_obj->VisitPointers(visitor); |
| 246 } |
| 247 while (PromotedStackHasMore()) { |
| 248 RawObject* raw_object = RawObject::FromAddr(PopFromPromotedStack()); |
| 249 // Resolve or copy all objects referred to by the current object. This |
| 250 // can potentially push more objects on this stack as well as add more |
| 251 // objects to be resolved in the to space. |
| 252 raw_object->VisitPointers(visitor); |
| 253 } |
| 222 } | 254 } |
| 223 } | 255 } |
| 224 | 256 |
| 225 | 257 |
| 226 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 258 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
| 227 uword cur = FirstObjectStart(); | 259 uword cur = FirstObjectStart(); |
| 228 while (cur < top_) { | 260 while (cur < top_) { |
| 229 RawObject* raw_obj = RawObject::FromAddr(cur); | 261 RawObject* raw_obj = RawObject::FromAddr(cur); |
| 230 cur += raw_obj->VisitPointers(visitor); | 262 cur += raw_obj->VisitPointers(visitor); |
| 231 } | 263 } |
| 232 } | 264 } |
| 233 | 265 |
| 234 | 266 |
| 235 void Scavenger::Scavenge() { | 267 void Scavenger::Scavenge() { |
| 236 // Scavenging is not reentrant. Make sure that is the case. | 268 // Scavenging is not reentrant. Make sure that is the case. |
| 237 ASSERT(!scavenging_); | 269 ASSERT(!scavenging_); |
| 238 scavenging_ = true; | 270 scavenging_ = true; |
| 239 Isolate* isolate = Isolate::Current(); | 271 Isolate* isolate = Isolate::Current(); |
| 240 NoHandleScope no_handles(isolate); | 272 NoHandleScope no_handles(isolate); |
| 241 | 273 |
| 274 if (FLAG_verify_before_gc) { |
| 275 OS::PrintErr("Verifying before Scavenge... "); |
| 276 heap_->Verify(); |
| 277 OS::PrintErr(" done.\n"); |
| 278 } |
| 279 |
| 242 Timer timer(FLAG_verbose_gc, "Scavenge"); | 280 Timer timer(FLAG_verbose_gc, "Scavenge"); |
| 243 timer.Start(); | 281 timer.Start(); |
| 244 // Setup the visitor and run a scavenge. | 282 // Setup the visitor and run a scavenge. |
| 245 ScavengerVisitor visitor(this); | 283 ScavengerVisitor visitor(this); |
| 246 Prologue(); | 284 Prologue(); |
| 247 IterateRoots(isolate, &visitor); | 285 IterateRoots(isolate, &visitor); |
| 248 ProcessToSpace(&visitor); | 286 ProcessToSpace(&visitor); |
| 249 ScavengerWeakVisitor weak_visitor(this); | 287 ScavengerWeakVisitor weak_visitor(this); |
| 250 IterateWeakRoots(isolate, &weak_visitor); | 288 IterateWeakRoots(isolate, &weak_visitor); |
| 251 Epilogue(); | 289 Epilogue(); |
| 252 timer.Stop(); | 290 timer.Stop(); |
| 253 if (FLAG_verbose_gc) { | 291 if (FLAG_verbose_gc) { |
| 254 OS::PrintErr("Scavenge[%d]: %dus\n", count_, timer.TotalElapsedTime()); | 292 OS::PrintErr("Scavenge[%d]: %dus\n", count_, timer.TotalElapsedTime()); |
| 255 } | 293 } |
| 256 | 294 |
| 295 if (FLAG_verify_after_gc) { |
| 296 OS::PrintErr("Verifying after Scavenge... "); |
| 297 heap_->Verify(); |
| 298 OS::PrintErr(" done.\n"); |
| 299 } |
| 300 |
| 257 count_++; | 301 count_++; |
| 258 // Done scavenging. Reset the marker. | 302 // Done scavenging. Reset the marker. |
| 259 ASSERT(scavenging_); | 303 ASSERT(scavenging_); |
| 260 scavenging_ = false; | 304 scavenging_ = false; |
| 261 } | 305 } |
| 262 | 306 |
| 263 } // namespace dart | 307 } // namespace dart |
| OLD | NEW |