| 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/gc_marker.h" | 5 #include "vm/gc_marker.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 it->second->VisitPointers(visitor); | 67 it->second->VisitPointers(visitor); |
| 68 } | 68 } |
| 69 } | 69 } |
| 70 | 70 |
| 71 private: | 71 private: |
| 72 Map delay_set_; | 72 Map delay_set_; |
| 73 Mutex* mutex_; | 73 Mutex* mutex_; |
| 74 }; | 74 }; |
| 75 | 75 |
| 76 | 76 |
| 77 class SkippedCodeFunctions : public ZoneAllocated { |
| 78 public: |
| 79 SkippedCodeFunctions() {} |
| 80 |
| 81 void Add(RawFunction* func) { |
| 82 skipped_code_functions_.Add(func); |
| 83 } |
| 84 |
| 85 void DetachCode() { |
| 86 intptr_t unoptimized_code_count = 0; |
| 87 intptr_t current_code_count = 0; |
| 88 for (int i = 0; i < skipped_code_functions_.length(); i++) { |
| 89 RawFunction* func = skipped_code_functions_[i]; |
| 90 RawCode* code = func->ptr()->instructions_->ptr()->code_; |
| 91 if (!code->IsMarked()) { |
| 92 // If the code wasn't strongly visited through other references |
| 93 // after skipping the function's code pointer, then we disconnect the |
| 94 // code from the function. |
| 95 func->StorePointer( |
| 96 &(func->ptr()->instructions_), |
| 97 StubCode::LazyCompile_entry()->code()->ptr()->instructions_); |
| 98 uword entry_point = StubCode::LazyCompile_entry()->EntryPoint(); |
| 99 func->ptr()->entry_point_ = entry_point; |
| 100 if (FLAG_log_code_drop) { |
| 101 // NOTE: This code runs while GC is in progress and runs within |
| 102 // a NoHandleScope block. Hence it is not okay to use a regular Zone |
| 103 // or Scope handle. We use a direct stack handle so the raw pointer in |
| 104 // this handle is not traversed. The use of a handle is mainly to |
| 105 // be able to reuse the handle based code and avoid having to add |
| 106 // helper functions to the raw object interface. |
| 107 String name; |
| 108 name = func->ptr()->name_; |
| 109 ISL_Print("Detaching code: %s\n", name.ToCString()); |
| 110 current_code_count++; |
| 111 } |
| 112 } |
| 113 |
| 114 code = func->ptr()->unoptimized_code_; |
| 115 if (!code->IsMarked()) { |
| 116 // If the code wasn't strongly visited through other references |
| 117 // after skipping the function's code pointer, then we disconnect the |
| 118 // code from the function. |
| 119 func->StorePointer(&(func->ptr()->unoptimized_code_), Code::null()); |
| 120 if (FLAG_log_code_drop) { |
| 121 unoptimized_code_count++; |
| 122 } |
| 123 } |
| 124 } |
| 125 if (FLAG_log_code_drop) { |
| 126 ISL_Print(" total detached current: %" Pd "\n", current_code_count); |
| 127 ISL_Print(" total detached unoptimized: %" Pd "\n", |
| 128 unoptimized_code_count); |
| 129 } |
| 130 // Clean up. |
| 131 skipped_code_functions_.Clear(); |
| 132 } |
| 133 |
| 134 private: |
| 135 GrowableArray<RawFunction*> skipped_code_functions_; |
| 136 |
| 137 DISALLOW_COPY_AND_ASSIGN(SkippedCodeFunctions); |
| 138 }; |
| 139 |
| 140 |
| 77 class MarkingVisitor : public ObjectPointerVisitor { | 141 class MarkingVisitor : public ObjectPointerVisitor { |
| 78 public: | 142 public: |
| 79 MarkingVisitor(Isolate* isolate, | 143 MarkingVisitor(Isolate* isolate, |
| 80 Heap* heap, | 144 Heap* heap, |
| 81 PageSpace* page_space, | 145 PageSpace* page_space, |
| 82 MarkingStack* marking_stack, | 146 MarkingStack* marking_stack, |
| 83 DelaySet* delay_set, | 147 DelaySet* delay_set, |
| 84 bool visit_function_code) | 148 SkippedCodeFunctions* skipped_code_functions) |
| 85 : ObjectPointerVisitor(isolate), | 149 : ObjectPointerVisitor(isolate), |
| 86 thread_(Thread::Current()), | 150 thread_(Thread::Current()), |
| 87 heap_(heap), | 151 heap_(heap), |
| 88 vm_heap_(Dart::vm_isolate()->heap()), | 152 vm_heap_(Dart::vm_isolate()->heap()), |
| 89 class_table_(isolate->class_table()), | 153 class_table_(isolate->class_table()), |
| 90 page_space_(page_space), | 154 page_space_(page_space), |
| 91 work_list_(marking_stack), | 155 work_list_(marking_stack), |
| 92 delay_set_(delay_set), | 156 delay_set_(delay_set), |
| 93 visiting_old_object_(NULL), | 157 visiting_old_object_(NULL), |
| 94 visit_function_code_(visit_function_code), | 158 skipped_code_functions_(skipped_code_functions), |
| 95 marked_bytes_(0) { | 159 marked_bytes_(0) { |
| 96 ASSERT(heap_ != vm_heap_); | 160 ASSERT(heap_ != vm_heap_); |
| 97 ASSERT(thread_->isolate() == isolate); | 161 ASSERT(thread_->isolate() == isolate); |
| 98 } | 162 } |
| 99 | 163 |
| 100 uintptr_t marked_bytes() const { return marked_bytes_; } | 164 uintptr_t marked_bytes() const { return marked_bytes_; } |
| 101 | 165 |
| 102 // Returns true if some non-zero amount of work was performed. | 166 // Returns true if some non-zero amount of work was performed. |
| 103 bool DrainMarkingStack() { | 167 bool DrainMarkingStack() { |
| 104 RawObject* raw_obj = work_list_.Pop(); | 168 RawObject* raw_obj = work_list_.Pop(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 124 VisitingOldObject(NULL); | 188 VisitingOldObject(NULL); |
| 125 return true; | 189 return true; |
| 126 } | 190 } |
| 127 | 191 |
| 128 void VisitPointers(RawObject** first, RawObject** last) { | 192 void VisitPointers(RawObject** first, RawObject** last) { |
| 129 for (RawObject** current = first; current <= last; current++) { | 193 for (RawObject** current = first; current <= last; current++) { |
| 130 MarkObject(*current, current); | 194 MarkObject(*current, current); |
| 131 } | 195 } |
| 132 } | 196 } |
| 133 | 197 |
| 134 bool visit_function_code() const { return visit_function_code_; } | 198 bool visit_function_code() const { |
| 199 return skipped_code_functions_ == NULL; |
| 200 } |
| 135 | 201 |
| 136 virtual MallocGrowableArray<RawFunction*>* skipped_code_functions() { | 202 virtual void add_skipped_code_function(RawFunction* func) { |
| 137 return &skipped_code_functions_; | 203 ASSERT(!visit_function_code()); |
| 204 skipped_code_functions_->Add(func); |
| 138 } | 205 } |
| 139 | 206 |
| 140 // Returns the mark bit. Sets the watch bit if unmarked. (The prior value of | 207 // Returns the mark bit. Sets the watch bit if unmarked. (The prior value of |
| 141 // the watched bit is returned in 'watched_before' for validation purposes.) | 208 // the watched bit is returned in 'watched_before' for validation purposes.) |
| 142 // TODO(koda): When synchronizing header bits, this goes in a single CAS loop. | 209 // TODO(koda): When synchronizing header bits, this goes in a single CAS loop. |
| 143 static bool EnsureWatchedIfWhite(RawObject* obj, bool* watched_before) { | 210 static bool EnsureWatchedIfWhite(RawObject* obj, bool* watched_before) { |
| 144 if (obj->IsMarked()) { | 211 if (obj->IsMarked()) { |
| 145 return false; | 212 return false; |
| 146 } | 213 } |
| 147 if (!obj->IsWatched()) { | 214 if (!obj->IsWatched()) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 164 bool new_key = delay_set_->Insert(raw_weak); | 231 bool new_key = delay_set_->Insert(raw_weak); |
| 165 ASSERT(new_key == !watched_before); | 232 ASSERT(new_key == !watched_before); |
| 166 } else { | 233 } else { |
| 167 // Key is gray or black. Make the weak property black. | 234 // Key is gray or black. Make the weak property black. |
| 168 raw_weak->VisitPointers(this); | 235 raw_weak->VisitPointers(this); |
| 169 } | 236 } |
| 170 } | 237 } |
| 171 | 238 |
| 172 // Called when all marking is complete. | 239 // Called when all marking is complete. |
| 173 void Finalize() { | 240 void Finalize() { |
| 174 if (!visit_function_code_) { | 241 work_list_.Finalize(); |
| 175 DetachCode(); | 242 if (skipped_code_functions_ != NULL) { |
| 243 skipped_code_functions_->DetachCode(); |
| 176 } | 244 } |
| 177 work_list_.Finalize(); | |
| 178 } | 245 } |
| 179 | 246 |
| 180 void VisitingOldObject(RawObject* obj) { | 247 void VisitingOldObject(RawObject* obj) { |
| 181 ASSERT((obj == NULL) || obj->IsOldObject()); | 248 ASSERT((obj == NULL) || obj->IsOldObject()); |
| 182 visiting_old_object_ = obj; | 249 visiting_old_object_ = obj; |
| 183 } | 250 } |
| 184 | 251 |
| 185 private: | 252 private: |
| 186 class WorkList : public ValueObject { | 253 class WorkList : public ValueObject { |
| 187 public: | 254 public: |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 } | 343 } |
| 277 if (RawObject::IsVariableSizeClassId(raw_obj->GetClassId())) { | 344 if (RawObject::IsVariableSizeClassId(raw_obj->GetClassId())) { |
| 278 class_table_->UpdateLiveOld(raw_obj->GetClassId(), raw_obj->Size()); | 345 class_table_->UpdateLiveOld(raw_obj->GetClassId(), raw_obj->Size()); |
| 279 } else { | 346 } else { |
| 280 class_table_->UpdateLiveOld(raw_obj->GetClassId(), 0); | 347 class_table_->UpdateLiveOld(raw_obj->GetClassId(), 0); |
| 281 } | 348 } |
| 282 | 349 |
| 283 MarkAndPush(raw_obj); | 350 MarkAndPush(raw_obj); |
| 284 } | 351 } |
| 285 | 352 |
| 286 void DetachCode() { | |
| 287 intptr_t unoptimized_code_count = 0; | |
| 288 intptr_t current_code_count = 0; | |
| 289 for (int i = 0; i < skipped_code_functions_.length(); i++) { | |
| 290 RawFunction* func = skipped_code_functions_[i]; | |
| 291 RawCode* code = func->ptr()->instructions_->ptr()->code_; | |
| 292 if (!code->IsMarked()) { | |
| 293 // If the code wasn't strongly visited through other references | |
| 294 // after skipping the function's code pointer, then we disconnect the | |
| 295 // code from the function. | |
| 296 func->StorePointer( | |
| 297 &(func->ptr()->instructions_), | |
| 298 StubCode::LazyCompile_entry()->code()->ptr()->instructions_); | |
| 299 uword entry_point = StubCode::LazyCompile_entry()->EntryPoint(); | |
| 300 func->ptr()->entry_point_ = entry_point; | |
| 301 | |
| 302 if (FLAG_log_code_drop) { | |
| 303 // NOTE: This code runs while GC is in progress and runs within | |
| 304 // a NoHandleScope block. Hence it is not okay to use a regular Zone | |
| 305 // or Scope handle. We use a direct stack handle so the raw pointer in | |
| 306 // this handle is not traversed. The use of a handle is mainly to | |
| 307 // be able to reuse the handle based code and avoid having to add | |
| 308 // helper functions to the raw object interface. | |
| 309 String name; | |
| 310 name = func->ptr()->name_; | |
| 311 ISL_Print("Detaching code: %s\n", name.ToCString()); | |
| 312 current_code_count++; | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 code = func->ptr()->unoptimized_code_; | |
| 317 if (!code->IsMarked()) { | |
| 318 // If the code wasn't strongly visited through other references | |
| 319 // after skipping the function's code pointer, then we disconnect the | |
| 320 // code from the function. | |
| 321 func->StorePointer(&(func->ptr()->unoptimized_code_), Code::null()); | |
| 322 if (FLAG_log_code_drop) { | |
| 323 unoptimized_code_count++; | |
| 324 } | |
| 325 } | |
| 326 } | |
| 327 if (FLAG_log_code_drop) { | |
| 328 ISL_Print(" total detached current: %" Pd "\n", current_code_count); | |
| 329 ISL_Print(" total detached unoptimized: %" Pd "\n", | |
| 330 unoptimized_code_count); | |
| 331 } | |
| 332 // Clean up. | |
| 333 skipped_code_functions_.Clear(); | |
| 334 } | |
| 335 | |
| 336 Thread* thread_; | 353 Thread* thread_; |
| 337 Heap* heap_; | 354 Heap* heap_; |
| 338 Heap* vm_heap_; | 355 Heap* vm_heap_; |
| 339 ClassTable* class_table_; | 356 ClassTable* class_table_; |
| 340 PageSpace* page_space_; | 357 PageSpace* page_space_; |
| 341 WorkList work_list_; | 358 WorkList work_list_; |
| 342 DelaySet* delay_set_; | 359 DelaySet* delay_set_; |
| 343 RawObject* visiting_old_object_; | 360 RawObject* visiting_old_object_; |
| 344 const bool visit_function_code_; | 361 SkippedCodeFunctions* skipped_code_functions_; |
| 345 MallocGrowableArray<RawFunction*> skipped_code_functions_; | |
| 346 uintptr_t marked_bytes_; | 362 uintptr_t marked_bytes_; |
| 347 | 363 |
| 348 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor); | 364 DISALLOW_IMPLICIT_CONSTRUCTORS(MarkingVisitor); |
| 349 }; | 365 }; |
| 350 | 366 |
| 351 | 367 |
| 352 static bool IsUnreachable(const RawObject* raw_obj) { | 368 static bool IsUnreachable(const RawObject* raw_obj) { |
| 353 if (!raw_obj->IsHeapObject()) { | 369 if (!raw_obj->IsHeapObject()) { |
| 354 return false; | 370 return false; |
| 355 } | 371 } |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 ObjectIdRing* ring = isolate->object_id_ring(); | 538 ObjectIdRing* ring = isolate->object_id_ring(); |
| 523 ASSERT(ring != NULL); | 539 ASSERT(ring != NULL); |
| 524 ring->VisitPointers(&visitor); | 540 ring->VisitPointers(&visitor); |
| 525 } | 541 } |
| 526 | 542 |
| 527 | 543 |
| 528 void GCMarker::MarkObjects(Isolate* isolate, | 544 void GCMarker::MarkObjects(Isolate* isolate, |
| 529 PageSpace* page_space, | 545 PageSpace* page_space, |
| 530 bool invoke_api_callbacks, | 546 bool invoke_api_callbacks, |
| 531 bool collect_code) { | 547 bool collect_code) { |
| 532 const bool visit_function_code = !collect_code; | |
| 533 Prologue(isolate, invoke_api_callbacks); | 548 Prologue(isolate, invoke_api_callbacks); |
| 534 // The API prologue/epilogue may create/destroy zones, so we must not | 549 // The API prologue/epilogue may create/destroy zones, so we must not |
| 535 // depend on zone allocations surviving beyond the epilogue callback. | 550 // depend on zone allocations surviving beyond the epilogue callback. |
| 536 { | 551 { |
| 537 StackZone zone(Thread::Current()); | 552 StackZone stack_zone(Thread::Current()); |
| 553 Zone* zone = stack_zone.GetZone(); |
| 538 MarkingStack marking_stack; | 554 MarkingStack marking_stack; |
| 539 DelaySet delay_set; | 555 DelaySet delay_set; |
| 556 SkippedCodeFunctions* skipped_code_functions = |
| 557 collect_code ? new(zone) SkippedCodeFunctions() : NULL; |
| 540 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, | 558 MarkingVisitor mark(isolate, heap_, page_space, &marking_stack, |
| 541 &delay_set, visit_function_code); | 559 &delay_set, skipped_code_functions); |
| 542 IterateRoots(isolate, &mark, !invoke_api_callbacks); | 560 IterateRoots(isolate, &mark, !invoke_api_callbacks); |
| 543 mark.DrainMarkingStack(); | 561 mark.DrainMarkingStack(); |
| 544 IterateWeakReferences(isolate, &mark); | 562 IterateWeakReferences(isolate, &mark); |
| 545 MarkingWeakVisitor mark_weak; | 563 MarkingWeakVisitor mark_weak; |
| 546 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); | 564 IterateWeakRoots(isolate, &mark_weak, invoke_api_callbacks); |
| 547 // TODO(koda): Add hand-over callback and centralize skipped code functions. | 565 // TODO(koda): Add hand-over callback. |
| 548 marked_bytes_ = mark.marked_bytes(); | 566 marked_bytes_ = mark.marked_bytes(); |
| 549 mark.Finalize(); | 567 mark.Finalize(); |
| 550 delay_set.ClearReferences(); | 568 delay_set.ClearReferences(); |
| 551 ProcessWeakTables(page_space); | 569 ProcessWeakTables(page_space); |
| 552 ProcessObjectIdTable(isolate); | 570 ProcessObjectIdTable(isolate); |
| 553 } | 571 } |
| 554 Epilogue(isolate, invoke_api_callbacks); | 572 Epilogue(isolate, invoke_api_callbacks); |
| 555 } | 573 } |
| 556 | 574 |
| 557 } // namespace dart | 575 } // namespace dart |
| OLD | NEW |