/* * 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.utility.sanitychecker; import org.mmtk.plan.Plan; import org.mmtk.plan.Simple; import org.mmtk.plan.TraceLocal; import org.mmtk.policy.Space; import org.mmtk.utility.Constants; import org.mmtk.utility.Log; import org.mmtk.vm.VM; import org.vmmagic.pragma.*; import org.vmmagic.unboxed.*; /** * This class performs sanity checks for Simple collectors. */ @Uninterruptible public class SanityCheckerLocal implements Constants { /* Trace */ private final SanityTraceLocal sanityTrace; /**************************************************************************** * Constants */ public SanityCheckerLocal() { sanityTrace = new SanityTraceLocal(global().trace, this); } /** * Perform any sanity checking collection phases. * * @param phaseId The id to proces * @param primary Perform local single threaded actions on this thread * @return True if the phase was handled. */ @NoInline public final boolean collectionPhase(int phaseId, boolean primary) { if (phaseId == Simple.SANITY_PREPARE) { if (primary) { sanityTrace.prepare(); } return true; } if (phaseId == Simple.SANITY_ROOTS) { VM.scanning.computeStaticRoots(sanityTrace); VM.scanning.computeThreadRoots(sanityTrace); if (Plan.SCAN_BOOT_IMAGE) { VM.scanning.computeBootImageRoots(sanityTrace); } sanityTrace.flush(); return true; } if (phaseId == Simple.SANITY_BUILD_TABLE) { if (primary) { // Trace, checking for dangling pointers sanityTrace.completeTrace(); } return true; } if (phaseId == Simple.SANITY_CHECK_TABLE) { if (primary) { // Iterate over the reachable objects. Address curr = global().getSanityTable().getFirst(); while (!curr.isZero()) { ObjectReference ref = SanityDataTable.getObjectReference(curr); int normalRC = SanityDataTable.getNormalRC(curr); int rootRC = SanityDataTable.getRootRC(curr); int expectedRC = sanityExpectedRC(ref, rootRC); switch (expectedRC) { case SanityChecker.ALIVE: case SanityChecker.UNSURE: // Always ok. break; case SanityChecker.DEAD: // Never ok. Log.write("ERROR: SanityRC = "); Log.write(normalRC); Log.write(", SpaceRC = 0 "); SanityChecker.dumpObjectInformation(ref); break; default: // A mismatch in an RC space if (normalRC != expectedRC) { Log.write("WARNING: SanityRC = "); Log.write(normalRC); Log.write(", SpaceRC = "); Log.write(expectedRC); Log.write(" "); SanityChecker.dumpObjectInformation(ref); break; } } curr = global().getSanityTable().getNext(curr); } } return true; } if (phaseId == Simple.SANITY_RELEASE) { if (primary) { sanityTrace.release(); } return true; } return false; } /** * Process an object during sanity checking, validating data, * incrementing counters and enqueuing if this is the first * visit to the object. * * @param object The object to mark. * @param root True If the object is a root. */ public final void processObject(TraceLocal trace, ObjectReference object, boolean root) { SanityChecker.referenceCount++; if (root) SanityChecker.rootReferenceCount++; if (object.isNull()) { SanityChecker.nullReferenceCount++; return; } if (Plan.SCAN_BOOT_IMAGE && Space.isInSpace(Plan.VM_SPACE, object)) { return; } // Get the table entry. Address tableEntry = global().getSanityTable().getEntry(object, true); if (SanityDataTable.incRC(tableEntry, root)) { SanityChecker.liveObjectCount++; trace.processNode(object); } } /** * Return the expected reference count. For non-reference counting * collectors this becomes a true/false relationship. * * @param object The object to check. * @param sanityRootRC The number of root references to the object. * @return The expected (root excluded) reference count. */ protected int sanityExpectedRC(ObjectReference object, int sanityRootRC) { if (global().preGCSanity()) return SanityChecker.UNSURE; Space space = Space.getSpaceForObject(object); return space.isReachable(object) ? SanityChecker.ALIVE : SanityChecker.DEAD; } /** @return The global trace as a SanityChecker instance. */ protected static SanityChecker global() { return VM.activePlan.global().getSanityChecker(); } }