Skip to content

Commit f65ff69

Browse files
committed
Components for on-the-fly reference processing.
1 parent 47a28bd commit f65ff69

20 files changed

+377
-45
lines changed

MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/Barriers.java

+6
Original file line numberDiff line numberDiff line change
@@ -627,4 +627,10 @@ public final void objectArrayStoreNoGCBarrier(Object[] dst, int index, Object va
627627
dst[index] = value;
628628
}
629629
}
630+
631+
@Inline
632+
@Override
633+
public final void addressWriteToReferenceTable(ObjectReference src, Address value, Word offset, Word location, int mode) {
634+
Magic.setAddressAtOffset(src, offset.toOffset(), value);
635+
}
630636
}

MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/FinalizableProcessor.java

+45-11
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ public final class FinalizableProcessor extends org.mmtk.vm.FinalizableProcessor
7171
/** Last object ready to be finalized */
7272
private volatile int lastReadyIndex = 0;
7373

74+
/** Last index + 1 for objects being getting ready to be finalized (for on-the-fly GC).
75+
* This is needed to prevent the finalizer thread from taking untraced, thus yet to be ready,
76+
* objects from the readyForFinalize array.
77+
*/
78+
private int lastNewReadyIndex = 0; // do not need to be volatile
79+
7480
/**
7581
* Create a new table.
7682
*/
@@ -96,7 +102,7 @@ public void add(Object object) {
96102
}
97103

98104
if (maxIndex>=freeReady()) {
99-
newReadyForFinalizeSize=table.length() + countReady();
105+
newReadyForFinalizeSize=table.length() + countReady() + countNewReady();
100106
if (newReadyForFinalizeSize<=readyForFinalize.length) {
101107
newReadyForFinalizeSize=-1;
102108
}
@@ -121,21 +127,28 @@ public void add(Object object) {
121127
}
122128

123129
if (maxIndex>=freeReady() && newReadyForFinalize!=null) {
130+
int i = nextReadyIndex;
124131
int j = 0;
125-
for(int i=nextReadyIndex; i < lastReadyIndex && i < readyForFinalize.length; i++) {
132+
while (i != lastReadyIndex) {
126133
newReadyForFinalize[j++] = readyForFinalize[i];
127-
}
128-
if (lastReadyIndex < nextReadyIndex) {
129-
for(int i=0; i < lastReadyIndex; i++) {
130-
newReadyForFinalize[j++] = readyForFinalize[i];
131-
}
134+
if (++i >= readyForFinalize.length)
135+
i = 0;
132136
}
133137
lastReadyIndex = j;
138+
while (i != lastNewReadyIndex) {
139+
newReadyForFinalize[j++] = readyForFinalize[i];
140+
if (++i >= readyForFinalize.length)
141+
i = 0;
142+
}
143+
lastNewReadyIndex = j;
134144
nextReadyIndex = 0;
135145
readyForFinalize = newReadyForFinalize;
136146
}
137147
}
138-
table.set(maxIndex++, Magic.objectAsAddress(object));
148+
if (Selected.Constraints.get().needsReferenceTableWriteBarrier())
149+
org.jikesrvm.mm.mminterface.Barriers.addressWriteToReferenceTable(table, maxIndex++, Magic.objectAsAddress(object));
150+
else
151+
table.set(maxIndex++, Magic.objectAsAddress(object));
139152
lock.release();
140153
}
141154

