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 }