blob: d2e7b66eff8153a2aa2c9b36226b3a93ce3a3976 [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
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07006#include "logging.h"
7#include "macros.h"
8#include "mark_stack.h"
9#include "object.h"
10#include "thread.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070011
12#define CLZ(x) __builtin_clz(x)
13
14namespace art {
15
16size_t MarkSweep::reference_referent_offset_ = 0; // TODO
17size_t MarkSweep::reference_queue_offset_ = 0; // TODO
18size_t MarkSweep::reference_queueNext_offset_ = 0; // TODO
19size_t MarkSweep::reference_pendingNext_offset_ = 0; // TODO
20size_t MarkSweep::finalizer_reference_zombie_offset_ = 0; // TODO
21
22void MarkSweep::MarkObject0(const Object* obj, bool check_finger) {
23 DCHECK(obj != NULL);
24 if (obj < condemned_) {
25 DCHECK(IsMarked(obj));
26 return;
27 }
28 bool is_marked = mark_bitmap_->Test(obj);
29 // This object was not previously marked.
30 if (!is_marked) {
31 mark_bitmap_->Set(obj);
32 if (check_finger && obj < finger_) {
33 // The object must be pushed on to the mark stack.
34 mark_stack_->Push(obj);
35 }
36 }
37}
38
39// Used to mark objects when recursing. Recursion is done by moving
40// the finger across the bitmaps in address order and marking child
41// objects. Any newly-marked objects whose addresses are lower than
42// the finger won't be visited by the bitmap scan, so those objects
43// need to be added to the mark stack.
44void MarkSweep::MarkObject(const Object* obj) {
45 if (obj != NULL) {
46 MarkObject0(obj, true);
47 }
48}
49
50// Marks all objects in the root set.
51void MarkSweep::MarkRoots() {
52 LOG(FATAL) << "Unimplemented";
53}
54
55void MarkSweep::ReMarkRoots()
56{
57 LOG(FATAL) << "Unimplemented";
58}
59
60// Scans instance fields.
61void MarkSweep::ScanInstanceFields(const Object* obj) {
62 DCHECK(obj != NULL);
63 DCHECK(obj->GetClass() != NULL);
64 uint32_t ref_offsets = obj->GetClass()->GetReferenceOffsets();
65 if (ref_offsets != CLASS_WALK_SUPER) {
66 // Found a reference offset bitmap. Mark the specified offsets.
67 while (ref_offsets != 0) {
68 size_t right_shift = CLZ(ref_offsets);
69 size_t byte_offset = CLASS_OFFSET_FROM_CLZ(right_shift);
70 const Object* ref = obj->GetFieldObject(byte_offset);
71 MarkObject(ref);
72 ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
73 }
74 } else {
75 // There is no reference offset bitmap for this class. Walk up
76 // the class inheritance hierarchy and find reference offsets the
77 // hard way.
78 for (Class *klass = obj->GetClass();
79 klass != NULL;
80 klass = klass->GetSuperClass()) {
81 for (size_t i = 0; i < klass->NumReferenceInstanceFields(); ++i) {
82 size_t field_offset = klass->GetInstanceField(i)->GetOffset();
83 const Object* ref = obj->GetFieldObject(field_offset);
84 MarkObject(ref);
85 }
86 }
87 }
88}
89
90// Scans the static fields of a class object.
91void MarkSweep::ScanStaticFields(const Class* klass) {
92 DCHECK(klass != NULL);
93 for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
94 // char ch = clazz->sfields[i].signature[0];
95 const StaticField* static_field = klass->GetStaticField(i);
96 char ch = static_field->GetType();
97 if (ch == '[' || ch == 'L') {
98 // Object *obj = clazz->sfields[i].value.l;
99 // markObject(obj, ctx);
100 const Object* obj = static_field->GetObject();
101 MarkObject(obj);
102 }
103 }
104}
105
106void MarkSweep::ScanInterfaces(const Class* klass) {
107 DCHECK(klass != NULL);
108 for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
109 MarkObject(klass->GetInterface(i));
110 }
111}
112
113// Scans the header, static field references, and interface pointers
114// of a class object.
115void MarkSweep::ScanClass(const Object* obj) {
116 DCHECK(obj != NULL);
117 DCHECK(obj->IsClass());
118 const Class* klass = obj->AsClass();
119 MarkObject(klass->GetClass());
120 if (klass->IsArray()) {
121 MarkObject(klass->GetComponentType());
122 }
123 if (klass->IsLoaded()) {
124 MarkObject(klass->GetSuperClass());
125 }
126 MarkObject(klass->GetClassLoader());
127 ScanInstanceFields(obj);
128 ScanStaticFields(klass);
129 // TODO: scan methods
130 // TODO: scan instance fields
131 if (klass->IsLoaded()) {
132 ScanInterfaces(klass);
133 }
134}
135
136// Scans the header of all array objects. If the array object is
137// specialized to a reference type, scans the array data as well.
138void MarkSweep::ScanArray(const Object *obj) {
139 DCHECK(obj != NULL);
140 DCHECK(obj->GetClass() != NULL);
141 MarkObject(obj->GetClass());
142 if (obj->IsObjectArray()) {
143 const ObjectArray* array = obj->AsObjectArray();
144 for (size_t i = 0; i < array->GetLength(); ++i) {
145 const Object* element = array->Get(i);
146 MarkObject(element);
147 }
148 }
149}
150
151void MarkSweep::EnqueuePendingReference(Object* ref, Object** list) {
152 DCHECK(ref != NULL);
153 DCHECK(list != NULL);
154 size_t offset = reference_pendingNext_offset_;
155 if (*list == NULL) {
156 ref->SetFieldObject(offset, ref);
157 *list = ref;
158 } else {
159 Object *head = (*list)->GetFieldObject(offset);
160 ref->SetFieldObject(offset, head);
161 (*list)->SetFieldObject(offset, ref);
162 }
163}
164
165Object* MarkSweep::DequeuePendingReference(Object** list) {
166 DCHECK(list != NULL);
167 DCHECK(*list != NULL);
168 size_t offset = reference_pendingNext_offset_;
169 Object* head = (*list)->GetFieldObject(offset);
170 Object* ref;
171 if (*list == head) {
172 ref = *list;
173 *list = NULL;
174 } else {
175 Object *next = head->GetFieldObject(offset);
176 (*list)->SetFieldObject(offset, next);
177 ref = head;
178 }
179 ref->SetFieldObject(offset, NULL);
180 return ref;
181}
182
183// Process the "referent" field in a java.lang.ref.Reference. If the
184// referent has not yet been marked, put it on the appropriate list in
185// the gcHeap for later processing.
186void MarkSweep::DelayReferenceReferent(Object* obj) {
187 DCHECK(obj != NULL);
188 DCHECK(obj->GetClass() != NULL);
189 //DCHECK(IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISREFERENCE));
190 Object* pending = obj->GetFieldObject(reference_pendingNext_offset_);
191 Object* referent = obj->GetFieldObject(reference_referent_offset_);
192 if (pending == NULL && referent != NULL && !IsMarked(referent)) {
193 Object **list = NULL;
194 if (obj->IsSoftReference()) {
195 list = &soft_reference_list_;
196 } else if (obj->IsWeakReference()) {
197 list = &weak_reference_list_;
198 } else if (obj->IsFinalizerReference()) {
199 list = &finalizer_reference_list_;
200 } else if (obj->IsPhantomReference()) {
201 list = &phantom_reference_list_;
202 }
203 DCHECK(list != NULL);
204 EnqueuePendingReference(obj, list);
205 }
206}
207
208// Scans the header and field references of a data object. If the
209// scanned object is a reference subclass, it is scheduled for later
210// processing
211void MarkSweep::ScanDataObject(const Object *obj) {
212 DCHECK(obj != NULL);
213 DCHECK(obj->GetClass() != NULL);
214 MarkObject(obj->GetClass());
215 ScanInstanceFields(obj);
216 if (obj->IsReference()) {
217 DelayReferenceReferent(const_cast<Object*>(obj));
218 }
219}
220
221// Scans an object reference. Determines the type of the reference
222// and dispatches to a specialized scanning routine.
223void MarkSweep::ScanObject(const Object* obj) {
224 DCHECK(obj != NULL);
225 DCHECK(obj->GetClass() != NULL);
226 DCHECK(IsMarked(obj));
227 if (obj->IsClass()) {
228 ScanClass(obj);
229 } else if (obj->IsArray()) {
230 ScanArray(obj);
231 } else {
232 ScanDataObject(obj);
233 }
234}
235
236// Scan anything that's on the mark stack. We can't use the bitmaps
237// anymore, so use a finger that points past the end of them.
238void MarkSweep::ProcessMarkStack() {
239 while (!mark_stack_->IsEmpty()) {
240 const Object *obj = mark_stack_->Pop();
241 ScanObject(obj);
242 }
243}
244
245void MarkSweep::ScanDirtyObjects() {
246 ProcessMarkStack();
247}
248
249void MarkSweep::ClearReference(Object* ref) {
250 DCHECK(ref != NULL);
251 ref->SetFieldObject(reference_referent_offset_, NULL);
252}
253
254bool MarkSweep::IsEnqueuable(const Object* ref) {
255 DCHECK(ref != NULL);
256 const Object* queue = ref->GetFieldObject(reference_queue_offset_);
257 const Object* queue_next = ref->GetFieldObject(reference_queueNext_offset_);
258 return (queue != NULL) && (queue_next == NULL);
259}
260
261void MarkSweep::EnqueueReference(Object* ref) {
262 DCHECK(ref != NULL);
263 CHECK(ref->GetFieldObject(reference_queue_offset_) != NULL);
264 CHECK(ref->GetFieldObject(reference_queueNext_offset_) == NULL);
265 EnqueuePendingReference(ref, &cleared_reference_list_);
266}
267
268// Walks the reference list marking any references subject to the
269// reference clearing policy. References with a black referent are
270// removed from the list. References with white referents biased
271// toward saving are blackened and also removed from the list.
272void MarkSweep::PreserveSomeSoftReferences(Object** list) {
273 DCHECK(list != NULL);
274 Object* clear = NULL;
275 size_t counter = 0;
276 while (*list != NULL) {
277 Object* ref = DequeuePendingReference(list);
278 Object* referent = ref->GetFieldObject(reference_referent_offset_);
279 if (referent == NULL) {
280 // Referent was cleared by the user during marking.
281 continue;
282 }
283 bool is_marked = IsMarked(referent);
284 if (!is_marked && ((++counter) & 1)) {
285 // Referent is white and biased toward saving, mark it.
286 MarkObject(referent);
287 is_marked = true;
288 }
289 if (!is_marked) {
290 // Referent is white, queue it for clearing.
291 EnqueuePendingReference(ref, &clear);
292 }
293 }
294 *list = clear;
295 // Restart the mark with the newly black references added to the
296 // root set.
297 ProcessMarkStack();
298}
299
300// Unlink the reference list clearing references objects with white
301// referents. Cleared references registered to a reference queue are
302// scheduled for appending by the heap worker thread.
303void MarkSweep::ClearWhiteReferences(Object** list) {
304 DCHECK(list != NULL);
305 size_t offset = reference_referent_offset_;
306 while (*list != NULL) {
307 Object *ref = DequeuePendingReference(list);
308 Object *referent = ref->GetFieldObject(offset);
309 if (referent != NULL && !IsMarked(referent)) {
310 // Referent is white, clear it.
311 ClearReference(ref);
312 if (IsEnqueuable(ref)) {
313 EnqueueReference(ref);
314 }
315 }
316 }
317 DCHECK(*list == NULL);
318}
319
320// Enqueues finalizer references with white referents. White
321// referents are blackened, moved to the zombie field, and the
322// referent field is cleared.
323void MarkSweep::EnqueueFinalizerReferences(Object** list) {
324 DCHECK(list != NULL);
325 size_t referent_offset = reference_referent_offset_;
326 size_t zombie_offset = finalizer_reference_zombie_offset_;
327 bool has_enqueued = false;
328 while (*list != NULL) {
329 Object* ref = DequeuePendingReference(list);
330 Object* referent = ref->GetFieldObject(referent_offset);
331 if (referent != NULL && !IsMarked(referent)) {
332 MarkObject(referent);
333 // If the referent is non-null the reference must queuable.
334 DCHECK(IsEnqueuable(ref));
335 ref->SetFieldObject(zombie_offset, referent);
336 ClearReference(ref);
337 EnqueueReference(ref);
338 has_enqueued = true;
339 }
340 }
341 if (has_enqueued) {
342 ProcessMarkStack();
343 }
344 DCHECK(*list == NULL);
345}
346
347/*
348 * Process reference class instances and schedule finalizations.
349 */
350void MarkSweep::ProcessReferences(Object** soft_references, bool clear_soft,
351 Object** weak_references,
352 Object** finalizer_references,
353 Object** phantom_references) {
354 DCHECK(soft_references != NULL);
355 DCHECK(weak_references != NULL);
356 DCHECK(finalizer_references != NULL);
357 DCHECK(phantom_references != NULL);
358
359 // Unless we are in the zygote or required to clear soft references
360 // with white references, preserve some white referents.
361 if (clear_soft) {
362 PreserveSomeSoftReferences(soft_references);
363 }
364
365 // Clear all remaining soft and weak references with white
366 // referents.
367 ClearWhiteReferences(soft_references);
368 ClearWhiteReferences(weak_references);
369
370 // Preserve all white objects with finalize methods and schedule
371 // them for finalization.
372 EnqueueFinalizerReferences(finalizer_references);
373
374 // Clear all f-reachable soft and weak references with white
375 // referents.
376 ClearWhiteReferences(soft_references);
377 ClearWhiteReferences(weak_references);
378
379 // Clear all phantom references with white referents.
380 ClearWhiteReferences(phantom_references);
381
382 // At this point all reference lists should be empty.
383 DCHECK(*soft_references == NULL);
384 DCHECK(*weak_references == NULL);
385 DCHECK(*finalizer_references == NULL);
386 DCHECK(*phantom_references == NULL);
387}
388
389// Pushes a list of cleared references out to the managed heap.
390void MarkSweep::EnqueueClearedReferences(Object** cleared) {
391 DCHECK(cleared != NULL);
392 if (*cleared != NULL) {
393 Thread* self = Thread::Current();
394 DCHECK(self != NULL);
395 // TODO: Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
396 // DCHECK(meth != NULL);
397 // JValue unused;
398 // Object *reference = *cleared;
399 // TODO: dvmCallMethod(self, meth, NULL, &unused, reference);
400 LOG(FATAL) << "Unimplemented";
401 *cleared = NULL;
402 }
403}
404
405MarkSweep::~MarkSweep() {
406 mark_bitmap_->Clear();
407}
408
409} // namespace art