blob: 65ec5d8be9fcfb648585a61a5d36df8481f719e2 [file] [log] [blame]
/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.policy;
import org.mmtk.plan.TraceLocal;
import org.mmtk.plan.TransitiveClosure;
import org.mmtk.utility.alloc.BumpPointer;
import org.mmtk.utility.heap.*;
import org.mmtk.utility.Constants;
import org.mmtk.utility.Log;
import org.mmtk.vm.Lock;
import org.mmtk.vm.VM;
import org.vmmagic.unboxed.*;
import org.vmmagic.pragma.*;
/**
* This class implements functionality for a simple sliding mark-compact
* space.
*/
@Uninterruptible public final class MarkCompactSpace extends Space
implements Constants {
/****************************************************************************
*
* Class variables
*/
public static final int LOCAL_GC_BITS_REQUIRED = 1;
public static final int GLOBAL_GC_BITS_REQUIRED = 0;
public static final int GC_HEADER_WORDS_REQUIRED = 1;
private static final Word GC_MARK_BIT_MASK = Word.one();
private static final Offset FORWARDING_POINTER_OFFSET = VM.objectModel.GC_HEADER_OFFSET();
private static final Lock lock = VM.newLock("mcSpace");
/** The list of occupied regions */
private Address regionList = Address.zero();
// TODO - maintain a separate list of partially allocated regions
// for threads to allocate into immediately after a collection.
/****************************************************************************
*
* Instance variables
*/
/****************************************************************************
*
* Initialization
*/
/**
* The caller specifies the region of virtual memory to be used for
* this space. If this region conflicts with an existing space,
* then the constructor will fail.
*
* @param name The name of this space (used when printing error messages etc)
* @param pageBudget The number of pages this space may consume
* before consulting the plan
* @param vmRequest An object describing the virtual memory requested.
*/
public MarkCompactSpace(String name, int pageBudget, VMRequest vmRequest) {
super(name, true, false, vmRequest);
if (vmRequest.isDiscontiguous()) {
pr = new FreeListPageResource(pageBudget, this, 0);
} else {
pr = new FreeListPageResource(pageBudget, this, start, extent, 0);
}
}
/**
* Prepare for a collection
*/
public void prepare() {
}
/**
* Release after a collection
*/
public void release() {
// nothing to do
}
/**
* Release an allocated page or pages. In this case we do nothing
* because we only release pages enmasse.
*
* @param start The address of the start of the page or pages
*/
@Override
@Inline
public void release(Address start) {
((FreeListPageResource)pr).releasePages(start);
}
/**
* Trace an object under a copying collection policy.
* If the object is already copied, the copy is returned.
* Otherwise, a copy is created and returned.
* In either case, the object will be marked on return.
*
* @param trace The trace being conducted.
* @param object The object to be forwarded.
* @return The forwarded object.
*/
@Override
@Inline
public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) {
if (VM.VERIFY_ASSERTIONS)
VM.assertions._assert(false);
return null;
}
/**
* Trace an object under a copying collection policy.
* If the object is already copied, the copy is returned.
* Otherwise, a copy is created and returned.
* In either case, the object will be marked on return.
*
* @param trace The trace being conducted.
* @param object The object to be forwarded.
* @return The forwarded object.
*/
@Inline
public ObjectReference traceMarkObject(TraceLocal trace, ObjectReference object) {
if (MarkCompactCollector.VERY_VERBOSE) {
Log.write("marking "); Log.write(object);
}
if (testAndMark(object)) {
trace.processNode(object);
} else if (!getForwardingPointer(object).isNull()) {
if (MarkCompactCollector.VERY_VERBOSE) {
Log.write(" -> "); Log.writeln(getForwardingPointer(object));
}
return getForwardingPointer(object);
}
if (MarkCompactCollector.VERY_VERBOSE) {
Log.writeln();
}
return object;
}
/**
* Trace an object under a copying collection policy.
* If the object is already copied, the copy is returned.
* Otherwise, a copy is created and returned.
* In either case, the object will be marked on return.
*
* @param trace The trace being conducted.
* @param object The object to be forwarded.
* @return The forwarded object.
*/
@Inline
public ObjectReference traceForwardObject(TraceLocal trace, ObjectReference object) {
if (testAndClearMark(object)) {
trace.processNode(object);
}
ObjectReference newObject = getForwardingPointer(object);
if (MarkCompactCollector.VERY_VERBOSE) {
Log.write("forwarding "); Log.write(object);
Log.write(" -> "); Log.writeln(newObject);
}
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!newObject.isNull());
return getForwardingPointer(object);
}
/**
* Is this object live?
*
* @param object The object
* @return True if the object is live
*/
@Override
public boolean isLive(ObjectReference object) {
return isMarked(object);
}
/**
* Has the object in this space been reached during the current collection.
* This is used for GC Tracing.
*
* @param object The object reference.
* @return True if the object is reachable.
*/
@Override
public boolean isReachable(ObjectReference object) {
return isMarked(object);
}
/****************************************************************************
*
* Header manipulation
*/
/**
* Perform any required post-allocation initialization
*
* <i>Nothing to be done in this case</i>
*
* @param object the object ref to the storage to be initialized
*/
@Inline
public void postAlloc(ObjectReference object) {
}
/**
* Non-atomic read of forwarding pointer
*
* @param object The object whose forwarding pointer is to be read
* @return The forwarding pointer stored in <code>object</code>'s
* header.
*/
@Inline
public static ObjectReference getForwardingPointer(ObjectReference object) {
return object.toAddress().loadObjectReference(FORWARDING_POINTER_OFFSET);
}
/**
* Initialise the header of the object.
*
* @param object The object to initialise
*/
@Inline
public void initializeHeader(ObjectReference object) {
// nothing to do
}
/**
* Used to mark boot image objects during a parallel scan of objects
* during GC Returns true if marking was done.
*
* @param object The object to be marked
*/
@Inline
public static boolean testAndMark(ObjectReference object) {
Word oldValue;
do {
oldValue = VM.objectModel.prepareAvailableBits(object);
Word markBit = oldValue.and(GC_MARK_BIT_MASK);
if (!markBit.isZero()) return false;
} while (!VM.objectModel.attemptAvailableBits(object, oldValue,
oldValue.or(GC_MARK_BIT_MASK)));
return true;
}
/**
* Used to mark boot image objects during a parallel scan of objects
* during GC Returns true if marking was done.
*
* @param object The object to be marked
*/
@Inline
public static boolean isMarked(ObjectReference object) {
Word oldValue = VM.objectModel.readAvailableBitsWord(object);
Word markBit = oldValue.and(GC_MARK_BIT_MASK);
return (!markBit.isZero());
}
/**
* Used to mark boot image objects during a parallel scan of objects
* during GC Returns true if marking was done.
*
* @param object The object to be marked
*/
@Inline
private static boolean testAndClearMark(ObjectReference object) {
Word oldValue;
do {
oldValue = VM.objectModel.prepareAvailableBits(object);
Word markBit = oldValue.and(GC_MARK_BIT_MASK);
if (markBit.isZero()) return false;
} while (!VM.objectModel.attemptAvailableBits(object, oldValue,
oldValue.and(GC_MARK_BIT_MASK.not())));
return true;
}
/**
* Used to mark boot image objects during a parallel scan of objects
* during GC Returns true if marking was done.
*
* @param object The object to be marked
*/
@Inline
public static boolean toBeCompacted(ObjectReference object) {
Word oldValue = VM.objectModel.readAvailableBitsWord(object);
Word markBit = oldValue.and(GC_MARK_BIT_MASK);
return !markBit.isZero() && getForwardingPointer(object).isNull();
}
/**
* Used to mark boot image objects during a parallel scan of objects
* during GC Returns true if marking was done.
*
* @param object The object to be marked
*/
@Inline
public static void clearMark(ObjectReference object) {
Word oldValue = VM.objectModel.readAvailableBitsWord(object);
VM.objectModel.writeAvailableBitsWord(object, oldValue.and(GC_MARK_BIT_MASK.not()));
}
/**
* Non-atomic write of forwarding pointer word (assumption, thread
* doing the set has done attempt to forward and owns the right to
* copy the object)
*
* @param object The object whose forwarding pointer is to be set
* @param ptr The forwarding pointer to be stored in the object's
* forwarding word
*/
@Inline
public static void setForwardingPointer(ObjectReference object,
ObjectReference ptr) {
object.toAddress().store(ptr.toAddress(), FORWARDING_POINTER_OFFSET);
}
/**
* Non-atomic clear of forwarding pointer word (assumption, thread
* doing the set has done attempt to forward and owns the right to
* copy the object)
*
* @param object The object whose forwarding pointer is to be set
*/
@Inline
public static void clearForwardingPointer(ObjectReference object) {
object.toAddress().store(Address.zero(), FORWARDING_POINTER_OFFSET);
}
/**
* @return A region of this space that has net yet been compacted during
* the current collection
*/
public Address getNextRegion() {
lock.acquire();
if (regionList.isZero()) {
lock.release();
return Address.zero();
}
Address result = regionList;
regionList = BumpPointer.getNextRegion(regionList);
BumpPointer.clearNextRegion(result);
lock.release();
return result;
}
/**
* Append a region or list of regions to the global list
* @param region
*/
public void append(Address region) {
lock.acquire();
if (MarkCompactCollector.VERBOSE) {
Log.write("Appending region "); Log.write(region);
Log.writeln(" to global list");
}
if (regionList.isZero()) {
regionList = region;
} else {
appendRegion(regionList,region);
}
lock.release();
}
public static void appendRegion(Address listHead, Address region) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!listHead.isZero());
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!region.isZero());
Address cursor = listHead;
while (!BumpPointer.getNextRegion(cursor).isZero()) {
cursor = BumpPointer.getNextRegion(cursor);
}
BumpPointer.setNextRegion(cursor,region);
}
}