blob: 523b9e432cba54c720b677386428dbb73a589ad3 [file] [log] [blame]
Carl Shapiro69759ea2011-07-21 18:13:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Carl Shapiro69759ea2011-07-21 18:13:35 -07002
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "mark_sweep.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -07004
Carl Shapiro58551df2011-07-24 03:09:51 -07005#include <climits>
6#include <vector>
7
8#include "heap.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07009#include "logging.h"
10#include "macros.h"
11#include "mark_stack.h"
12#include "object.h"
Carl Shapiro58551df2011-07-24 03:09:51 -070013#include "space.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070014#include "thread.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070015
16#define CLZ(x) __builtin_clz(x)
17
18namespace art {
19
20size_t MarkSweep::reference_referent_offset_ = 0; // TODO
21size_t MarkSweep::reference_queue_offset_ = 0; // TODO
22size_t MarkSweep::reference_queueNext_offset_ = 0; // TODO
23size_t MarkSweep::reference_pendingNext_offset_ = 0; // TODO
24size_t MarkSweep::finalizer_reference_zombie_offset_ = 0; // TODO
25
Carl Shapiro58551df2011-07-24 03:09:51 -070026bool MarkSweep::Init() {
27 mark_stack_ = MarkStack::Create(Heap::GetMaximumSize());
28 if (mark_stack_ == NULL) {
29 return false;
30 }
31
32 mark_bitmap_ = Heap::GetMarkBits();
33 live_bitmap_ = Heap::GetLiveBits();
34
35 // TODO: if concurrent, clear the card table.
36
37 // TODO: check that the mark bitmap is entirely clear.
38
39 return true;
40}
41
Carl Shapiro69759ea2011-07-21 18:13:35 -070042void MarkSweep::MarkObject0(const Object* obj, bool check_finger) {
43 DCHECK(obj != NULL);
44 if (obj < condemned_) {
45 DCHECK(IsMarked(obj));
46 return;
47 }
48 bool is_marked = mark_bitmap_->Test(obj);
49 // This object was not previously marked.
50 if (!is_marked) {
51 mark_bitmap_->Set(obj);
52 if (check_finger && obj < finger_) {
53 // The object must be pushed on to the mark stack.
54 mark_stack_->Push(obj);
55 }
56 }
57}
58
59// Used to mark objects when recursing. Recursion is done by moving
60// the finger across the bitmaps in address order and marking child
61// objects. Any newly-marked objects whose addresses are lower than
62// the finger won't be visited by the bitmap scan, so those objects
63// need to be added to the mark stack.
64void MarkSweep::MarkObject(const Object* obj) {
65 if (obj != NULL) {
66 MarkObject0(obj, true);
67 }
68}
69
70// Marks all objects in the root set.
71void MarkSweep::MarkRoots() {
Elliott Hughes53b61312011-08-12 18:28:20 -070072 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070073}
74
Carl Shapiro58551df2011-07-24 03:09:51 -070075void MarkSweep::ScanBitmapCallback(Object* obj, void* finger, void* arg) {
76 MarkSweep* mark_sweep = reinterpret_cast<MarkSweep*>(arg);
77 mark_sweep->finger_ = reinterpret_cast<Object*>(finger);
78 mark_sweep->ScanObject(obj);
79}
80
81// Populates the mark stack based on the set of marked objects and
82// recursively marks until the mark stack is emptied.
83void MarkSweep::RecursiveMark() {
84 void* arg = reinterpret_cast<void*>(this);
85 const std::vector<Space*>& spaces = Heap::GetSpaces();
86 for (size_t i = 0; i < spaces.size(); ++i) {
87 if (spaces[i]->IsCondemned()) {
88 uintptr_t base = reinterpret_cast<uintptr_t>(spaces[i]->GetBase());
89 uintptr_t limit = reinterpret_cast<uintptr_t>(spaces[i]->GetLimit());
90 mark_bitmap_->ScanWalk(base, limit, &MarkSweep::ScanBitmapCallback, arg);
91 }
92 }
93 finger_ = reinterpret_cast<Object*>(~0);
94 ProcessMarkStack();
95}
96
97void MarkSweep::ReMarkRoots() {
Elliott Hughes53b61312011-08-12 18:28:20 -070098 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070099}
100
Carl Shapiro58551df2011-07-24 03:09:51 -0700101void MarkSweep::SweepSystemWeaks() {
Elliott Hughes53b61312011-08-12 18:28:20 -0700102 UNIMPLEMENTED(FATAL);
Carl Shapiro58551df2011-07-24 03:09:51 -0700103}
104
105void MarkSweep::SweepCallback(size_t num_ptrs, void **ptrs, void *arg) {
106 // TODO, lock heap if concurrent
107 Space* space = static_cast<Space*>(arg);
108 for (size_t i = 0; i < num_ptrs; ++i) {
109 Object* obj = static_cast<Object*>(ptrs[i]);
110 space->Free(obj);
111 }
112 // TODO, unlock heap if concurrent
113}
114
115void MarkSweep::Sweep() {
116 const std::vector<Space*>& spaces = Heap::GetSpaces();
117 for (size_t i = 0; i < spaces.size(); ++i) {
118 if (spaces[i]->IsCondemned()) {
119 uintptr_t base = reinterpret_cast<uintptr_t>(spaces[i]->GetBase());
120 uintptr_t limit = reinterpret_cast<uintptr_t>(spaces[i]->GetLimit());
121 void* arg = static_cast<void*>(spaces[i]);
122 HeapBitmap::SweepWalk(*live_bitmap_, *mark_bitmap_, base, limit,
123 &MarkSweep::SweepCallback, arg);
124 }
125 }
126}
127
Carl Shapiro69759ea2011-07-21 18:13:35 -0700128// Scans instance fields.
129void MarkSweep::ScanInstanceFields(const Object* obj) {
130 DCHECK(obj != NULL);
131 DCHECK(obj->GetClass() != NULL);
132 uint32_t ref_offsets = obj->GetClass()->GetReferenceOffsets();
133 if (ref_offsets != CLASS_WALK_SUPER) {
134 // Found a reference offset bitmap. Mark the specified offsets.
135 while (ref_offsets != 0) {
136 size_t right_shift = CLZ(ref_offsets);
137 size_t byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
138 const Object* ref = obj->GetFieldObject(byte_offset);
139 MarkObject(ref);
140 ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
141 }
142 } else {
143 // There is no reference offset bitmap for this class. Walk up
144 // the class inheritance hierarchy and find reference offsets the
145 // hard way.
146 for (Class *klass = obj->GetClass();
147 klass != NULL;
148 klass = klass->GetSuperClass()) {
149 for (size_t i = 0; i < klass->NumReferenceInstanceFields(); ++i) {
150 size_t field_offset = klass->GetInstanceField(i)->GetOffset();
151 const Object* ref = obj->GetFieldObject(field_offset);
152 MarkObject(ref);
153 }
154 }
155 }
156}
157
158// Scans the static fields of a class object.
159void MarkSweep::ScanStaticFields(const Class* klass) {
160 DCHECK(klass != NULL);
161 for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
Jesse Wilson35baaab2011-08-10 16:18:03 -0400162 const Field* static_field = klass->GetStaticField(i);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700163 char ch = static_field->GetType();
164 if (ch == '[' || ch == 'L') {
Carl Shapiro69759ea2011-07-21 18:13:35 -0700165 const Object* obj = static_field->GetObject();
166 MarkObject(obj);
167 }
168 }
169}
170
171void MarkSweep::ScanInterfaces(const Class* klass) {
172 DCHECK(klass != NULL);
173 for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
174 MarkObject(klass->GetInterface(i));
175 }
176}
177
178// Scans the header, static field references, and interface pointers
179// of a class object.
180void MarkSweep::ScanClass(const Object* obj) {
181 DCHECK(obj != NULL);
182 DCHECK(obj->IsClass());
183 const Class* klass = obj->AsClass();
184 MarkObject(klass->GetClass());
185 if (klass->IsArray()) {
186 MarkObject(klass->GetComponentType());
187 }
188 if (klass->IsLoaded()) {
189 MarkObject(klass->GetSuperClass());
190 }
191 MarkObject(klass->GetClassLoader());
192 ScanInstanceFields(obj);
193 ScanStaticFields(klass);
194 // TODO: scan methods
195 // TODO: scan instance fields
196 if (klass->IsLoaded()) {
197 ScanInterfaces(klass);
198 }
199}
200
201// Scans the header of all array objects. If the array object is
202// specialized to a reference type, scans the array data as well.
203void MarkSweep::ScanArray(const Object *obj) {
204 DCHECK(obj != NULL);
205 DCHECK(obj->GetClass() != NULL);
206 MarkObject(obj->GetClass());
207 if (obj->IsObjectArray()) {
Brian Carlstrom4a96b602011-07-26 16:40:23 -0700208 const ObjectArray<Object>* array = obj->AsObjectArray();
Carl Shapiro69759ea2011-07-21 18:13:35 -0700209 for (size_t i = 0; i < array->GetLength(); ++i) {
210 const Object* element = array->Get(i);
211 MarkObject(element);
212 }
213 }
214}
215
216void MarkSweep::EnqueuePendingReference(Object* ref, Object** list) {
217 DCHECK(ref != NULL);
218 DCHECK(list != NULL);
219 size_t offset = reference_pendingNext_offset_;
220 if (*list == NULL) {
221 ref->SetFieldObject(offset, ref);
222 *list = ref;
223 } else {
224 Object *head = (*list)->GetFieldObject(offset);
225 ref->SetFieldObject(offset, head);
226 (*list)->SetFieldObject(offset, ref);
227 }
228}
229
230Object* MarkSweep::DequeuePendingReference(Object** list) {
231 DCHECK(list != NULL);
232 DCHECK(*list != NULL);
233 size_t offset = reference_pendingNext_offset_;
234 Object* head = (*list)->GetFieldObject(offset);
235 Object* ref;
236 if (*list == head) {
237 ref = *list;
238 *list = NULL;
239 } else {
240 Object *next = head->GetFieldObject(offset);
241 (*list)->SetFieldObject(offset, next);
242 ref = head;
243 }
244 ref->SetFieldObject(offset, NULL);
245 return ref;
246}
247
248// Process the "referent" field in a java.lang.ref.Reference. If the
249// referent has not yet been marked, put it on the appropriate list in
250// the gcHeap for later processing.
251void MarkSweep::DelayReferenceReferent(Object* obj) {
252 DCHECK(obj != NULL);
253 DCHECK(obj->GetClass() != NULL);
Carl Shapiro58551df2011-07-24 03:09:51 -0700254 DCHECK(obj->IsReference());
Carl Shapiro69759ea2011-07-21 18:13:35 -0700255 Object* pending = obj->GetFieldObject(reference_pendingNext_offset_);
256 Object* referent = obj->GetFieldObject(reference_referent_offset_);
257 if (pending == NULL && referent != NULL && !IsMarked(referent)) {
258 Object **list = NULL;
259 if (obj->IsSoftReference()) {
260 list = &soft_reference_list_;
261 } else if (obj->IsWeakReference()) {
262 list = &weak_reference_list_;
263 } else if (obj->IsFinalizerReference()) {
264 list = &finalizer_reference_list_;
265 } else if (obj->IsPhantomReference()) {
266 list = &phantom_reference_list_;
267 }
268 DCHECK(list != NULL);
269 EnqueuePendingReference(obj, list);
270 }
271}
272
273// Scans the header and field references of a data object. If the
274// scanned object is a reference subclass, it is scheduled for later
275// processing
Carl Shapiro58551df2011-07-24 03:09:51 -0700276void MarkSweep::ScanOther(const Object* obj) {
Carl Shapiro69759ea2011-07-21 18:13:35 -0700277 DCHECK(obj != NULL);
278 DCHECK(obj->GetClass() != NULL);
279 MarkObject(obj->GetClass());
280 ScanInstanceFields(obj);
281 if (obj->IsReference()) {
282 DelayReferenceReferent(const_cast<Object*>(obj));
283 }
284}
285
286// Scans an object reference. Determines the type of the reference
287// and dispatches to a specialized scanning routine.
288void MarkSweep::ScanObject(const Object* obj) {
289 DCHECK(obj != NULL);
290 DCHECK(obj->GetClass() != NULL);
291 DCHECK(IsMarked(obj));
292 if (obj->IsClass()) {
293 ScanClass(obj);
294 } else if (obj->IsArray()) {
295 ScanArray(obj);
296 } else {
Carl Shapiro58551df2011-07-24 03:09:51 -0700297 ScanOther(obj);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700298 }
299}
300
301// Scan anything that's on the mark stack. We can't use the bitmaps
302// anymore, so use a finger that points past the end of them.
303void MarkSweep::ProcessMarkStack() {
304 while (!mark_stack_->IsEmpty()) {
305 const Object *obj = mark_stack_->Pop();
306 ScanObject(obj);
307 }
308}
309
310void MarkSweep::ScanDirtyObjects() {
311 ProcessMarkStack();
312}
313
314void MarkSweep::ClearReference(Object* ref) {
315 DCHECK(ref != NULL);
316 ref->SetFieldObject(reference_referent_offset_, NULL);
317}
318
319bool MarkSweep::IsEnqueuable(const Object* ref) {
320 DCHECK(ref != NULL);
321 const Object* queue = ref->GetFieldObject(reference_queue_offset_);
322 const Object* queue_next = ref->GetFieldObject(reference_queueNext_offset_);
323 return (queue != NULL) && (queue_next == NULL);
324}
325
326void MarkSweep::EnqueueReference(Object* ref) {
327 DCHECK(ref != NULL);
328 CHECK(ref->GetFieldObject(reference_queue_offset_) != NULL);
329 CHECK(ref->GetFieldObject(reference_queueNext_offset_) == NULL);
330 EnqueuePendingReference(ref, &cleared_reference_list_);
331}
332
333// Walks the reference list marking any references subject to the
334// reference clearing policy. References with a black referent are
335// removed from the list. References with white referents biased
336// toward saving are blackened and also removed from the list.
337void MarkSweep::PreserveSomeSoftReferences(Object** list) {
338 DCHECK(list != NULL);
339 Object* clear = NULL;
340 size_t counter = 0;
341 while (*list != NULL) {
342 Object* ref = DequeuePendingReference(list);
343 Object* referent = ref->GetFieldObject(reference_referent_offset_);
344 if (referent == NULL) {
345 // Referent was cleared by the user during marking.
346 continue;
347 }
348 bool is_marked = IsMarked(referent);
349 if (!is_marked && ((++counter) & 1)) {
350 // Referent is white and biased toward saving, mark it.
351 MarkObject(referent);
352 is_marked = true;
353 }
354 if (!is_marked) {
355 // Referent is white, queue it for clearing.
356 EnqueuePendingReference(ref, &clear);
357 }
358 }
359 *list = clear;
360 // Restart the mark with the newly black references added to the
361 // root set.
362 ProcessMarkStack();
363}
364
365// Unlink the reference list clearing references objects with white
366// referents. Cleared references registered to a reference queue are
367// scheduled for appending by the heap worker thread.
368void MarkSweep::ClearWhiteReferences(Object** list) {
369 DCHECK(list != NULL);
370 size_t offset = reference_referent_offset_;
371 while (*list != NULL) {
372 Object *ref = DequeuePendingReference(list);
373 Object *referent = ref->GetFieldObject(offset);
374 if (referent != NULL && !IsMarked(referent)) {
375 // Referent is white, clear it.
376 ClearReference(ref);
377 if (IsEnqueuable(ref)) {
378 EnqueueReference(ref);
379 }
380 }
381 }
382 DCHECK(*list == NULL);
383}
384
385// Enqueues finalizer references with white referents. White
386// referents are blackened, moved to the zombie field, and the
387// referent field is cleared.
388void MarkSweep::EnqueueFinalizerReferences(Object** list) {
389 DCHECK(list != NULL);
390 size_t referent_offset = reference_referent_offset_;
391 size_t zombie_offset = finalizer_reference_zombie_offset_;
392 bool has_enqueued = false;
393 while (*list != NULL) {
394 Object* ref = DequeuePendingReference(list);
395 Object* referent = ref->GetFieldObject(referent_offset);
396 if (referent != NULL && !IsMarked(referent)) {
397 MarkObject(referent);
398 // If the referent is non-null the reference must queuable.
399 DCHECK(IsEnqueuable(ref));
400 ref->SetFieldObject(zombie_offset, referent);
401 ClearReference(ref);
402 EnqueueReference(ref);
403 has_enqueued = true;
404 }
405 }
406 if (has_enqueued) {
407 ProcessMarkStack();
408 }
409 DCHECK(*list == NULL);
410}
411
Carl Shapiro58551df2011-07-24 03:09:51 -0700412// Process reference class instances and schedule finalizations.
Carl Shapiro69759ea2011-07-21 18:13:35 -0700413void MarkSweep::ProcessReferences(Object** soft_references, bool clear_soft,
414 Object** weak_references,
415 Object** finalizer_references,
416 Object** phantom_references) {
417 DCHECK(soft_references != NULL);
418 DCHECK(weak_references != NULL);
419 DCHECK(finalizer_references != NULL);
420 DCHECK(phantom_references != NULL);
421
422 // Unless we are in the zygote or required to clear soft references
423 // with white references, preserve some white referents.
424 if (clear_soft) {
425 PreserveSomeSoftReferences(soft_references);
426 }
427
428 // Clear all remaining soft and weak references with white
429 // referents.
430 ClearWhiteReferences(soft_references);
431 ClearWhiteReferences(weak_references);
432
433 // Preserve all white objects with finalize methods and schedule
434 // them for finalization.
435 EnqueueFinalizerReferences(finalizer_references);
436
437 // Clear all f-reachable soft and weak references with white
438 // referents.
439 ClearWhiteReferences(soft_references);
440 ClearWhiteReferences(weak_references);
441
442 // Clear all phantom references with white referents.
443 ClearWhiteReferences(phantom_references);
444
445 // At this point all reference lists should be empty.
446 DCHECK(*soft_references == NULL);
447 DCHECK(*weak_references == NULL);
448 DCHECK(*finalizer_references == NULL);
449 DCHECK(*phantom_references == NULL);
450}
451
452// Pushes a list of cleared references out to the managed heap.
453void MarkSweep::EnqueueClearedReferences(Object** cleared) {
454 DCHECK(cleared != NULL);
455 if (*cleared != NULL) {
456 Thread* self = Thread::Current();
457 DCHECK(self != NULL);
458 // TODO: Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
459 // DCHECK(meth != NULL);
460 // JValue unused;
461 // Object *reference = *cleared;
462 // TODO: dvmCallMethod(self, meth, NULL, &unused, reference);
Elliott Hughes53b61312011-08-12 18:28:20 -0700463 UNIMPLEMENTED(FATAL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700464 *cleared = NULL;
465 }
466}
467
468MarkSweep::~MarkSweep() {
Carl Shapiro58551df2011-07-24 03:09:51 -0700469 delete mark_stack_;
Carl Shapiro69759ea2011-07-21 18:13:35 -0700470 mark_bitmap_->Clear();
471}
472
473} // namespace art