@@ -156,10 +169,12 @@ public void clear() {
156169
*/
157170
@Override
158171
public void forward(TraceLocal trace, boolean nursery) {
172+
if (Selected.Constraints.get().onTheFlyCollector()) lock.acquire();
159173
for (int i=0 ; i < maxIndex; i++) {
160174
ObjectReference ref = table.get(i).toObjectReference();
161175
table.set(i, trace.getForwardedFinalizable(ref).toAddress());
162176
}
177+
if (Selected.Constraints.get().onTheFlyCollector()) lock.release();
163178
}
164179

165180
/**
@@ -177,6 +192,7 @@ public void forward(TraceLocal trace, boolean nursery) {
177192
@Override
178193
@UninterruptibleNoWarn
179194
public void scan(TraceLocal trace, boolean nursery) {
195+
if (Selected.Constraints.get().onTheFlyCollector()) lock.acquire();
180196
int toIndex = nursery ? nurseryIndex : 0;
181197

182198
for (int fromIndex = toIndex; fromIndex < maxIndex; fromIndex++) {
@@ -192,12 +208,26 @@ public void scan(TraceLocal trace, boolean nursery) {
192208
ref = trace.retainForFinalize(ref);
193209

194210
/* Add to object table */
195-
Offset offset = Word.fromIntZeroExtend(lastReadyIndex).lsh(LOG_BYTES_IN_ADDRESS).toOffset();
211+
Offset offset = Word.fromIntZeroExtend(lastNewReadyIndex).lsh(LOG_BYTES_IN_ADDRESS).toOffset();
196212
Selected.Plan.get().storeObjectReference(Magic.objectAsAddress(readyForFinalize).plus(offset), ref);
197-
lastReadyIndex = (lastReadyIndex + 1) % readyForFinalize.length;
213+
lastNewReadyIndex = (lastNewReadyIndex + 1) % readyForFinalize.length;
198214
}
199215
nurseryIndex = maxIndex = toIndex;
216+
if (Selected.Constraints.get().onTheFlyCollector()) lock.release();
217+
218+
if (!Selected.Constraints.get().onTheFlyCollector()) {
219+
lastReadyIndex = lastNewReadyIndex;
220+
/* Possible schedule finalizers to run */
221+
Collection.scheduleFinalizerThread();
222+
}
223+
}
200224

225+
/*
226+
* This method is for on-the-fly GC
227+
*/
228+
@Override
229+
public void triggerFinalize() {
230+
lastReadyIndex = lastNewReadyIndex;
201231
/* Possible schedule finalizers to run */
202232
Collection.scheduleFinalizerThread();
203233
}
@@ -238,12 +268,16 @@ public int count() {
238268
public int countReady() {
239269
return ((lastReadyIndex - nextReadyIndex) + readyForFinalize.length) % readyForFinalize.length;
240270
}
271+
272+
public int countNewReady() {
273+
return ((lastNewReadyIndex - lastReadyIndex) + readyForFinalize.length) % readyForFinalize.length;
274+
}
241275

242276
/**
243277
* The number of entries ready to be finalized.
244278
*/
245279
public int freeReady() {
246-
return readyForFinalize.length - countReady();
280+
return readyForFinalize.length - countReady() - countNewReady();
247281
}
248282

249283
/***********************************************************************

MMTk/ext/vm/jikesrvm/org/jikesrvm/mm/mmtk/ReferenceProcessor.java

+82-27
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
2424
import org.jikesrvm.mm.mminterface.Selected;
2525
import org.jikesrvm.runtime.Entrypoints;
2626
import org.jikesrvm.runtime.Magic;
27+
import org.jikesrvm.runtime.Statics;
2728
import org.jikesrvm.scheduler.RVMThread;
2829

2930
import java.lang.ref.Reference;
3031
import java.lang.ref.SoftReference;
3132
import java.lang.ref.WeakReference;
3233
import java.lang.ref.PhantomReference;
3334

35+
import static org.jikesrvm.mm.mminterface.Barriers.NEEDS_OBJECT_PUTFIELD_BARRIER;
36+
import static org.jikesrvm.mm.mminterface.Barriers.NEEDS_JAVA_LANG_REFERENCE_WRITE_BARRIER;
3437

3538
/**
3639
* This class manages SoftReferences, WeakReferences, and
@@ -277,6 +280,14 @@ private void addCandidate(Reference<?> ref, ObjectReference referent) {
277280
public void forward(TraceLocal trace, boolean nursery) {
278281
if (VM.VerifyAssertions) VM._assert(unforwardedReferences != null);
279282
if (TRACE) VM.sysWriteln("Starting ReferenceGlue.forward(",semanticsStr,")");
283+
284+
if (Selected.Constraints.get().onTheFlyCollector()) {
285+
lock.acquire();
286+
/* In on-the-fly collector, unforwardedReference which is captured in scan()
287+
* may be stale.
288+
*/
289+
unforwardedReferences = references;
290+
}
280291
if (TRACE_DETAIL) {
281292
VM.sysWrite(semanticsStr," Reference table is ",
282293
Magic.objectAsAddress(references));
@@ -287,12 +298,13 @@ public void forward(TraceLocal trace, boolean nursery) {
287298
if (TRACE_DETAIL) VM.sysWrite("slot ",i,": ");
288299
ObjectReference reference = unforwardedReferences.get(i).toObjectReference();
289300
if (TRACE_DETAIL) VM.sysWriteln("forwarding ",reference);
290-
setReferent(reference, trace.getForwardedReferent(getReferent(reference)));
301+
setReferentDuringGC(reference, trace.getForwardedReferent(getReferent(reference)));
291302
ObjectReference newReference = trace.getForwardedReference(reference);
292303
unforwardedReferences.set(i, newReference.toAddress());
293304
}
294305
if (TRACE) VM.sysWriteln("Ending ReferenceGlue.forward(",semanticsStr,")");
295306
unforwardedReferences = null;
307+
if (Selected.Constraints.get().onTheFlyCollector()) lock.release();
296308
}
297309

