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     */
013    package org.jikesrvm.mm.mmtk;
014    
015    import org.mmtk.plan.CollectorContext;
016    import org.mmtk.plan.TraceLocal;
017    import org.mmtk.utility.Constants;
018    import org.mmtk.utility.Log;
019    import org.jikesrvm.VM;
020    import org.jikesrvm.runtime.Statics;
021    import org.jikesrvm.runtime.Magic;
022    import org.jikesrvm.scheduler.RVMThread;
023    import org.jikesrvm.mm.mminterface.MemoryManager;
024    
025    import org.vmmagic.unboxed.*;
026    import org.vmmagic.pragma.*;
027    
028    /**
029     * Class that determines all JTOC slots (statics) that hold references
030     */
031    public final class ScanStatics implements Constants {
032      /**
033       * Size in 32bits words of a JTOC slot (ie 32bit addresses = 1,
034       * 64bit addresses =2)
035       */
036      private static final int refSlotSize = Statics.getReferenceSlotSize();
037      /**
038       * Mask used when calculating the chunkSize to ensure chunks are
039       * 64bit aligned on 64bit architectures
040       */
041      private static final int chunkSizeMask = 0xFFFFFFFF - (refSlotSize - 1);
042      /**
043       * Scan static variables (JTOC) for object references.  Executed by
044       * all GC threads in parallel, with each doing a portion of the
045       * JTOC.
046       */
047      @Inline
048      @Uninterruptible
049      public static void scanStatics(TraceLocal trace) {
050        // The address of the statics table
051        // equivalent to Statics.getSlots()
052        final Address slots = Magic.getJTOC();
053        // This thread as a collector
054        final CollectorContext cc = RVMThread.getCurrentThread().getCollectorContext();
055        // The number of collector threads
056        final int numberOfCollectors = cc.parallelWorkerCount();
057        // The number of static references
058        final int numberOfReferences = Statics.getNumberOfReferenceSlots();
059        // The size to give each thread
060        final int chunkSize = (numberOfReferences / numberOfCollectors) & chunkSizeMask;
061        // The number of this collector thread (1...n)
062        final int threadOrdinal = cc.parallelWorkerOrdinal();
063    
064        // Start and end of statics region to be processed
065        final int start = (threadOrdinal == 0) ? refSlotSize : threadOrdinal * chunkSize;
066        final int end = (threadOrdinal+1 == numberOfCollectors) ? numberOfReferences : (threadOrdinal+1) * chunkSize;
067    
068        // Process region
069        for (int slot=start; slot < end; slot+=refSlotSize) {
070          Offset slotOffset = Offset.fromIntSignExtend(slot << LOG_BYTES_IN_INT);
071          if (ScanThread.VALIDATE_REFS) checkReference(slots.plus(slotOffset), slot);
072          trace.processRootEdge(slots.plus(slotOffset), true);
073        }
074      }
075    
076      /**
077       * Check that a reference encountered during scanning is valid.  If
078       * the reference is invalid, dump stack and die.
079       *
080       * @param refaddr The address of the reference in question.
081       */
082      @Uninterruptible
083      private static void checkReference(Address refaddr, int slot) {
084        ObjectReference ref = refaddr.loadObjectReference();
085        if (!MemoryManager.validRef(ref)) {
086          Log.writeln();
087          Log.writeln("Invalid ref reported while scanning statics");
088          Log.write("Static slot: "); Log.writeln(slot);
089          Log.writeln();
090          Log.write(refaddr); Log.write(":"); Log.flush(); MemoryManager.dumpRef(ref);
091          Log.writeln();
092          Log.writeln("Dumping stack:");
093          RVMThread.dumpStack();
094          VM.sysFail("\n\nScanStack: Detected bad GC map; exiting RVM with fatal error");
095        }
096      }
097    }