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 |