298310
@Override
@@ -311,9 +323,11 @@ public void clear() {
311323
* TODO parallelise this code
312324
*
313325
* @param nursery Scan only the newly created references
326+
* @param if true, retain referent regardless of its reachability
314327
*/
315328
@Override
316-
public void scan(TraceLocal trace, boolean nursery) {
329+
public void scan(TraceLocal trace, boolean nursery, boolean retainUnreachable) {
330+
if (Selected.Constraints.get().onTheFlyCollector()) lock.acquire();
317331
unforwardedReferences = references;
318332

319333
if (TRACE) VM.sysWriteln("Starting ReferenceGlue.scan(",semanticsStr,")");
@@ -324,7 +338,7 @@ public void scan(TraceLocal trace, boolean nursery) {
324338
ObjectReference reference = getReference(fromIndex);
325339

326340
/* Determine liveness (and forward if necessary) the reference */
327-
ObjectReference newReference = processReference(trace,reference);
341+
ObjectReference newReference = processReference(trace, reference, retainUnreachable);
328342
if (!newReference.isNull()) {
329343
setReference(toIndex++,newReference);
330344
if (TRACE_DETAIL) {
@@ -340,8 +354,11 @@ public void scan(TraceLocal trace, boolean nursery) {
340354
VM.sysWrite(semanticsStr);
341355
VM.sysWriteln(" references: ",maxIndex," -> ",toIndex);
342356
}
343-
nurseryIndex = maxIndex = toIndex;
344-
357+
maxIndex = toIndex;
358+
if (!retainUnreachable)
359+
nurseryIndex = toIndex;
360+
if (Selected.Constraints.get().onTheFlyCollector()) lock.release();
361+
345362
/* flush out any remset entries generated during the above activities */
346363
Selected.Mutator.get().flushRememberedSets();
347364
if (TRACE) VM.sysWriteln("Ending ReferenceGlue.scan(",semanticsStr,")");
@@ -411,14 +428,35 @@ public static void addPhantomCandidate(PhantomReference<?> ref, ObjectReference
411428
* @param reference the address of the reference. This may or may not
412429
* be the address of a heap object, depending on the VM.
413430
* @param trace the thread local trace element.
431+
* @param retainUnreachable if this is true, retain referent even if it is unreachable
414432
*/
415433
@UninterruptibleNoWarn("Call out to ReferenceQueue API")
416-
public ObjectReference processReference(TraceLocal trace, ObjectReference reference) {
434+
public ObjectReference processReference(TraceLocal trace, ObjectReference reference, boolean retainUnreachable) {
417435
if (VM.VerifyAssertions) VM._assert(!reference.isNull());
418436

419437
if (TRACE_DETAIL) {
420438
VM.sysWrite("Processing reference: ",reference);
421439
}
440+
441+
if (retainUnreachable) {
442+
if (!trace.isLive(reference)) {
443+
/*
444+
* Some unreachable references may resurrect because they may be reachable from
445+
* retained referents of other references.
446+
*/
447+
return reference;
448+
}
449+
450+
ObjectReference referent = getReferent(reference);
451+
if (!referent.isNull())
452+
trace.retainReferent(referent);
453+
if (TRACE_DETAIL) {
454+
VM.sysWriteln(" ~> ", referent.toAddress(), " (retained)");
455+
}
456+
return reference;
457+
}
458+
459+
/* clear if referent is unreachable */
422460
/*
423461
* If the reference is dead, we're done with it. Let it (and
424462
* possibly its referent) be garbage-collected.
@@ -453,24 +491,6 @@ public ObjectReference processReference(TraceLocal trace, ObjectReference refere
453491

454492
if (TRACE_DETAIL) VM.sysWrite(" => ",newReference);
455493

456-
if (semantics == Semantics.SOFT) {
457-
/*
458-
* Unless we've completely run out of memory, we keep
459-
* softly reachable objects alive.
460-
*/
461-
if (!Plan.isEmergencyCollection()) {
462-
if (TRACE_DETAIL) VM.sysWrite(" (soft) ");
463-
trace.retainReferent(oldReferent);
464-
}
465-
} else if (semantics == Semantics.PHANTOM) {
466-
/*
467-
* The spec says we should forward the reference. Without unsafe uses of
468-
* reflection, the application can't tell the difference whether we do or not,
469-
* so we don't forward the reference.
470-
*/
471-
// trace.retainReferent(oldReferent);
472-
}
473-
474494
if (trace.isLive(oldReferent)) {
475495
if (VM.VerifyAssertions) {
476496
if (!DebugUtil.validRef(oldReferent)) {
@@ -491,6 +511,7 @@ public ObjectReference processReference(TraceLocal trace, ObjectReference refere
491511
if (!DebugUtil.validRef(newReferent)) {
492512
VM.sysWriteln("Error forwarding reference object.");
493513
DebugUtil.dumpRef(oldReferent);
514+
VM.sysWriteln("reference = ", reference);
494515
VM.sysFail("Invalid reference");
495516
}
496517
VM._assert(trace.isLive(newReferent));
@@ -505,7 +526,7 @@ public ObjectReference processReference(TraceLocal trace, ObjectReference refere
505526
*/
506527

507528
/* Update the referent */
508-
setReferent(newReference, newReferent);
529+
setReferentDuringGC(newReference, newReferent);
509530
return newReference;
510531
} else {
511532
/* Referent is unreachable. Clear the referent and enqueue the reference object. */
@@ -527,7 +548,7 @@ public ObjectReference processReference(TraceLocal trace, ObjectReference refere
527548
* occur.
528549
*/
529550
protected void clearReferent(ObjectReference newReference) {
530-
setReferent(newReference, ObjectReference.nullReference());
551+
setReferentDuringGC(newReference, ObjectReference.nullReference());
531552
}
532553

533554
/***********************************************************************
@@ -553,7 +574,41 @@ protected ObjectReference getReferent(ObjectReference object) {
553574
* @param referent the referent object reference.
554575
*/
555576
protected void setReferent(ObjectReference ref, ObjectReference referent) {
556-
ref.toAddress().store(referent, Entrypoints.referenceReferentField.getOffset());
577+
if (Options.noReferenceTypes.getValue()) {
578+
if (NEEDS_OBJECT_PUTFIELD_BARRIER)
579+
// treat as a objectReference write
580+
org.jikesrvm.mm.mminterface.Barriers.objectFieldWrite(ref.toObject(), referent.toObject(),
581+
Entrypoints.referenceReferentField.getOffset(), 0);
582+
else
583+
// treat as a plain Address write - it is up to the collector to ensure we process the references correctly
584+
org.jikesrvm.mm.mminterface.Barriers.addressFieldWrite(ref.toObject(), referent.toAddress(),
585+
Entrypoints.referenceReferentField.getOffset(), 0);
586+
} else {
587+
if (NEEDS_JAVA_LANG_REFERENCE_WRITE_BARRIER)
588+
// needs special treatment
589+
org.jikesrvm.mm.mminterface.Barriers.javaLangReferenceWriteBarrier(ref, referent,
590+
Entrypoints.referenceReferentField.getOffset(), 0);
591+
else
592+
// treat as a plain Address write - it is up to the collector to ensure we process the references correctly
593+
org.jikesrvm.mm.mminterface.Barriers.addressFieldWrite(ref.toObject(), referent.toAddress(),
594+
Entrypoints.referenceReferentField.getOffset(), 0);
595+
}
596+
}
597+
598+
protected void setReferentDuringGC(ObjectReference ref, ObjectReference referent) {
599+
if (NEEDS_OBJECT_PUTFIELD_BARRIER) {
600+
if (Options.noReferenceTypes.getValue()) {
601+
// treat as a objectReference write
602+
org.jikesrvm.mm.mminterface.Barriers.objectFieldWrite(ref.toObject(), referent.toObject(),
603+
Entrypoints.referenceReferentField.getOffset(), 0);
604+
} else {
605+
// write raw Address avoiding certain Sapphire assertions because ref might be in toSpace
606+
org.jikesrvm.mm.mminterface.Barriers.addressFieldWriteDuringGC(ref.toObject(), referent.toAddress(),
607+
Entrypoints.referenceReferentField.getOffset(), 0);
608+
}
609+
} else {
610+
ref.toAddress().store(referent, Entrypoints.referenceReferentField.getOffset());
611+
}
557612
}
558613

559614
/***********************************************************************

0 commit comments

Comments
 (0)