001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.mm.mmtk;
014
015import org.mmtk.plan.CollectorContext;
016import org.mmtk.plan.TraceLocal;
017import org.mmtk.utility.Log;
018
019import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
020
021import org.jikesrvm.VM;
022import org.jikesrvm.runtime.Statics;
023import org.jikesrvm.runtime.Magic;
024import org.jikesrvm.scheduler.RVMThread;
025import org.jikesrvm.mm.mminterface.MemoryManager;
026
027import org.vmmagic.unboxed.*;
028import org.vmmagic.pragma.*;
029
030/**
031 * Class that determines all JTOC slots (statics) that hold references
032 */
033public final class ScanStatics {
034  /**
035   * Size in 32bits words of a JTOC slot (ie 32bit addresses = 1,
036   * 64bit addresses =2)
037   */
038  private static final int refSlotSize = Statics.getReferenceSlotSize();
039  /**
040   * Mask used when calculating the chunkSize to ensure chunks are
041   * 64bit aligned on 64bit architectures
042   */
043  private static final int chunkSizeMask = 0xFFFFFFFF - (refSlotSize - 1);
044  /**
045   * Scan static variables (JTOC) for object references.  Executed by
046   * all GC threads in parallel, with each doing a portion of the
047   * JTOC.
048   *
049   * @param trace the trace to use for scanning
050   */
051  @Inline
052  @Uninterruptible
053  public static void scanStatics(TraceLocal trace) {
054    // The address of the statics table
055    // equivalent to Statics.getSlots()
056    final Address slots = Magic.getJTOC();
057    // This thread as a collector
058    final CollectorContext cc = RVMThread.getCurrentThread().getCollectorContext();
059    // The number of collector threads
060    final int numberOfCollectors = cc.parallelWorkerCount();
061    // The number of static references
062    final int numberOfReferences = Statics.getNumberOfReferenceSlots();
063    // The size to give each thread
064    final int chunkSize = (numberOfReferences / numberOfCollectors) & chunkSizeMask;
065    // The number of this collector thread (1...n)
066    final int threadOrdinal = cc.parallelWorkerOrdinal();
067
068    // Start and end of statics region to be processed
069    final int start = (threadOrdinal == 0) ? refSlotSize : threadOrdinal * chunkSize;
070    final int end = (threadOrdinal + 1 == numberOfCollectors) ? numberOfReferences : (threadOrdinal + 1) * chunkSize;
071
072    // Process region
073    for (int slot = start; slot < end; slot += refSlotSize) {
074      Offset slotOffset = Offset.fromIntSignExtend(slot << LOG_BYTES_IN_INT);
075      if (ScanThread.VALIDATE_REFS) checkReference(slots.plus(slotOffset), slot);
076      trace.processRootEdge(slots.plus(slotOffset), true);
077    }
078  }
079
080  /**
081   * Check that a reference encountered during scanning is valid.  If
082   * the reference is invalid, dump stack and die.
083   *
084   * @param refaddr The address of the reference in question.
085   * @param slot the index of the slot. This is necessary to trace
086   *  where the reference came from in case it turns out to be invalid.
087   */
088  @Uninterruptible
089  private static void checkReference(Address refaddr, int slot) {
090    ObjectReference ref = refaddr.loadObjectReference();
091    if (!MemoryManager.validRef(ref)) {
092      Log.writeln();
093      Log.writeln("Invalid ref reported while scanning statics");
094      Log.write("Static slot: "); Log.writeln(slot);
095      Log.writeln();
096      Log.write(refaddr); Log.write(":"); Log.flush(); MemoryManager.dumpRef(ref);
097      Log.writeln();
098      Log.writeln("Dumping stack:");
099      RVMThread.dumpStack();
100      VM.sysFail("\n\nScanStack: Detected bad GC map; exiting RVM with fatal error");
101    }
102  }
103}