/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * 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/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.mmtk.policy; import org.jikesrvm.annotations.NoSubArchCompile; 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.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 Word GC_MARK_BIT_MASK = Word.one(); private static final int META_DATA_PAGES_PER_REGION = CARD_META_PAGES_PER_REGION; /**************************************************************************** * * Instance variables */ private Word markState = Word.zero(); // 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. */ @NoSubArchCompile 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 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) { Word oldValue = VM.objectModel.readAvailableBitsWord(object); Word newValue = oldValue.and(GC_MARK_BIT_MASK.not()).or(markState); VM.objectModel.writeAvailableBitsWord(object, newValue); } /** * Used to mark boot image objects during a parallel scan of objects during GC * Returns true if marking was done. */ @Inline @NoSubArchCompile private static boolean testAndMark(ObjectReference object, Word value) { Word oldValue; do { oldValue = VM.objectModel.prepareAvailableBits(object); Word markBit = oldValue.and(GC_MARK_BIT_MASK); if (markBit.EQ(value)) return false; } while (!VM.objectModel.attemptAvailableBits(object, oldValue, oldValue.xor(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 @NoSubArchCompile 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 = GC_MARK_BIT_MASK.minus(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.readAvailableBitsWord(object).and(GC_MARK_BIT_MASK).EQ(markState)); } }