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    }