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.objectmodel;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.Constants;
017    import org.jikesrvm.mm.mminterface.MemoryManagerConstants;
018    import org.jikesrvm.runtime.Magic;
019    import org.vmmagic.pragma.Entrypoint;
020    import org.vmmagic.pragma.Interruptible;
021    import org.vmmagic.pragma.Uninterruptible;
022    import org.vmmagic.unboxed.Address;
023    import org.vmmagic.unboxed.ObjectReference;
024    import org.vmmagic.unboxed.Offset;
025    import org.vmmagic.unboxed.Word;
026    
027    /**
028     * Defines other header words not used for
029     * core Java language support of memory allocation.
030     * Typically these are extra header words used for various
031     * kinds of instrumentation or profiling.
032     *
033     * @see ObjectModel
034     */
035    @Uninterruptible
036    public final class MiscHeader implements Constants, MiscHeaderConstants {
037    
038      private static final Offset MISC_HEADER_START = JavaHeaderConstants.MISC_HEADER_OFFSET;
039    
040      /* offset from object ref to .oid field, in bytes */
041      static final Offset OBJECT_OID_OFFSET = MISC_HEADER_START;
042      /* offset from object ref to OBJECT_DEATH field, in bytes */
043      static final Offset OBJECT_DEATH_OFFSET = OBJECT_OID_OFFSET.plus(BYTES_IN_ADDRESS);
044      /* offset from object ref to .link field, in bytes */
045      static final Offset OBJECT_LINK_OFFSET = OBJECT_DEATH_OFFSET.plus(BYTES_IN_ADDRESS);
046    
047      /////////////////////////
048      // Support for YYY (an example of how to add a word to all objects)
049      /////////////////////////
050      // offset from object ref to yet-to-be-defined instrumentation word
051      // static final int YYY_DATA_OFFSET_1 = (VM.YYY ? MISC_HEADER_START + GC_TRACING_HEADER_WORDS : 0);
052      // static final int YYY_DATA_OFFSET_2 = (VM.YYY ? MISC_HEADER_START + GC_TRACING_HEADER_WORDS + 4 : 0);
053      // static final int YYY_HEADER_BYTES = (VM.YYY ? 8 : 0);
054    
055      /**
056       * How many available bits does the misc header want to use?
057       */
058      static final int REQUESTED_BITS = 0;
059    
060      /**
061       * The next object ID to be used.
062       */
063      @Entrypoint
064      private static Word oid;
065      /**
066       * The current "time" for the trace being generated.
067       */
068      private static Word time;
069      /**
070       * The address of the last object allocated into the header.
071       */
072      @Entrypoint
073      private static Word prevAddress;
074    
075      static {
076        oid = Word.fromIntSignExtend(4);
077        time = Word.fromIntSignExtend(4);
078        prevAddress = Word.zero();
079      }
080    
081      /**
082       * Perform any required initialization of the MISC portion of the header.
083       * @param obj the object ref to the storage to be initialized
084       * @param tib the TIB of the instance being created
085       * @param size the number of bytes allocated by the GC system for this object.
086       * @param isScalar are we initializing a scalar (true) or array (false) object?
087       */
088      @Uninterruptible
089      public static void initializeHeader(Object obj, TIB tib, int size, boolean isScalar) {
090        /* Only perform initialization when it is required */
091        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
092          Address ref = Magic.objectAsAddress(obj);
093          ref.store(oid, OBJECT_OID_OFFSET);
094          ref.store(time, OBJECT_DEATH_OFFSET);
095          oid = oid.plus(Word.fromIntSignExtend((size - GC_TRACING_HEADER_BYTES) >> LOG_BYTES_IN_ADDRESS));
096        }
097      }
098    
099      /**
100       * Perform any required initialization of the MISC portion of the header.
101       * @param bootImage the bootimage being written
102       * @param ref the object ref to the storage to be initialized
103       * @param tib the TIB of the instance being created
104       * @param size the number of bytes allocated by the GC system for this object.
105       * @param isScalar are we initializing a scalar (true) or array (false) object?
106       */
107      @Interruptible("Only called during boot iamge creation")
108      public static void initializeHeader(BootImageInterface bootImage, Address ref, TIB tib, int size,
109                                          boolean isScalar) {
110        /* Only perform initialization when it is required */
111        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
112          bootImage.setAddressWord(ref.plus(OBJECT_OID_OFFSET), oid, false, false);
113          bootImage.setAddressWord(ref.plus(OBJECT_DEATH_OFFSET), time, false, false);
114          bootImage.setAddressWord(ref.plus(OBJECT_LINK_OFFSET), prevAddress, false, false);
115          prevAddress = ref.toWord();
116          oid = oid.plus(Word.fromIntSignExtend((size - GC_TRACING_HEADER_BYTES) >> LOG_BYTES_IN_ADDRESS));
117        }
118      }
119    
120      public static void updateDeathTime(Object object) {
121        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
122        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
123          Magic.objectAsAddress(object).store(time, OBJECT_DEATH_OFFSET);
124        }
125      }
126    
127      public static void setDeathTime(Object object, Word time_) {
128        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
129        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
130          Magic.objectAsAddress(object).store(time_, OBJECT_DEATH_OFFSET);
131        }
132      }
133    
134      public static void setLink(Object object, ObjectReference link) {
135        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
136        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
137          Magic.objectAsAddress(object).store(link, OBJECT_LINK_OFFSET);
138        }
139      }
140    
141      public static void updateTime(Word time_) {
142        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
143        time = time_;
144      }
145    
146      public static Word getOID(Object object) {
147        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
148        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
149          return Magic.objectAsAddress(object).plus(OBJECT_OID_OFFSET).loadWord();
150        } else {
151          return Word.zero();
152        }
153      }
154    
155      public static Word getDeathTime(Object object) {
156        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
157        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
158          return Magic.objectAsAddress(object).plus(OBJECT_DEATH_OFFSET).loadWord();
159        } else {
160          return Word.zero();
161        }
162      }
163    
164      public static ObjectReference getLink(Object ref) {
165        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
166        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
167          return ObjectReference.fromObject(Magic.getObjectAtOffset(ref, OBJECT_LINK_OFFSET));
168        } else {
169          return ObjectReference.nullReference();
170        }
171      }
172    
173      public static Address getBootImageLink() {
174        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
175        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
176          return prevAddress.toAddress();
177        } else {
178          return Address.zero();
179        }
180      }
181    
182      public static Word getOID() {
183        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
184        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
185          return oid;
186        } else {
187          return Word.zero();
188        }
189      }
190    
191      public static void setOID(Word oid_) {
192        if (VM.VerifyAssertions) VM._assert(MemoryManagerConstants.GENERATE_GC_TRACE);
193        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
194          oid = oid_;
195        }
196      }
197    
198      public static int getHeaderSize() {
199        return NUM_BYTES_HEADER;
200      }
201    
202      /**
203       * For low level debugging of GC subsystem.
204       * Dump the header word(s) of the given object reference.
205       * @param ref the object reference whose header should be dumped
206       */
207      public static void dumpHeader(Object ref) {
208        // by default nothing to do, unless the misc header is required
209        if (MemoryManagerConstants.GENERATE_GC_TRACE) {
210          VM.sysWrite(" OID=", getOID(ref));
211          VM.sysWrite(" LINK=", getLink(ref));
212          VM.sysWrite(" DEATH=", getDeathTime(ref));
213        }
214      }
215    }