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.mmtk.utility.sanitychecker; 014 015 import org.mmtk.plan.TraceLocal; 016 import org.mmtk.policy.RawPageSpace; 017 import org.mmtk.utility.Constants; 018 import org.mmtk.utility.deque.*; 019 import org.mmtk.utility.SimpleHashtable; 020 021 import org.vmmagic.pragma.*; 022 import org.vmmagic.unboxed.*; 023 024 /** 025 * This class implements a simple hashtable to store and retrieve per 026 * object information for sanity checking. <p> 027 * 028 * This class is not thread safe. 029 */ 030 @Uninterruptible 031 public final class SanityDataTable extends SimpleHashtable implements Constants { 032 033 /** The number of bits for the normal reference count */ 034 private static final int NORMAL_RC_BITS = 25; 035 036 /** The mask for the normal reference count */ 037 private static final int NORMAL_RC_MASK = (1 << 25) - 1; 038 039 /** The shift for the root reference count */ 040 private static final int ROOT_RC_SHIFT = NORMAL_RC_BITS; 041 042 /** The increment to use for normal increments */ 043 private static final int NORMAL_RC_INC = 1; 044 045 /** The increment to use for root increments */ 046 private static final int ROOT_RC_INC = 1 << ROOT_RC_SHIFT; 047 048 /** 049 * Create a new data table of a specified size. 050 * 051 * @param rps The space to acquire the data structure from. 052 * @param logSize The log of the number of table entries. 053 */ 054 public SanityDataTable(RawPageSpace rps, int logSize) { 055 super(rps, logSize, Extent.fromIntSignExtend(BYTES_IN_WORD)); 056 } 057 058 /** 059 * Increment the data word for an object. 060 * 061 * @param entry The table entry. 062 * @param root True if this is a root reference. 063 * @return True if this is the first ref to that object. 064 */ 065 @Inline 066 public static boolean incRC(Address entry, boolean root) { 067 Address data = SimpleHashtable.getPayloadAddress(entry); 068 int old = data.loadInt(); 069 data.store(old + (root ? ROOT_RC_INC : NORMAL_RC_INC)); 070 return (old == 0); 071 } 072 073 /** 074 * Push any entries that are only in this table, and not the 075 * passed table. This does not compare values. 076 * 077 * @param other The table to use for comparison. 078 * @param deque The buffer to push results onto. 079 */ 080 public void pushNotInOther(SanityDataTable other, 081 ObjectReferenceDeque deque) { 082 Address entry = getFirst(); 083 while (!entry.isZero()) { 084 Word key = SimpleHashtable.getKey(entry); 085 if (!other.contains(key)) { 086 deque.push(key.toAddress().toObjectReference()); 087 } 088 entry = getNext(entry); 089 } 090 } 091 092 093 /** 094 * Given an address of an entry, read the reference count, 095 * excluding root references. 096 * 097 * @param entry The entry 098 * @return The reference count. 099 */ 100 public static int getNormalRC(Address entry) { 101 return SimpleHashtable.getPayloadAddress(entry).loadInt() & NORMAL_RC_MASK; 102 } 103 104 /** 105 * Given an address of an entry, read the root reference count. 106 * 107 * @param entry The entry 108 * @return The root reference count. 109 */ 110 public static int getRootRC(Address entry) { 111 return SimpleHashtable.getPayloadAddress(entry).loadInt() >>> ROOT_RC_SHIFT; 112 } 113 114 /** 115 * Given an address of an entry, read the total reference count. 116 * 117 * @param entry The entry 118 * @return The total reference count. 119 */ 120 public static int getRC(Address entry) { 121 int val = SimpleHashtable.getPayloadAddress(entry).loadInt(); 122 return (val & NORMAL_RC_MASK) + val >>> ROOT_RC_SHIFT; 123 } 124 125 /** 126 * Given an address of an entry, read the reference component. 127 * 128 * @param entry The entry 129 * @return The object reference. 130 */ 131 public static ObjectReference getObjectReference(Address entry) { 132 return SimpleHashtable.getKey(entry).toAddress().toObjectReference(); 133 } 134 135 /** 136 * Forward data table using the supplied trace. Note that the data is 137 * not hashed correctly, so only enumeration can be used without 138 * rehashing. 139 * 140 * @param trace The trace to use. 141 */ 142 public void forwardTable(TraceLocal trace) { 143 Address entry = getFirst(); 144 while (!entry.isZero()) { 145 ObjectReference obj = getObjectReference(entry); 146 SimpleHashtable.replaceKey(entry, trace.getForwardedReference(obj).toAddress().toWord()); 147 entry = getNext(entry); 148 } 149 } 150 151 /** 152 * Get an entry for an object. 153 * 154 * @param object The object to find an entry for. 155 * @param create Create an entry if none exists? 156 * @return The entry address. 157 */ 158 public Address getEntry(ObjectReference object, boolean create) { 159 return super.getEntry(object.toAddress().toWord(), create); 160 } 161 }