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}