Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/heap.h" | 5 #include "vm/heap.h" |
| 6 | 6 |
| 7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
| 8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
| 9 #include "vm/compiler_stats.h" | 9 #include "vm/compiler_stats.h" |
| 10 #include "vm/flags.h" | 10 #include "vm/flags.h" |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 DEFINE_FLAG(bool, verify_before_gc, false, | 25 DEFINE_FLAG(bool, verify_before_gc, false, |
| 26 "Enables heap verification before GC."); | 26 "Enables heap verification before GC."); |
| 27 DEFINE_FLAG(bool, verify_after_gc, false, | 27 DEFINE_FLAG(bool, verify_after_gc, false, |
| 28 "Enables heap verification after GC."); | 28 "Enables heap verification after GC."); |
| 29 DEFINE_FLAG(bool, gc_at_alloc, false, "GC at every allocation."); | 29 DEFINE_FLAG(bool, gc_at_alloc, false, "GC at every allocation."); |
| 30 DEFINE_FLAG(int, new_gen_heap_size, 32, "new gen heap size in MB," | 30 DEFINE_FLAG(int, new_gen_heap_size, 32, "new gen heap size in MB," |
| 31 "e.g: --new_gen_heap_size=64 allocates a 64MB new gen heap"); | 31 "e.g: --new_gen_heap_size=64 allocates a 64MB new gen heap"); |
| 32 DEFINE_FLAG(int, old_gen_heap_size, Heap::kHeapSizeInMB, | 32 DEFINE_FLAG(int, old_gen_heap_size, Heap::kHeapSizeInMB, |
| 33 "old gen heap size in MB," | 33 "old gen heap size in MB," |
| 34 "e.g: --old_gen_heap_size=1024 allocates a 1024MB old gen heap"); | 34 "e.g: --old_gen_heap_size=1024 allocates a 1024MB old gen heap"); |
| 35 DEFINE_FLAG(int, code_heap_size, Heap::kCodeHeapSizeInMB, | |
| 36 "code heap size in MB," | |
| 37 "e.g: --code_heap_size=8 allocates a 8MB code heap"); | |
| 38 | 35 |
| 39 Heap::Heap() : read_only_(false) { | 36 Heap::Heap() : read_only_(false) { |
| 40 new_space_ = new Scavenger(this, | 37 new_space_ = new Scavenger(this, |
| 41 (FLAG_new_gen_heap_size * MB), | 38 (FLAG_new_gen_heap_size * MB), |
| 42 kNewObjectAlignmentOffset); | 39 kNewObjectAlignmentOffset); |
| 43 old_space_ = new PageSpace(this, (FLAG_old_gen_heap_size * MB)); | 40 old_space_ = new PageSpace(this, (FLAG_old_gen_heap_size * MB)); |
| 44 code_space_ = new PageSpace(this, (FLAG_code_heap_size * MB), true); | |
| 45 } | 41 } |
| 46 | 42 |
| 47 | 43 |
| 48 Heap::~Heap() { | 44 Heap::~Heap() { |
| 49 delete new_space_; | 45 delete new_space_; |
| 50 delete old_space_; | 46 delete old_space_; |
| 51 delete code_space_; | |
| 52 } | 47 } |
| 53 | 48 |
| 54 | 49 |
| 55 uword Heap::AllocateNew(intptr_t size) { | 50 uword Heap::AllocateNew(intptr_t size) { |
| 56 ASSERT(Isolate::Current()->no_gc_scope_depth() == 0); | 51 ASSERT(Isolate::Current()->no_gc_scope_depth() == 0); |
| 57 uword addr = new_space_->TryAllocate(size); | 52 uword addr = new_space_->TryAllocate(size); |
| 58 if (addr != 0) { | 53 if (addr != 0) { |
| 59 return addr; | 54 return addr; |
| 60 } | 55 } |
| 61 CollectGarbage(kNew); | 56 CollectGarbage(kNew); |
| 62 addr = new_space_->TryAllocate(size); | 57 addr = new_space_->TryAllocate(size); |
| 63 if (addr != 0) { | 58 if (addr != 0) { |
| 64 return addr; | 59 return addr; |
| 65 } | 60 } |
| 66 return AllocateOld(size); | 61 return AllocateOld(size, HeapPage::kData); |
| 67 } | 62 } |
| 68 | 63 |
| 69 | 64 |
| 70 uword Heap::AllocateOld(intptr_t size) { | 65 uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) { |
| 71 ASSERT(Isolate::Current()->no_gc_scope_depth() == 0); | 66 ASSERT(Isolate::Current()->no_gc_scope_depth() == 0); |
| 72 uword addr = old_space_->TryAllocate(size); | 67 uword addr = old_space_->TryAllocate(size, type); |
| 73 if (addr == 0) { | 68 if (addr == 0) { |
| 74 CollectAllGarbage(); | 69 CollectAllGarbage(); |
| 75 addr = old_space_->TryAllocate(size, PageSpace::kForceGrowth); | 70 addr = old_space_->TryAllocate(size, type, PageSpace::kForceGrowth); |
| 76 if (addr == 0) { | 71 if (addr == 0) { |
| 77 OS::PrintErr("Exhausted heap space, trying to allocate %"Pd" bytes.\n", | 72 OS::PrintErr("Exhausted heap space, trying to allocate %"Pd" bytes.\n", |
| 78 size); | 73 size); |
| 79 } | 74 } |
| 80 } | 75 } |
| 81 return addr; | 76 return addr; |
| 82 } | 77 } |
| 83 | 78 |
| 84 | 79 |
| 85 uword Heap::AllocateCode(PageSpace* space, intptr_t size) { | |
| 86 ASSERT(Isolate::Current()->no_gc_scope_depth() == 0); | |
| 87 ASSERT(Utils::IsAligned(size, OS::PreferredCodeAlignment())); | |
| 88 uword addr = space->TryAllocate(size); | |
| 89 if (addr == 0) { | |
| 90 // TODO(iposva): Support GC. | |
| 91 FATAL("Exhausted code heap space."); | |
| 92 } | |
| 93 if (FLAG_compiler_stats) { | |
| 94 CompilerStats::code_allocated += size; | |
| 95 } | |
| 96 return addr; | |
| 97 } | |
| 98 | |
| 99 | |
| 100 bool Heap::Contains(uword addr) const { | 80 bool Heap::Contains(uword addr) const { |
| 101 return new_space_->Contains(addr) || | 81 return new_space_->Contains(addr) || |
| 102 old_space_->Contains(addr) || | 82 old_space_->Contains(addr); |
| 103 code_space_->Contains(addr); | |
| 104 } | 83 } |
| 105 | 84 |
| 106 | 85 |
| 107 bool Heap::NewContains(uword addr) const { | 86 bool Heap::NewContains(uword addr) const { |
| 108 return new_space_->Contains(addr); | 87 return new_space_->Contains(addr); |
| 109 } | 88 } |
| 110 | 89 |
| 111 | 90 |
| 112 bool Heap::OldContains(uword addr) const { | 91 bool Heap::OldContains(uword addr) const { |
| 113 return old_space_->Contains(addr); | 92 return old_space_->Contains(addr); |
| 114 } | 93 } |
| 115 | 94 |
| 116 | 95 |
| 117 bool Heap::CodeContains(uword addr) const { | 96 bool Heap::CodeContains(uword addr) const { |
| 118 return code_space_->Contains(addr); | 97 return old_space_->Contains(addr, HeapPage::kExecutable); |
| 119 } | 98 } |
| 120 | 99 |
| 121 | 100 |
| 122 void Heap::IterateObjects(ObjectVisitor* visitor) { | 101 void Heap::IterateObjects(ObjectVisitor* visitor) { |
| 123 new_space_->VisitObjects(visitor); | 102 new_space_->VisitObjects(visitor); |
| 124 old_space_->VisitObjects(visitor); | 103 old_space_->VisitObjects(visitor); |
| 125 code_space_->VisitObjects(visitor); | |
| 126 } | 104 } |
| 127 | 105 |
| 128 | 106 |
| 129 void Heap::IteratePointers(ObjectPointerVisitor* visitor) { | 107 void Heap::IteratePointers(ObjectPointerVisitor* visitor) { |
| 130 new_space_->VisitObjectPointers(visitor); | 108 new_space_->VisitObjectPointers(visitor); |
| 131 old_space_->VisitObjectPointers(visitor); | 109 old_space_->VisitObjectPointers(visitor); |
| 132 code_space_->VisitObjectPointers(visitor); | |
| 133 } | 110 } |
| 134 | 111 |
| 135 | 112 |
| 136 void Heap::IterateNewPointers(ObjectPointerVisitor* visitor) { | 113 void Heap::IterateNewPointers(ObjectPointerVisitor* visitor) { |
| 137 new_space_->VisitObjectPointers(visitor); | 114 new_space_->VisitObjectPointers(visitor); |
| 138 } | 115 } |
| 139 | 116 |
| 140 | 117 |
| 141 void Heap::IterateOldPointers(ObjectPointerVisitor* visitor) { | 118 void Heap::IterateOldPointers(ObjectPointerVisitor* visitor) { |
| 142 old_space_->VisitObjectPointers(visitor); | 119 old_space_->VisitObjectPointers(visitor); |
| 143 code_space_->VisitObjectPointers(visitor); | |
| 144 } | |
| 145 | |
| 146 | |
| 147 void Heap::IterateCodePointers(ObjectPointerVisitor* visitor) { | |
| 148 code_space_->VisitObjectPointers(visitor); | |
| 149 } | 120 } |
| 150 | 121 |
| 151 | 122 |
| 152 void Heap::IterateNewObjects(ObjectVisitor* visitor) { | 123 void Heap::IterateNewObjects(ObjectVisitor* visitor) { |
| 153 new_space_->VisitObjects(visitor); | 124 new_space_->VisitObjects(visitor); |
| 154 } | 125 } |
| 155 | 126 |
| 156 | 127 |
| 157 void Heap::IterateOldObjects(ObjectVisitor* visitor) { | 128 void Heap::IterateOldObjects(ObjectVisitor* visitor) { |
| 158 old_space_->VisitObjects(visitor); | 129 old_space_->VisitObjects(visitor); |
| 159 code_space_->VisitObjects(visitor); | |
| 160 } | 130 } |
| 161 | 131 |
| 162 | 132 |
| 163 void Heap::IterateCodeObjects(ObjectVisitor* visitor) { | 133 RawInstructions* Heap::FindObjectInOldSpace(FindObjectVisitor* visitor) { |
|
siva
2012/10/25 22:29:52
The signature and name of the function does not se
Ivan Posva
2012/10/25 23:45:41
I'll stick with this second option.
| |
| 164 code_space_->VisitObjects(visitor); | |
| 165 } | |
| 166 | |
| 167 | |
| 168 RawInstructions* Heap::FindObjectInCodeSpace(FindObjectVisitor* visitor) { | |
| 169 // The code heap can only have RawInstructions objects. | 134 // The code heap can only have RawInstructions objects. |
|
siva
2012/10/25 22:29:52
This comment doesn't jive anymore...
Ivan Posva
2012/10/25 23:45:41
Done.
| |
| 170 RawObject* raw_obj = code_space_->FindObject(visitor); | 135 RawObject* raw_obj = old_space_->FindObject(visitor); |
| 171 ASSERT((raw_obj == Object::null()) || | 136 ASSERT((raw_obj == Object::null()) || |
| 172 (raw_obj->GetClassId() == kInstructionsCid)); | 137 (raw_obj->GetClassId() == kInstructionsCid)); |
|
siva
2012/10/25 22:29:52
If we choose to go with the generic find object fu
Ivan Posva
2012/10/25 23:45:41
Went the other way...
| |
| 173 return reinterpret_cast<RawInstructions*>(raw_obj); | 138 return reinterpret_cast<RawInstructions*>(raw_obj); |
| 174 } | 139 } |
| 175 | 140 |
| 176 | 141 |
| 177 void Heap::CollectGarbage(Space space, ApiCallbacks api_callbacks) { | 142 void Heap::CollectGarbage(Space space, ApiCallbacks api_callbacks) { |
| 178 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks); | 143 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks); |
| 179 switch (space) { | 144 switch (space) { |
| 180 case kNew: { | 145 case kNew: { |
| 181 new_space_->Scavenge(invoke_api_callbacks, | 146 new_space_->Scavenge(invoke_api_callbacks, |
| 182 GCReasonToString(kNewSpace)); | 147 GCReasonToString(kNewSpace)); |
| 183 if (new_space_->HadPromotionFailure()) { | 148 if (new_space_->HadPromotionFailure()) { |
| 184 old_space_->MarkSweep(true, | 149 old_space_->MarkSweep(true, |
| 185 GCReasonToString(kPromotionFailure)); | 150 GCReasonToString(kPromotionFailure)); |
| 186 } | 151 } |
| 187 break; | 152 break; |
| 188 } | 153 } |
| 189 case kOld: | 154 case kOld: |
| 155 case kCode: | |
| 190 old_space_->MarkSweep(invoke_api_callbacks, | 156 old_space_->MarkSweep(invoke_api_callbacks, |
| 191 GCReasonToString(kOldSpace)); | 157 GCReasonToString(kOldSpace)); |
| 192 break; | 158 break; |
| 193 case kCode: | |
| 194 UNIMPLEMENTED(); | |
| 195 code_space_->MarkSweep(invoke_api_callbacks, | |
| 196 GCReasonToString(kCodeSpace)); | |
| 197 break; | |
| 198 default: | 159 default: |
| 199 UNREACHABLE(); | 160 UNREACHABLE(); |
| 200 } | 161 } |
| 201 if (FLAG_verbose_gc) { | 162 if (FLAG_verbose_gc) { |
| 202 PrintSizes(); | 163 PrintSizes(); |
| 203 } | 164 } |
| 204 } | 165 } |
| 205 | 166 |
| 206 | 167 |
| 207 void Heap::CollectGarbage(Space space) { | 168 void Heap::CollectGarbage(Space space) { |
| 208 ApiCallbacks api_callbacks; | 169 ApiCallbacks api_callbacks; |
| 209 if (space == kOld) { | 170 if (space == kOld) { |
| 210 api_callbacks = kInvokeApiCallbacks; | 171 api_callbacks = kInvokeApiCallbacks; |
| 211 } else { | 172 } else { |
| 212 api_callbacks = kIgnoreApiCallbacks; | 173 api_callbacks = kIgnoreApiCallbacks; |
| 213 } | 174 } |
| 214 CollectGarbage(space, api_callbacks); | 175 CollectGarbage(space, api_callbacks); |
| 215 } | 176 } |
| 216 | 177 |
| 217 | 178 |
| 218 void Heap::CollectAllGarbage() { | 179 void Heap::CollectAllGarbage() { |
| 219 const char* gc_reason = GCReasonToString(kFull); | 180 const char* gc_reason = GCReasonToString(kFull); |
| 220 new_space_->Scavenge(kInvokeApiCallbacks, gc_reason); | 181 new_space_->Scavenge(kInvokeApiCallbacks, gc_reason); |
| 221 old_space_->MarkSweep(kInvokeApiCallbacks, gc_reason); | 182 old_space_->MarkSweep(kInvokeApiCallbacks, gc_reason); |
| 222 // TODO(iposva): Merge old and code space. | |
| 223 // code_space_->MarkSweep(kInvokeApiCallbacks, gc_reason); | |
| 224 if (FLAG_verbose_gc) { | 183 if (FLAG_verbose_gc) { |
| 225 PrintSizes(); | 184 PrintSizes(); |
| 226 } | 185 } |
| 227 } | 186 } |
| 228 | 187 |
| 229 | 188 |
| 230 void Heap::EnableGrowthControl() { | 189 void Heap::EnableGrowthControl() { |
| 231 old_space_->EnableGrowthControl(); | 190 old_space_->EnableGrowthControl(); |
| 232 } | 191 } |
| 233 | 192 |
| 234 | 193 |
| 235 void Heap::WriteProtect(bool read_only) { | 194 void Heap::WriteProtect(bool read_only) { |
| 236 read_only_ = read_only; | 195 read_only_ = read_only; |
| 237 new_space_->WriteProtect(read_only); | 196 new_space_->WriteProtect(read_only); |
| 238 old_space_->WriteProtect(read_only); | 197 old_space_->WriteProtect(read_only); |
| 239 // TODO(iposva): Merge old and code space. | |
| 240 // code_space_->WriteProtect(read_only); | |
| 241 } | 198 } |
| 242 | 199 |
| 243 | 200 |
| 244 uword Heap::TopAddress() { | 201 uword Heap::TopAddress() { |
| 245 return reinterpret_cast<uword>(new_space_->TopAddress()); | 202 return reinterpret_cast<uword>(new_space_->TopAddress()); |
| 246 } | 203 } |
| 247 | 204 |
| 248 | 205 |
| 249 uword Heap::EndAddress() { | 206 uword Heap::EndAddress() { |
| 250 return reinterpret_cast<uword>(new_space_->EndAddress()); | 207 return reinterpret_cast<uword>(new_space_->EndAddress()); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 261 void Heap::StartEndAddress(uword* start, uword* end) const { | 218 void Heap::StartEndAddress(uword* start, uword* end) const { |
| 262 ASSERT(new_space_->capacity() != 0); | 219 ASSERT(new_space_->capacity() != 0); |
| 263 new_space_->StartEndAddress(start, end); | 220 new_space_->StartEndAddress(start, end); |
| 264 if (old_space_->capacity() != 0) { | 221 if (old_space_->capacity() != 0) { |
| 265 uword old_start; | 222 uword old_start; |
| 266 uword old_end; | 223 uword old_end; |
| 267 old_space_->StartEndAddress(&old_start, &old_end); | 224 old_space_->StartEndAddress(&old_start, &old_end); |
| 268 *start = Utils::Minimum(old_start, *start); | 225 *start = Utils::Minimum(old_start, *start); |
| 269 *end = Utils::Maximum(old_end, *end); | 226 *end = Utils::Maximum(old_end, *end); |
| 270 } | 227 } |
| 271 if (code_space_->capacity() != 0) { | |
| 272 uword code_start; | |
| 273 uword code_end; | |
| 274 code_space_->StartEndAddress(&code_start, &code_end); | |
| 275 *start = Utils::Minimum(code_start, *start); | |
| 276 *end = Utils::Maximum(code_end, *end); | |
| 277 } | |
| 278 ASSERT(*start <= *end); | 228 ASSERT(*start <= *end); |
| 279 } | 229 } |
| 280 | 230 |
| 281 | 231 |
| 282 ObjectSet* Heap::CreateAllocatedObjectSet() const { | 232 ObjectSet* Heap::CreateAllocatedObjectSet() const { |
| 283 Isolate* isolate = Isolate::Current(); | 233 Isolate* isolate = Isolate::Current(); |
| 284 uword start, end; | 234 uword start, end; |
| 285 isolate->heap()->StartEndAddress(&start, &end); | 235 isolate->heap()->StartEndAddress(&start, &end); |
| 286 | 236 |
| 287 Isolate* vm_isolate = Dart::vm_isolate(); | 237 Isolate* vm_isolate = Dart::vm_isolate(); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 305 VerifyPointersVisitor visitor(isolate, allocated_set); | 255 VerifyPointersVisitor visitor(isolate, allocated_set); |
| 306 isolate->heap()->IteratePointers(&visitor); | 256 isolate->heap()->IteratePointers(&visitor); |
| 307 delete allocated_set; | 257 delete allocated_set; |
| 308 // Only returning a value so that Heap::Validate can be called from an ASSERT. | 258 // Only returning a value so that Heap::Validate can be called from an ASSERT. |
| 309 return true; | 259 return true; |
| 310 } | 260 } |
| 311 | 261 |
| 312 | 262 |
| 313 void Heap::PrintSizes() const { | 263 void Heap::PrintSizes() const { |
| 314 OS::PrintErr("New space (%"Pd"k of %"Pd"k) " | 264 OS::PrintErr("New space (%"Pd"k of %"Pd"k) " |
| 315 "Old space (%"Pd"k of %"Pd"k) " | 265 "Old space (%"Pd"k of %"Pd"k)\n", |
| 316 "Code space (%"Pd"k of %"Pd"k)\n", | |
| 317 (new_space_->in_use() / KB), (new_space_->capacity() / KB), | 266 (new_space_->in_use() / KB), (new_space_->capacity() / KB), |
| 318 (old_space_->in_use() / KB), (old_space_->capacity() / KB), | 267 (old_space_->in_use() / KB), (old_space_->capacity() / KB)); |
| 319 (code_space_->in_use() / KB), (code_space_->capacity() / KB)); | |
| 320 } | 268 } |
| 321 | 269 |
| 322 | 270 |
| 323 void Heap::Profile(Dart_HeapProfileWriteCallback callback, void* stream) const { | 271 void Heap::Profile(Dart_HeapProfileWriteCallback callback, void* stream) const { |
| 324 HeapProfiler profiler(callback, stream); | 272 HeapProfiler profiler(callback, stream); |
| 325 | 273 |
| 326 // Dump the root set. | 274 // Dump the root set. |
| 327 HeapProfilerRootVisitor root_visitor(&profiler); | 275 HeapProfilerRootVisitor root_visitor(&profiler); |
| 328 Isolate* isolate = Isolate::Current(); | 276 Isolate* isolate = Isolate::Current(); |
| 329 Isolate* vm_isolate = Dart::vm_isolate(); | 277 Isolate* vm_isolate = Dart::vm_isolate(); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 isolate()->IncrementNoGCScopeDepth(); | 339 isolate()->IncrementNoGCScopeDepth(); |
| 392 } | 340 } |
| 393 | 341 |
| 394 | 342 |
| 395 NoGCScope::~NoGCScope() { | 343 NoGCScope::~NoGCScope() { |
| 396 isolate()->DecrementNoGCScopeDepth(); | 344 isolate()->DecrementNoGCScopeDepth(); |
| 397 } | 345 } |
| 398 #endif // defined(DEBUG) | 346 #endif // defined(DEBUG) |
| 399 | 347 |
| 400 } // namespace dart | 348 } // namespace dart |
| OLD | NEW |