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