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.plan.TransitiveClosure;
018    import org.mmtk.utility.Constants;
019    
020    import org.jikesrvm.compilers.common.CompiledMethods;
021    import org.jikesrvm.jni.JNIEnvironment;
022    import org.jikesrvm.jni.JNIGlobalRefTable;
023    import org.jikesrvm.mm.mminterface.AlignmentEncoding;
024    import org.jikesrvm.mm.mminterface.HandInlinedScanning;
025    import org.jikesrvm.mm.mminterface.Selected;
026    import org.jikesrvm.mm.mminterface.MemoryManagerConstants;
027    import org.jikesrvm.mm.mminterface.SpecializedScanMethod;
028    import org.jikesrvm.runtime.Magic;
029    import org.jikesrvm.scheduler.RVMThread;
030    
031    import org.vmmagic.unboxed.*;
032    import org.vmmagic.pragma.*;
033    
034    @Uninterruptible
035    public final class Scanning extends org.mmtk.vm.Scanning implements Constants {
036      /****************************************************************************
037       *
038       * Class variables
039       */
040    
041      /** Counter to track index into thread table for root tracing.  */
042      private static final SynchronizedCounter threadCounter = new SynchronizedCounter();
043    
044      /**
045       * Scanning of a object, processing each pointer field encountered.
046       *
047       * @param trace The closure being used.
048       * @param object The object to be scanned.
049       */
050      @Override
051      @Inline
052      public void scanObject(TransitiveClosure trace, ObjectReference object) {
053        if (HandInlinedScanning.ENABLED) {
054          int tibCode = AlignmentEncoding.getTibCode(object);
055          HandInlinedScanning.scanObject(tibCode, object.toObject(), trace);
056        } else {
057          SpecializedScanMethod.fallback(object.toObject(), trace);
058        }
059      }
060    
061      @Override
062      @Inline
063      public void specializedScanObject(int id, TransitiveClosure trace, ObjectReference object) {
064        if (HandInlinedScanning.ENABLED) {
065          int tibCode = AlignmentEncoding.getTibCode(object);
066          HandInlinedScanning.scanObject(tibCode, id, object.toObject(), trace);
067        } else {
068          if (SpecializedScanMethod.ENABLED) {
069            SpecializedScanMethod.invoke(id, object.toObject(), trace);
070          } else {
071            SpecializedScanMethod.fallback(object.toObject(), trace);
072          }
073        }
074      }
075    
076      @Override
077      public void resetThreadCounter() {
078        threadCounter.reset();
079      }
080    
081      @Override
082      public void notifyInitialThreadScanComplete() {
083        CompiledMethods.snipObsoleteCompiledMethods();
084        /* flush out any remset entries generated during the above activities */
085        Selected.Mutator.get().flushRememberedSets();
086      }
087    
088      /**
089       * Computes static roots.  This method establishes all such roots for
090       * collection and places them in the root locations queue.  This method
091       * should not have side effects (such as copying or forwarding of
092       * objects).  There are a number of important preconditions:
093       *
094       * <ul>
095       * <li> The <code>threadCounter</code> must be reset so that load
096       * balancing parallel GC can share the work of scanning threads.
097       * </ul>
098       *
099       * @param trace The trace to use for computing roots.
100       */
101      @Override
102      public void computeStaticRoots(TraceLocal trace) {
103        /* scan statics */
104        ScanStatics.scanStatics(trace);
105      }
106    
107      /**
108       * Computes global roots.  This method establishes all such roots for
109       * collection and places them in the root locations queue.  This method
110       * should not have side effects (such as copying or forwarding of
111       * objects).  There are a number of important preconditions:
112       *
113       * <ul>
114       * <li> The <code>threadCounter</code> must be reset so that load
115       * balancing parallel GC can share the work of scanning threads.
116       * </ul>
117       *
118       * @param trace The trace to use for computing roots.
119       */
120      @Override
121      public void computeGlobalRoots(TraceLocal trace) {
122        /* scan jni functions */
123        CollectorContext cc = RVMThread.getCurrentThread().getCollectorContext();
124        Address jniFunctions = Magic.objectAsAddress(JNIEnvironment.JNIFunctions);
125        int threads = cc.parallelWorkerCount();
126        int size = JNIEnvironment.JNIFunctions.length();
127        int chunkSize = size / threads;
128        int start = cc.parallelWorkerOrdinal() * chunkSize;
129        int end = (cc.parallelWorkerOrdinal()+1 == threads) ? size : threads * chunkSize;
130    
131        for(int i=start; i < end; i++) {
132          trace.processRootEdge(jniFunctions.plus(i << LOG_BYTES_IN_ADDRESS), true);
133        }
134    
135        Address linkageTriplets = Magic.objectAsAddress(JNIEnvironment.LinkageTriplets);
136        if (linkageTriplets != null) {
137          for(int i=start; i < end; i++) {
138            trace.processRootEdge(linkageTriplets.plus(i << LOG_BYTES_IN_ADDRESS), true);
139          }
140        }
141    
142        /* scan jni global refs */
143        Address jniGlobalRefs = Magic.objectAsAddress(JNIGlobalRefTable.JNIGlobalRefs);
144        size = JNIGlobalRefTable.JNIGlobalRefs.length();
145        chunkSize = size / threads;
146        start = cc.parallelWorkerOrdinal() * chunkSize;
147        end = (cc.parallelWorkerOrdinal()+1 == threads) ? size : threads * chunkSize;
148    
149        for(int i=start; i < end; i++) {
150          trace.processRootEdge(jniGlobalRefs.plus(i << LOG_BYTES_IN_ADDRESS), true);
151        }
152      }
153    
154      /**
155       * Computes roots pointed to by threads, their associated registers
156       * and stacks.  This method places these roots in the root values,
157       * root locations and interior root locations queues.  This method
158       * should not have side effects (such as copying or forwarding of
159       * objects).  There are a number of important preconditions:
160       *
161       * <ul>
162       * <li> The <code>threadCounter</code> must be reset so that load
163       * balancing parallel GC can share the work of scanning threads.
164       * </ul>
165       *
166       * TODO try to rewrite using chunking to avoid the per-thread synchronization?
167       *
168       * @param trace The trace to use for computing roots.
169       */
170      @Override
171      public void computeThreadRoots(TraceLocal trace) {
172        boolean processCodeLocations = MemoryManagerConstants.MOVES_CODE;
173    
174        /* scan all threads */
175        while (true) {
176          int threadIndex = threadCounter.increment();
177          if (threadIndex > RVMThread.numThreads) break;
178    
179          RVMThread thread = RVMThread.threads[threadIndex];
180          if (thread == null || thread.isCollectorThread()) continue;
181    
182          /* scan the thread (stack etc.) */
183          ScanThread.scanThread(thread, trace, processCodeLocations);
184        }
185    
186        /* flush out any remset entries generated during the above activities */
187        Selected.Mutator.get().flushRememberedSets();
188      }
189    
190      @Override
191      public void computeBootImageRoots(TraceLocal trace) {
192        ScanBootImage.scanBootImage(trace);
193      }
194    }