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