/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.utility.sanitychecker;
import static org.mmtk.utility.Constants.BYTES_IN_WORD;
import org.mmtk.plan.TraceLocal;
import org.mmtk.policy.RawPageSpace;
import org.mmtk.utility.deque.*;
import org.mmtk.utility.SimpleHashtable;
import org.vmmagic.pragma.*;
import org.vmmagic.unboxed.*;
/**
* This class implements a simple hashtable to store and retrieve per
* object information for sanity checking. <p>
*
* This class is not thread safe.
*/
@Uninterruptible
public final class SanityDataTable extends SimpleHashtable {
/** The number of bits for the normal reference count */
private static final int NORMAL_RC_BITS = 25;
/** The mask for the normal reference count */
private static final int NORMAL_RC_MASK = (1 << 25) - 1;
/** The shift for the root reference count */
private static final int ROOT_RC_SHIFT = NORMAL_RC_BITS;
/** The increment to use for normal increments */
private static final int NORMAL_RC_INC = 1;
/** The increment to use for root increments */
private static final int ROOT_RC_INC = 1 << ROOT_RC_SHIFT;
/**
* Create a new data table of a specified size.
*
* @param rps The space to acquire the data structure from.
* @param logSize The log of the number of table entries.
*/
public SanityDataTable(RawPageSpace rps, int logSize) {
super(rps, logSize, Extent.fromIntSignExtend(BYTES_IN_WORD));
}
/**
* Increment the data word for an object.
*
* @param entry The table entry.
* @param root True if this is a root reference.
* @return True if this is the first ref to that object.
*/
@Inline
public static boolean incRC(Address entry, boolean root) {
Address data = SimpleHashtable.getPayloadAddress(entry);
int old = data.loadInt();
data.store(old + (root ? ROOT_RC_INC : NORMAL_RC_INC));
return (old == 0);
}
/**
* Push any entries that are only in this table, and not the
* passed table. This does not compare values.
*
* @param other The table to use for comparison.
* @param deque The buffer to push results onto.
*/
public void pushNotInOther(SanityDataTable other,
ObjectReferenceDeque deque) {
Address entry = getFirst();
while (!entry.isZero()) {
Word key = SimpleHashtable.getKey(entry);
if (!other.contains(key)) {
deque.push(key.toAddress().toObjectReference());
}
entry = getNext(entry);
}
}
/**
* Given an address of an entry, read the reference count,
* excluding root references.
*
* @param entry The entry
* @return The reference count.
*/
public static int getNormalRC(Address entry) {
return SimpleHashtable.getPayloadAddress(entry).loadInt() & NORMAL_RC_MASK;
}
/**
* Given an address of an entry, read the root reference count.
*
* @param entry The entry
* @return The root reference count.
*/
public static int getRootRC(Address entry) {
return SimpleHashtable.getPayloadAddress(entry).loadInt() >>> ROOT_RC_SHIFT;
}
/**
* Given an address of an entry, read the total reference count.
*
* @param entry The entry
* @return The total reference count.
*/
public static int getRC(Address entry) {
int val = SimpleHashtable.getPayloadAddress(entry).loadInt();
return (val & NORMAL_RC_MASK) + val >>> ROOT_RC_SHIFT;
}
/**
* Given an address of an entry, read the reference component.
*
* @param entry The entry
* @return The object reference.
*/
public static ObjectReference getObjectReference(Address entry) {
return SimpleHashtable.getKey(entry).toAddress().toObjectReference();
}
/**
* Forward data table using the supplied trace. Note that the data is
* not hashed correctly, so only enumeration can be used without
* rehashing.
*
* @param trace The trace to use.
*/
public void forwardTable(TraceLocal trace) {
Address entry = getFirst();
while (!entry.isZero()) {
ObjectReference obj = getObjectReference(entry);
SimpleHashtable.replaceKey(entry, trace.getForwardedReference(obj).toAddress().toWord());
entry = getNext(entry);
}
}
/**
* Get an entry for an object.
*
* @param object The object to find an entry for.
* @param create Create an entry if none exists?
* @return The entry address.
*/
public Address getEntry(ObjectReference object, boolean create) {
return super.getEntry(object.toAddress().toWord(), create);
}
}