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.jikesrvm.mm.mminterface;
014    
015    import static org.jikesrvm.SizeConstants.LOG_BYTES_IN_ADDRESS;
016    
017    import org.jikesrvm.VM;
018    import org.jikesrvm.objectmodel.JavaHeader;
019    import org.jikesrvm.objectmodel.ObjectModel;
020    import org.jikesrvm.runtime.Magic;
021    import org.vmmagic.pragma.Inline;
022    import org.vmmagic.pragma.Uninterruptible;
023    import org.vmmagic.unboxed.Address;
024    import org.vmmagic.unboxed.ObjectReference;
025    import org.vmmagic.unboxed.Word;
026    
027    /**
028     * Support for encoding a small amount of metadata in the alignment of
029     * a TIB.  We choose the alignment of the TIB so that the pointer
030     * looks like
031     * <pre>
032     *     31      24      16      8       0
033     *     +-------+-------+-------+-------+
034     *     xxxxxxxxxxxxxxxxxxxxxxxxxxxxfff00
035     * </pre>
036     * where the natural alignment of the object is preserved (the low-order bits
037     * are zero), and the next least significant <i>n</i> bits contain the
038     * encoded metadata.
039     * <p>
040     * With the cooperation of MemoryManager, the idea is that we allocate 2^n
041     * additional words of memory, then offset the object within the allocated
042     * region so that the value of <i>fff</i> is encoded.
043     * <p>
044     * The current implementation specifically encodes the TIB pointer, because this
045     * is the only pointer field where this technique can give a speedup that
046     * makes it worthwhile.
047     */
048    public class AlignmentEncoding {
049    
050      public static final int ALIGN_CODE_NONE = -1;
051    
052      /** Bits of metadata that we encode */
053      static final int FIELD_WIDTH = 3;
054    
055      /** Maximum distance (in words) that we shift an object */
056      private static final int MAX_ALIGN_WORDS = 1 << FIELD_WIDTH;
057    
058      /** First bit of the encoded field */
059      private static final int FIELD_SHIFT = LOG_BYTES_IN_ADDRESS;
060    
061      /** How far do we need to shift the object to increment the encoded field by 1 */
062      private static final int ALIGNMENT_INCREMENT = 1 << FIELD_SHIFT;
063    
064      /** Bit-mask to select out the encoded field */
065      private static final int TIB_ALIGN_MASK = (MAX_ALIGN_WORDS - 1) << FIELD_SHIFT;
066    
067      private static final boolean VERBOSE = false;
068    
069      /**
070       * Assert that a prospective encoded value is sane
071       * @param alignCode Prospective encoded value
072       */
073      static void assertSanity(int alignCode) {
074        if (VM.VerifyAssertions)  {
075          VM._assert(alignCode == ALIGN_CODE_NONE || (alignCode >= 0 && alignCode < MAX_ALIGN_WORDS));
076        }
077      }
078    
079      /**
080       * Number of padding bytes required.
081       * @param alignCode Prospective encoded value.
082       * @return the number of padding bytes required
083       */
084      public static int padding(int alignCode) {
085        if (alignCode == ALIGN_CODE_NONE)
086          return 0;
087        return (MAX_ALIGN_WORDS << FIELD_SHIFT);
088      }
089    
090      /**
091       * Adjust a region address so that the object pointer of an object that starts at this address
092       * will be aligned so as to encode the specified value.
093       *
094       * @param alignCode Value to encode
095       * @param region The initial region
096       * @return the aligned address
097       */
098      public static Address adjustRegion(int alignCode, Address region) {
099        assertSanity(alignCode);
100        if (alignCode == ALIGN_CODE_NONE)
101          return region;
102        // Now fake the region address to encode our data
103        final Address limit = region.plus(padding(alignCode));
104        if (VERBOSE) {
105          VM.sysWrite("Allocating TIB: region = ",region," tib code = ",getTibCodeForRegion(region));
106          VM.sysWriteln(", requested = ",alignCode);
107        }
108        while (getTibCodeForRegion(region) != alignCode) {
109          if (VM.runningVM) {
110            // Hack to allow alignment, but no alignment filling during boot
111            region.store(Word.fromIntZeroExtend(ObjectModel.ALIGNMENT_VALUE));
112          }
113          region = region.plus(ALIGNMENT_INCREMENT);
114          if (region.GT(limit)) {
115            VM.sysFail("Tib alignment fail");
116          }
117        }
118        if (VERBOSE) {
119          VM.sysWrite("           TIB: region = ",region," tib code = ",getTibCodeForRegion(region));
120          VM.sysWriteln(", requested = ",alignCode);
121        }
122        return region;
123      }
124    
125    
126      private static int getTibCodeForRegion(Address region) {
127        return extractTibCode(region.plus(JavaHeader.OBJECT_REF_OFFSET));
128      }
129    
130      /**
131       * Extract the encoded value from a TIB pointer,
132       * represented as a raw address.
133       * @param address
134       * @return the encoded value from a TIB pointer
135       */
136      @Uninterruptible
137      @Inline
138      public static int extractTibCode(Address address) {
139        return (address.toInt() & TIB_ALIGN_MASK) >> FIELD_SHIFT;
140      }
141    
142      /**
143       * Extract the encoded value from an object's TIB pointer
144       * @param object
145       * @return the encoded value from a TIB pointer
146       */
147      @Uninterruptible
148      @Inline
149      public static int getTibCode(ObjectReference object) {
150        int tibCode = extractTibCode(Magic.objectAsAddress(ObjectModel.getTIB(object)));
151        return tibCode;
152      }
153    
154    }