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 }