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