/* * 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.jikesrvm.mm.mmtk; import org.mmtk.plan.TraceLocal; import org.mmtk.utility.Constants; import org.mmtk.utility.Log; import org.jikesrvm.VM; import org.jikesrvm.runtime.Statics; import org.jikesrvm.runtime.Magic; import org.jikesrvm.scheduler.RVMThread; import org.jikesrvm.mm.mminterface.CollectorThread; import org.jikesrvm.mm.mminterface.MemoryManager; import org.vmmagic.unboxed.*; import org.vmmagic.pragma.*; /** * Class that determines all JTOC slots (statics) that hold references */ public final class ScanStatics implements Constants { /** * Size in 32bits words of a JTOC slot (ie 32bit addresses = 1, * 64bit addresses =2) */ private static final int refSlotSize = Statics.getReferenceSlotSize(); /** * Mask used when calculating the chunkSize to ensure chunks are * 64bit aligned on 64bit architectures */ private static final int chunkSizeMask = 0xFFFFFFFF - (refSlotSize - 1); /** * Scan static variables (JTOC) for object references. Executed by * all GC threads in parallel, with each doing a portion of the * JTOC. */ @Inline @Uninterruptible public static void scanStatics(TraceLocal trace) { // The address of the statics table // equivalent to Statics.getSlots() final Address slots = Magic.getJTOC(); // The number of collector threads final int numberOfCollectors = CollectorThread.numCollectors(); // This thread as a collector final CollectorThread ct = Magic.threadAsCollectorThread(RVMThread.getCurrentThread()); // The number of static references final int numberOfReferences = Statics.getNumberOfReferenceSlots(); // The size to give each thread final int chunkSize = (numberOfReferences / numberOfCollectors) & chunkSizeMask; // The number of this collector thread (1...n) final int threadOrdinal = ct.getGCOrdinal(); // Start and end of statics region to be processed final int start = (threadOrdinal == 1) ? refSlotSize : (threadOrdinal - 1) * chunkSize; final int end = (threadOrdinal == numberOfCollectors) ? numberOfReferences : threadOrdinal * chunkSize; // Process region for (int slot=start; slot < end; slot+=refSlotSize) { Offset slotOffset = Offset.fromIntSignExtend(slot << LOG_BYTES_IN_INT); if (ScanThread.VALIDATE_REFS) checkReference(slots.plus(slotOffset), slot); trace.processRootEdge(slots.plus(slotOffset), true); } } /** * Check that a reference encountered during scanning is valid. If * the reference is invalid, dump stack and die. * * @param refaddr The address of the reference in question. */ @Uninterruptible private static void checkReference(Address refaddr, int slot) { ObjectReference ref = refaddr.loadObjectReference(); if (!MemoryManager.validRef(ref)) { Log.writeln(); Log.writeln("Invalid ref reported while scanning statics"); Log.write("Static slot: "); Log.writeln(slot); Log.writeln(); Log.write(refaddr); Log.write(":"); Log.flush(); MemoryManager.dumpRef(ref); Log.writeln(); Log.writeln("Dumping stack:"); RVMThread.dumpStack(); VM.sysFail("\n\nScanStack: Detected bad GC map; exiting RVM with fatal error"); } } }