blob: d1fca7b3233c773fa417c620c1b008f38a99fcb3 [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.Plan;
import org.mmtk.plan.TransitiveClosure;
import org.mmtk.utility.heap.MonotonePageResource;
import org.mmtk.utility.heap.VMRequest;
import org.mmtk.utility.Constants;
import org.mmtk.utility.HeaderByte;
import org.mmtk.vm.VM;
import org.vmmagic.unboxed.*;
import org.vmmagic.pragma.*;
/**
* This class implements tracing for a simple immortal collection
* policy. Under this policy all that is required is for the
* "collector" to propogate marks in a liveness trace. It does not
* actually collect. This class does not hold any state, all methods
* are static.
*/
@Uninterruptible public final class ImmortalSpace extends Space
implements Constants {
/****************************************************************************
*
* Class variables
*/
static final byte GC_MARK_BIT_MASK = 1;
private static final int META_DATA_PAGES_PER_REGION = CARD_META_PAGES_PER_REGION;
/****************************************************************************
*
* Instance variables
*/
private byte markState = 0; // when GC off, the initialization value
/****************************************************************************
*
* 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 ImmortalSpace(String name, int pageBudget, VMRequest vmRequest) {
super(name, false, true, vmRequest);
if (vmRequest.isDiscontiguous()) {
pr = new MonotonePageResource(pageBudget, this, META_DATA_PAGES_PER_REGION);
} else {
pr = new MonotonePageResource(pageBudget, this, start, extent, META_DATA_PAGES_PER_REGION);
}
}
/** @return the current mark state */
@Inline
public Word getMarkState() { return Word.fromIntZeroExtend(markState); }
/****************************************************************************
*
* Object header manipulations
*/
/**
* Initialize the object header post-allocation. We need to set the mark state
* correctly and set the logged bit if necessary.
*
* @param object The newly allocated object instance whose header we are initializing
*/
public void initializeHeader(ObjectReference object) {
byte oldValue = VM.objectModel.readAvailableByte(object);
byte newValue = (byte) ((oldValue & GC_MARK_BIT_MASK) | markState);
if (HeaderByte.NEEDS_UNLOGGED_BIT) newValue |= HeaderByte.UNLOGGED_BIT;
VM.objectModel.writeAvailableByte(object, newValue);
}
/**
* Used to mark boot image objects during a parallel scan of objects during GC
* Returns true if marking was done.
*/
@Inline
private static boolean testAndMark(ObjectReference object, byte value) {
Word oldValue;
do {
oldValue = VM.objectModel.prepareAvailableBits(object);
byte markBit = (byte) (oldValue.toInt() & GC_MARK_BIT_MASK);
if (markBit == value) return false;
} while (!VM.objectModel.attemptAvailableBits(object, oldValue,
oldValue.xor(Word.fromIntZeroExtend(GC_MARK_BIT_MASK))));
return true;
}
/**
* Trace a reference to an object under an immortal collection
* policy. If the object is not already marked, enqueue the object
* for subsequent processing. The object is marked as (an atomic)
* side-effect of checking whether already marked.
*
* @param trace The trace being conducted.
* @param object The object to be traced.
*/
@Inline
public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) {
if (testAndMark(object, markState))
trace.processNode(object);
return object;
}
/**
* Prepare for a new collection increment. For the immortal
* collector we must flip the state of the mark bit between
* collections.
*/
public void prepare() {
markState = (byte) (GC_MARK_BIT_MASK - markState);
}
public void release() {}
/**
* 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
*/
@Inline
public void release(Address start) {
if (VM.VERIFY_ASSERTIONS)
VM.assertions._assert(false); // this policy only releases pages enmasse
}
@Inline
public boolean isLive(ObjectReference object) {
return true;
}
/**
* Returns if the object in question is currently thought to be reachable.
* This is done by comparing the mark bit to the current mark state. For the
* immortal collector reachable and live are different, making this method
* necessary.
*
* @param object The address of an object in immortal space to test
* @return True if <code>ref</code> may be a reachable object (e.g., having
* the current mark state). While all immortal objects are live,
* some may be unreachable.
*/
public boolean isReachable(ObjectReference object) {
if (Plan.SCAN_BOOT_IMAGE && this == Plan.vmSpace)
return true; // ignore boot image "reachabilty" if we're not tracing it
else
return (VM.objectModel.readAvailableByte(object) & GC_MARK_BIT_MASK) == markState;
}
}