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.ArchitectureSpecific.Assembler;
016    import org.jikesrvm.VM;
017    import org.jikesrvm.Configuration;
018    import org.jikesrvm.SizeConstants;
019    import org.jikesrvm.classloader.RVMArray;
020    import org.jikesrvm.classloader.RVMClass;
021    import org.jikesrvm.classloader.RVMType;
022    import org.jikesrvm.mm.mminterface.MemoryManagerConstants;
023    import org.jikesrvm.runtime.Magic;
024    import org.jikesrvm.runtime.Memory;
025    import org.jikesrvm.scheduler.Lock;
026    import org.jikesrvm.scheduler.ThinLock;
027    import org.jikesrvm.scheduler.RVMThread;
028    import org.vmmagic.pragma.Inline;
029    import org.vmmagic.pragma.Interruptible;
030    import org.vmmagic.pragma.NoInline;
031    import org.vmmagic.pragma.Uninterruptible;
032    import org.vmmagic.pragma.Unpreemptible;
033    import org.vmmagic.unboxed.Address;
034    import org.vmmagic.unboxed.ObjectReference;
035    import org.vmmagic.unboxed.Offset;
036    import org.vmmagic.unboxed.Word;
037    
038    /**
039     * Defines the JavaHeader portion of the object header for the
040     * default JikesRVM object model.
041     * The default object model uses a two word header. <p>
042     *
043     * One word holds a TIB pointer. <p>
044     *
045     * The other word ("status word") contains an inline thin lock,
046     * either the hash code or hash code state, and a few unallocated
047     * bits that can be used for other purposes.
048     * If {@link JavaHeaderConstants#ADDRESS_BASED_HASHING} is false,
049     * then to implement default hashcodes, Jikes RVM uses a 10 bit hash code
050     * that is completely stored in the status word, which is laid out as
051     * shown below:
052     * <pre>
053     *      TTTT TTTT TTTT TTTT TTTT HHHH HHHH HHAA
054     * T = thin lock bits
055     * H = hash code
056     * A = available for use by GCHeader and/or MiscHeader.
057     * </pre>
058     *
059     * If {@link JavaHeaderConstants#ADDRESS_BASED_HASHING ADDRESS_BASED_HASHING} is true,
060     * then Jikes RVM uses two bits of the status word to record the hash code state in
061     * a typical three state scheme ({@link #HASH_STATE_UNHASHED}, {@link #HASH_STATE_HASHED},
062     * and {@link #HASH_STATE_HASHED_AND_MOVED}). In this case, the status word is laid
063     * out as shown below:
064     * <pre>
065     *      TTTT TTTT TTTT TTTT TTTT TTHH AAAA AAAA
066     * T = thin lock bits
067     * H = hash code state bits
068     * A = available for use by GCHeader and/or MiscHeader.
069     * </pre>
070     */
071    @Uninterruptible
072    public class JavaHeader implements JavaHeaderConstants {
073    
074      protected static final int SCALAR_HEADER_SIZE = JAVA_HEADER_BYTES + OTHER_HEADER_BYTES;
075      protected static final int ARRAY_HEADER_SIZE = SCALAR_HEADER_SIZE + ARRAY_LENGTH_BYTES;
076    
077      /** offset of object reference from the lowest memory word */
078      public static final int OBJECT_REF_OFFSET = ARRAY_HEADER_SIZE;  // from start to ref
079      protected static final Offset TIB_OFFSET = JAVA_HEADER_OFFSET;
080      protected static final Offset STATUS_OFFSET = TIB_OFFSET.plus(STATUS_BYTES);
081      protected static final Offset AVAILABLE_BITS_OFFSET =
082          VM.LittleEndian ? (STATUS_OFFSET) : (STATUS_OFFSET.plus(STATUS_BYTES - 1));
083    
084      /*
085       * Used for 10 bit header hash code in header (!ADDRESS_BASED_HASHING)
086       */
087      protected static final int HASH_CODE_SHIFT = 2;
088      protected static final Word HASH_CODE_MASK = Word.one().lsh(10).minus(Word.one()).lsh(HASH_CODE_SHIFT);
089      protected static Word hashCodeGenerator; // seed for generating hash codes with copying collectors.
090    
091      /** How many bits are allocated to a thin lock? */
092      public static final int NUM_THIN_LOCK_BITS = ADDRESS_BASED_HASHING ? 22 : 20;
093      /** How many bits to shift to get the thin lock? */
094      public static final int THIN_LOCK_SHIFT = ADDRESS_BASED_HASHING ? 10 : 12;
095      /** How many bytes do we have to offset to get to the high locking bits */
096      public static final int THIN_LOCK_DEDICATED_U16_OFFSET = VM.LittleEndian ? 2 : (VM.BuildFor64Addr ? 4 : 0);
097      /** How many bits do we have to shift to only hold the high locking bits */
098      public static final int THIN_LOCK_DEDICATED_U16_SHIFT  = 16;
099    
100      /** The alignment value **/
101      public static final int ALIGNMENT_VALUE = JavaHeaderConstants.ALIGNMENT_VALUE;
102      public static final int LOG_MIN_ALIGNMENT = JavaHeaderConstants.LOG_MIN_ALIGNMENT;
103    
104      static {
105        if (VM.VerifyAssertions) {
106          VM._assert(MiscHeader.REQUESTED_BITS + MemoryManagerConstants.GC_HEADER_BITS <= NUM_AVAILABLE_BITS);
107          VM._assert((THIN_LOCK_SHIFT + NUM_THIN_LOCK_BITS - THIN_LOCK_DEDICATED_U16_SHIFT) == 16);
108        }
109      }
110    
111      /**
112       * Return the TIB offset.
113       */
114      public static Offset getTibOffset() {
115        return TIB_OFFSET;
116      }
117    
118      /**
119       * What is the offset of the first word after the class?
120       * For use by ObjectModel.layoutInstanceFields
121       */
122      public static Offset objectEndOffset(RVMClass klass) {
123        return Offset.fromIntSignExtend(klass.getInstanceSizeInternal() - OBJECT_REF_OFFSET);
124      }
125    
126      /**
127       * What is the first word after the class?
128       */
129      public static Address getObjectEndAddress(Object obj, RVMClass type) {
130        int size = type.getInstanceSize();
131        if (ADDRESS_BASED_HASHING && DYNAMIC_HASH_OFFSET) {
132          Word hashState = Magic.objectAsAddress(obj).loadWord(STATUS_OFFSET).and(HASH_STATE_MASK);
133          if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
134            size += HASHCODE_BYTES;
135          }
136        }
137        return Magic.objectAsAddress(obj).plus(Memory.alignUp(size, SizeConstants.BYTES_IN_INT) -
138                                                  OBJECT_REF_OFFSET);
139      }
140    
141      /**
142       * What is the first word after the array?
143       */
144      public static Address getObjectEndAddress(Object obj, RVMArray type, int numElements) {
145        int size = type.getInstanceSize(numElements);
146        if (ADDRESS_BASED_HASHING && DYNAMIC_HASH_OFFSET) {
147          Word hashState = Magic.getWordAtOffset(obj, STATUS_OFFSET).and(HASH_STATE_MASK);
148          if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
149            size += HASHCODE_BYTES;
150          }
151        }
152        return Magic.objectAsAddress(obj).plus(Memory.alignUp(size, SizeConstants.BYTES_IN_INT) -
153                                                  OBJECT_REF_OFFSET);
154      }
155    
156      /**
157       * What is the offset of the first word of the class?
158       */
159      public static int objectStartOffset(RVMClass klass) {
160        return -OBJECT_REF_OFFSET;
161      }
162    
163      /**
164       * What is the last word of the header from an out-to-in perspective?
165       */
166      public static int getHeaderEndOffset() {
167        return SCALAR_HEADER_SIZE - OBJECT_REF_OFFSET;
168      }
169    
170      /**
171       * How small is the minimum object header size?
172       * Can be used to pick chunk sizes for allocators.
173       */
174      public static int minimumObjectSize() {
175        return SCALAR_HEADER_SIZE;
176      }
177    
178      /**
179       * Given a reference, return an address which is guaranteed to be inside
180       * the memory region allocated to the object.
181       */
182      public static Address getPointerInMemoryRegion(ObjectReference ref) {
183        return ref.toAddress().plus(TIB_OFFSET);
184      }
185    
186      /**
187       * Get the TIB for an object.
188       */
189      public static TIB getTIB(Object o) {
190        return Magic.getTIBAtOffset(o, TIB_OFFSET);
191      }
192    
193      /**
194       * Set the TIB for an object.
195       */
196      public static void setTIB(Object ref, TIB tib) {
197        Magic.setObjectAtOffset(ref, TIB_OFFSET, tib);
198      }
199    
200      /**
201       * Set the TIB for an object.
202       */
203      @Interruptible
204      public static void setTIB(BootImageInterface bootImage, Address refOffset, Address tibAddr, RVMType type) {
205        bootImage.setAddressWord(refOffset.plus(TIB_OFFSET), tibAddr.toWord(), false, false);
206      }
207    
208      /**
209       * how many bytes are needed when the scalar object is copied by GC?
210       */
211      public static int bytesRequiredWhenCopied(Object fromObj, RVMClass type) {
212        int size = type.getInstanceSize();
213        if (ADDRESS_BASED_HASHING) {
214          Word hashState = Magic.getWordAtOffset(fromObj, STATUS_OFFSET).and(HASH_STATE_MASK);
215          if (hashState.NE(HASH_STATE_UNHASHED)) {
216            size += HASHCODE_BYTES;
217          }
218        }
219        return size;
220      }
221    
222      /**
223       * how many bytes are used by the scalar object?
224       */
225      public static int bytesUsed(Object obj, RVMClass type) {
226        int size = type.getInstanceSize();
227        if (MemoryManagerConstants.MOVES_OBJECTS) {
228          if (ADDRESS_BASED_HASHING) {
229            Word hashState = Magic.getWordAtOffset(obj, STATUS_OFFSET).and(HASH_STATE_MASK);
230            if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
231              size += HASHCODE_BYTES;
232            }
233          }
234        }
235        return size;
236      }
237    
238      /**
239       * how many bytes are needed when the array object is copied by GC?
240       */
241      public static int bytesRequiredWhenCopied(Object fromObj, RVMArray type, int numElements) {
242        int size = type.getInstanceSize(numElements);
243        if (ADDRESS_BASED_HASHING) {
244          Word hashState = Magic.getWordAtOffset(fromObj, STATUS_OFFSET).and(HASH_STATE_MASK);
245          if (hashState.NE(HASH_STATE_UNHASHED)) {
246            size += HASHCODE_BYTES;
247          }
248        }
249        return Memory.alignUp(size, SizeConstants.BYTES_IN_INT);
250      }
251    
252      /**
253       * how many bytes are used by the array object?
254       */
255      public static int bytesUsed(Object obj, RVMArray type, int numElements) {
256        int size = type.getInstanceSize(numElements);
257        if (MemoryManagerConstants.MOVES_OBJECTS) {
258          if (ADDRESS_BASED_HASHING) {
259            Word hashState = Magic.getWordAtOffset(obj, STATUS_OFFSET).and(HASH_STATE_MASK);
260            if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
261              size += HASHCODE_BYTES;
262            }
263          }
264        }
265        return Memory.alignUp(size, SizeConstants.BYTES_IN_INT);
266      }
267    
268      /**
269       * Map from the object ref to the lowest address of the storage
270       * associated with the object
271       */
272      @Inline
273      public static Address objectStartRef(ObjectReference obj) {
274        if (MemoryManagerConstants.MOVES_OBJECTS) {
275          if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
276            Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK);
277            if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
278              return obj.toAddress().minus(OBJECT_REF_OFFSET + HASHCODE_BYTES);
279            }
280          }
281        }
282        return obj.toAddress().minus(OBJECT_REF_OFFSET);
283      }
284    
285      /**
286       * Get an object reference from the address the lowest word of the
287       * object was allocated.  In general this required that we are using
288       * a dynamic hash offset or not using address based
289       * hashing. However, the GC algorithm could safely do this in the
290       * nursery so we can't assert DYNAMIC_HASH_OFFSET.
291       */
292      public static ObjectReference getObjectFromStartAddress(Address start) {
293        while ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) {
294          start = start.plus(SizeConstants.BYTES_IN_WORD);
295        }
296        return start.plus(OBJECT_REF_OFFSET).toObjectReference();
297      }
298    
299      /**
300       * Get an object reference from the address the lowest word of the
301       * object was allocated.
302       */
303      public static ObjectReference getScalarFromStartAddress(Address start) {
304        return getObjectFromStartAddress(start);
305      }
306    
307      /**
308       * Get an object reference from the address the lowest word of the
309       * object was allocated.
310       */
311      public static ObjectReference getArrayFromStartAddress(Address start) {
312        return getObjectFromStartAddress(start);
313      }
314    
315      /**
316       * Get the next object in the heap under contiguous
317       * allocation. Handles alignment issues only when there are no GC or
318       * Misc header words. In the case there are we probably have to ask
319       * MemoryManager to distinguish this for us.
320       */
321      protected static ObjectReference getNextObject(ObjectReference obj, int size) {
322        if (VM.VerifyAssertions) VM._assert(OTHER_HEADER_BYTES == 0);
323    
324        return getObjectFromStartAddress(obj.toAddress().plus(size).minus(OBJECT_REF_OFFSET));
325      }
326    
327      /**
328       * Get the next scalar in the heap under contiguous
329       * allocation. Handles alignment issues
330       */
331      public static ObjectReference getNextObject(ObjectReference obj, RVMClass type) {
332        return getObjectFromStartAddress(getObjectEndAddress(obj.toObject(), type));
333      }
334    
335      /**
336       * Get the next array in the heap under contiguous
337       * allocation. Handles alignment issues
338       */
339      public static ObjectReference getNextObject(ObjectReference obj, RVMArray type, int numElements) {
340        return getObjectFromStartAddress(getObjectEndAddress(obj.toObject(), type, numElements));
341      }
342    
343      /**
344       * Get the reference of an array when copied to the specified region.
345       */
346      @Inline
347      public static Object getReferenceWhenCopiedTo(Object obj, Address to, RVMArray type) {
348        return getReferenceWhenCopiedTo(obj, to);
349      }
350    
351      /**
352       * Get the reference of a scalar when copied to the specified region.
353       */
354      @Inline
355      public static Object getReferenceWhenCopiedTo(Object obj, Address to, RVMClass type) {
356        return getReferenceWhenCopiedTo(obj, to);
357      }
358    
359      @Inline
360      protected static Object getReferenceWhenCopiedTo(Object obj, Address to) {
361        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
362          // Read the hash state (used below)
363          Word statusWord = Magic.getWordAtOffset(obj, STATUS_OFFSET);
364          Word hashState = statusWord.and(HASH_STATE_MASK);
365          if (hashState.NE(HASH_STATE_UNHASHED)) {
366            to = to.plus(HASHCODE_BYTES);
367          }
368        }
369        return Magic.addressAsObject(to.plus(OBJECT_REF_OFFSET));
370      }
371    
372      /**
373       * Copy a scalar to the given raw storage address
374       */
375      @Inline
376      public static Object moveObject(Address toAddress, Object fromObj, int numBytes, RVMClass type) {
377    
378        // We copy arrays and scalars the same way
379        return moveObject(toAddress, fromObj, null, numBytes);
380      }
381    
382      /**
383       * Copy an array to the given location.
384       */
385      @Inline
386      public static Object moveObject(Object fromObj, Object toObj, int numBytes, RVMClass type) {
387    
388        // We copy arrays and scalars the same way
389        return moveObject(Address.zero(), fromObj, toObj, numBytes);
390      }
391    
392      /**
393       * Copy an array to the given raw storage address
394       */
395      @Inline
396      public static Object moveObject(Address toAddress, Object fromObj, int numBytes, RVMArray type) {
397    
398        // We copy arrays and scalars the same way
399        return moveObject(toAddress, fromObj, null, numBytes);
400      }
401    
402      /**
403       * Copy an array to the given location.
404       */
405      @Inline
406      public static Object moveObject(Object fromObj, Object toObj, int numBytes, RVMArray type) {
407    
408        // We copy arrays and scalars the same way
409        return moveObject(Address.zero(), fromObj, toObj, numBytes);
410      }
411    
412      /**
413       * Copy an object to the given raw storage address
414       */
415      @Inline
416      public static Object moveObject(Address toAddress, Object fromObj, Object toObj, int numBytes) {
417        if (VM.VerifyAssertions) VM._assert(toAddress.isZero() || toObj == null);
418    
419        // Default values
420        int copyBytes = numBytes;
421        int objRefOffset = OBJECT_REF_OFFSET;
422        Word statusWord = Word.zero();
423        Word hashState = HASH_STATE_UNHASHED;
424    
425        if (ADDRESS_BASED_HASHING) {
426          // Read the hash state (used below)
427          statusWord = Magic.getWordAtOffset(fromObj, STATUS_OFFSET);
428          hashState = statusWord.and(HASH_STATE_MASK);
429          if (hashState.EQ(HASH_STATE_HASHED)) {
430            // We do not copy the hashcode, but we do allocate it
431            copyBytes -= HASHCODE_BYTES;
432    
433            if (!DYNAMIC_HASH_OFFSET) {
434              // The hashcode is the first word, so we copy to object one word higher
435              if (toObj == null) {
436                toAddress = toAddress.plus(HASHCODE_BYTES);
437              }
438            }
439          } else if (!DYNAMIC_HASH_OFFSET && hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
440            // Simple operation (no hash state change), but one word larger header
441            objRefOffset += HASHCODE_BYTES;
442          }
443        }
444    
445        if (toObj != null) {
446          toAddress = Magic.objectAsAddress(toObj).minus(objRefOffset);
447        }
448    
449        // Low memory word of source object
450        Address fromAddress = Magic.objectAsAddress(fromObj).minus(objRefOffset);
451    
452        // Do the copy
453        Memory.aligned32Copy(toAddress, fromAddress, copyBytes);
454    
455        if (toObj == null) {
456          toObj = Magic.addressAsObject(toAddress.plus(objRefOffset));
457        } else {
458          if (VM.VerifyAssertions) VM._assert(toObj == Magic.addressAsObject(toAddress.plus(objRefOffset)));
459        }
460    
461        // Do we need to copy the hash code?
462        if (hashState.EQ(HASH_STATE_HASHED)) {
463          int hashCode = Magic.objectAsAddress(fromObj).toWord().rshl(SizeConstants.LOG_BYTES_IN_ADDRESS).toInt();
464          if (DYNAMIC_HASH_OFFSET) {
465            Magic.setIntAtOffset(toObj, Offset.fromIntSignExtend(numBytes - OBJECT_REF_OFFSET - HASHCODE_BYTES), hashCode);
466          } else {
467            Magic.setIntAtOffset(toObj, HASHCODE_OFFSET, (hashCode << 1) | ALIGNMENT_MASK);
468          }
469          Magic.setWordAtOffset(toObj, STATUS_OFFSET, statusWord.or(HASH_STATE_HASHED_AND_MOVED));
470          if (ObjectModel.HASH_STATS) ObjectModel.hashTransition2++;
471        }
472    
473        return toObj;
474      }
475    
476      /**
477       * Get the hash code of an object.
478       */
479      @Inline
480      @Interruptible
481      public static int getObjectHashCode(Object o) {
482        if (ADDRESS_BASED_HASHING) {
483          if (MemoryManagerConstants.MOVES_OBJECTS) {
484            Word hashState = Magic.getWordAtOffset(o, STATUS_OFFSET).and(HASH_STATE_MASK);
485            if (hashState.EQ(HASH_STATE_HASHED)) {
486              // HASHED, NOT MOVED
487              return Magic.objectAsAddress(o).toWord().rshl(SizeConstants.LOG_BYTES_IN_ADDRESS).toInt();
488            } else if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
489              // HASHED AND MOVED
490              if (DYNAMIC_HASH_OFFSET) {
491                // Read the size of this object.
492                RVMType t = Magic.getObjectType(o);
493                int offset =
494                    t.isArrayType() ? t.asArray().getInstanceSize(Magic.getArrayLength(o)) -
495                                      OBJECT_REF_OFFSET : t.asClass().getInstanceSize() - OBJECT_REF_OFFSET;
496                return Magic.getIntAtOffset(o, Offset.fromIntSignExtend(offset));
497              } else {
498                return (Magic.getIntAtOffset(o, HASHCODE_OFFSET) >>> 1);
499              }
500            } else {
501              // UNHASHED
502              Word tmp;
503              do {
504                tmp = Magic.prepareWord(o, STATUS_OFFSET);
505              } while (!Magic.attemptWord(o, STATUS_OFFSET, tmp, tmp.or(HASH_STATE_HASHED)));
506              if (ObjectModel.HASH_STATS) ObjectModel.hashTransition1++;
507              return getObjectHashCode(o);
508            }
509          } else {
510            return Magic.objectAsAddress(o).toWord().rshl(SizeConstants.LOG_BYTES_IN_ADDRESS).toInt();
511          }
512        } else { // 10 bit hash code in status word
513          int hashCode = Magic.getWordAtOffset(o, STATUS_OFFSET).and(HASH_CODE_MASK).rshl(HASH_CODE_SHIFT).toInt();
514          if (hashCode != 0) {
515            return hashCode;
516          }
517          return installHashCode(o);
518        }
519      }
520    
521      /** Install a new hashcode (only used if !ADDRESS_BASED_HASHING) */
522      @NoInline
523      @Interruptible
524      protected static int installHashCode(Object o) {
525        Word hashCode;
526        do {
527          hashCodeGenerator = hashCodeGenerator.plus(Word.one().lsh(HASH_CODE_SHIFT));
528          hashCode = hashCodeGenerator.and(HASH_CODE_MASK);
529        } while (hashCode.isZero());
530        while (true) {
531          Word statusWord = Magic.prepareWord(o, STATUS_OFFSET);
532          if (!(statusWord.and(HASH_CODE_MASK).isZero())) {
533            // some other thread installed a hashcode
534            return statusWord.and(HASH_CODE_MASK).rshl(HASH_CODE_SHIFT).toInt();
535          }
536          if (Magic.attemptWord(o, STATUS_OFFSET, statusWord, statusWord.or(hashCode))) {
537            // we installed the hash code
538            return hashCode.rshl(HASH_CODE_SHIFT).toInt();
539          }
540        }
541      }
542    
543      /**
544       * Get the offset of the thin lock word in this object
545       */
546      public static Offset getThinLockOffset(Object o) {
547        return STATUS_OFFSET;
548      }
549    
550      /**
551       * what is the default offset for a thin lock?
552       */
553      public static Offset defaultThinLockOffset() {
554        return STATUS_OFFSET;
555      }
556    
557      /**
558       * Allocate a thin lock word for instances of the type
559       * (if they already have one, then has no effect).
560       */
561      public static void allocateThinLock(RVMType t) {
562        // nothing to do (all objects have thin locks in this object model);
563      }
564    
565      /**
566       * Generic lock
567       */
568      @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases")
569      public static void genericLock(Object o) {
570        ThinLock.lock(o, STATUS_OFFSET);
571      }
572    
573      /**
574       * Generic unlock
575       */
576      @Unpreemptible("No interruption unless of exceptions")
577      public static void genericUnlock(Object o) {
578        ThinLock.unlock(o, STATUS_OFFSET);
579      }
580    
581      /**
582       * @param obj an object
583       * @param thread a thread
584       * @return <code>true</code> if the lock on obj is currently owned
585       *         by thread <code>false</code> if it is not.
586       */
587      public static boolean holdsLock(Object obj, RVMThread thread) {
588        return ThinLock.holdsLock(obj, STATUS_OFFSET, thread);
589      }
590    
591      /**
592       * Obtains the heavy-weight lock, if there is one, associated with the
593       * indicated object.  Returns <code>null</code>, if there is no
594       * heavy-weight lock associated with the object.
595       *
596       * @param o the object from which a lock is desired
597       * @param create if true, create heavy lock if none found
598       * @return the heavy-weight lock on the object (if any)
599       */
600      @Unpreemptible("May be interrupted for allocations of locks")
601      public static Lock getHeavyLock(Object o, boolean create) {
602        return ThinLock.getHeavyLock(o, STATUS_OFFSET, create);
603      }
604    
605      /**
606       * Non-atomic read of word containing available bits
607       */
608      public static Word readAvailableBitsWord(Object o) {
609        return Magic.getWordAtOffset(o, STATUS_OFFSET);
610      }
611    
612      /**
613       * Non-atomic read of byte containing available bits
614       */
615      public static byte readAvailableByte(Object o) {
616        return Magic.getByteAtOffset(o, AVAILABLE_BITS_OFFSET);
617      }
618    
619      /**
620       * Non-atomic write of word containing available bits
621       */
622      public static void writeAvailableBitsWord(Object o, Word val) {
623        Magic.setWordAtOffset(o, STATUS_OFFSET, val);
624      }
625    
626      /**
627       * Non-atomic write of word containing available bits
628       */
629      @Interruptible
630      public static void writeAvailableByte(BootImageInterface bootImage, Address ref, byte val) {
631        bootImage.setByte(ref.plus(AVAILABLE_BITS_OFFSET), val);
632      }
633    
634      /**
635       * Non-atomic write of byte containing available bits
636       */
637      public static void writeAvailableByte(Object o, byte val) {
638        Magic.setByteAtOffset(o, AVAILABLE_BITS_OFFSET, val);
639      }
640    
641      /**
642       * Return true if argument bit is 1, false if it is 0
643       */
644      public static boolean testAvailableBit(Object o, int idx) {
645        Word mask = Word.fromIntSignExtend(1 << idx);
646        Word status = Magic.getWordAtOffset(o, STATUS_OFFSET);
647        return mask.and(status).NE(Word.zero());
648      }
649    
650      /**
651       * Set argument bit to 1 if value is true, 0 if value is false
652       */
653      public static void setAvailableBit(Object o, int idx, boolean flag) {
654        Word status = Magic.getWordAtOffset(o, STATUS_OFFSET);
655        if (flag) {
656          Word mask = Word.fromIntSignExtend(1 << idx);
657          Magic.setWordAtOffset(o, STATUS_OFFSET, status.or(mask));
658        } else {
659          Word mask = Word.fromIntSignExtend(1 << idx).not();
660          Magic.setWordAtOffset(o, STATUS_OFFSET, status.and(mask));
661        }
662      }
663    
664      /**
665       * Freeze the other bits in the byte containing the available bits
666       * so that it is safe to update them using setAvailableBits.
667       */
668      @Interruptible
669      public static void initializeAvailableByte(Object o) {
670        if (!ADDRESS_BASED_HASHING) getObjectHashCode(o);
671      }
672    
673      /**
674       * A prepare on the word containing the available bits
675       */
676      public static Word prepareAvailableBits(Object o) {
677        return Magic.prepareWord(o, STATUS_OFFSET);
678      }
679    
680      /**
681       * An attempt on the word containing the available bits
682       */
683      public static boolean attemptAvailableBits(Object o, Word oldVal, Word newVal) {
684        return Magic.attemptWord(o, STATUS_OFFSET, oldVal, newVal);
685      }
686    
687      /**
688       * Given the smallest base address in a region, return the smallest
689       * object reference that could refer to an object in the region.
690       */
691      public static Address minimumObjectRef(Address regionBaseAddr) {
692        return regionBaseAddr.plus(OBJECT_REF_OFFSET);
693      }
694    
695      /**
696       * Given the largest base address in a region, return the largest
697       * object reference that could refer to an object in the region.
698       */
699      public static Address maximumObjectRef(Address regionHighAddr) {
700        return regionHighAddr.plus(OBJECT_REF_OFFSET - SCALAR_HEADER_SIZE);
701      }
702    
703      /**
704       * Compute the header size of an instance of the given type.
705       */
706      public static int computeScalarHeaderSize(RVMClass type) {
707        return SCALAR_HEADER_SIZE;
708      }
709    
710      /**
711       * Compute the header size of an instance of the given type.
712       */
713      public static int computeArrayHeaderSize(RVMArray type) {
714        return ARRAY_HEADER_SIZE;
715      }
716    
717      /**
718       * Return the desired aligment of the alignment point returned by
719       * getOffsetForAlignment in instances of the argument RVMClass.
720       * @param t RVMClass instance being created
721       */
722      public static int getAlignment(RVMClass t) {
723        return t.getAlignment();
724      }
725    
726      /**
727       * Return the desired aligment of the alignment point returned by
728       * getOffsetForAlignment in instances of the argument RVMClass.
729       * @param t RVMClass instance being copied
730       * @param obj the object being copied
731       */
732      public static int getAlignment(RVMClass t, Object obj) {
733        return t.getAlignment();
734      }
735    
736      /**
737       * Return the desired alignment of the alignment point returned by
738       * getOffsetForAlignment in instances of the argument RVMArray.
739       * @param t RVMArray instance being created
740       */
741      public static int getAlignment(RVMArray t) {
742        return t.getAlignment();
743      }
744    
745      /**
746       * Return the desired alignment of the alignment point returned by
747       * getOffsetForAlignment in instances of the argument RVMArray.
748       * @param t RVMArray instance being copied
749       * @param obj the object being copied
750       */
751      public static int getAlignment(RVMArray t, Object obj) {
752        return t.getAlignment();
753      }
754    
755      /**
756       * Return the offset relative to physical beginning of object
757       * that must be aligned.
758       * @param t RVMClass instance being created
759       */
760      public static int getOffsetForAlignment(RVMClass t, boolean needsIdentityHash) {
761        /* Align the first field - note that this is one word off from
762           the reference. */
763        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET && needsIdentityHash) {
764          return SCALAR_HEADER_SIZE + HASHCODE_BYTES;
765        }
766        return SCALAR_HEADER_SIZE;
767      }
768    
769      /**
770       * Return the offset relative to physical beginning of object
771       * that must be aligned.
772       * @param t RVMClass instance being copied
773       * @param obj the object being copied
774       */
775      public static int getOffsetForAlignment(RVMClass t, ObjectReference obj) {
776        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
777          Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK);
778          if (hashState.NE(HASH_STATE_UNHASHED)) {
779            return SCALAR_HEADER_SIZE + HASHCODE_BYTES;
780          }
781        }
782        return SCALAR_HEADER_SIZE;
783      }
784    
785      /**
786       * Return the offset relative to physical beginning of object that must
787       * be aligned.
788       * @param t RVMArray instance being created
789       */
790      public static int getOffsetForAlignment(RVMArray t, boolean needsIdentityHash) {
791        /* although array_header_size == object_ref_offset we say this
792           because the whole point is to align the object ref */
793        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET && needsIdentityHash) {
794            return OBJECT_REF_OFFSET + HASHCODE_BYTES;
795        }
796        return OBJECT_REF_OFFSET;
797      }
798    
799      /**
800       * Return the offset relative to physical beginning of object that must
801       * be aligned.
802       * @param t RVMArray instance being copied
803       * @param obj the object being copied
804       */
805      public static int getOffsetForAlignment(RVMArray t, ObjectReference obj) {
806        /* although array_header_size == object_ref_offset we say this
807           because the whole point is to align the object ref */
808        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
809          Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK);
810          if (hashState.NE(HASH_STATE_UNHASHED)) {
811            return OBJECT_REF_OFFSET + HASHCODE_BYTES;
812          }
813        }
814        return OBJECT_REF_OFFSET;
815      }
816    
817      /**
818       * Perform any required initialization of the JAVA portion of the header.
819       * @param ptr the raw storage to be initialized
820       * @param tib the TIB of the instance being created
821       * @param size the number of bytes allocated by the GC system for this object.
822       */
823      public static Object initializeScalarHeader(Address ptr, TIB tib, int size) {
824        // (TIB set by ObjectModel)
825        Object ref = Magic.addressAsObject(ptr.plus(OBJECT_REF_OFFSET));
826        return ref;
827      }
828    
829      /**
830       * Perform any required initialization of the JAVA portion of the header.
831       * @param bootImage The bootimage being written
832       * @param ptr  The object ref to the storage to be initialized
833       * @param tib  The TIB of the instance being created
834       * @param size The number of bytes allocated by the GC system for this object.
835       * @param needsIdentityHash needs an identity hash value
836       * @param identityHashValue the value for the identity hash
837       * @return the address used for a reference to this object
838       */
839      @Interruptible
840      public static Address initializeScalarHeader(BootImageInterface bootImage, Address ptr, TIB tib, int size, boolean needsIdentityHash, int identityHashValue) {
841        Address ref = ptr.plus(OBJECT_REF_OFFSET);
842        if (needsIdentityHash) {
843          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED_AND_MOVED.toInt());
844          if (DYNAMIC_HASH_OFFSET) {
845            // Read the size of this object.
846            RVMType t = tib.getType();
847            bootImage.setFullWord(ptr.plus(t.asClass().getInstanceSize()), identityHashValue);
848          } else {
849            ref = ref.plus(HASHCODE_BYTES);
850            bootImage.setFullWord(ref.plus(HASHCODE_OFFSET), (identityHashValue << 1) | ALIGNMENT_MASK);
851          }
852        } else {
853          // As boot image objects can't move there is no benefit in lazily setting them to hashed
854          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED.toInt());
855        }
856        return ref;
857      }
858    
859      /**
860       * Perform any required initialization of the JAVA portion of the header.
861       * @param ptr the raw storage to be initialized
862       * @param tib the TIB of the instance being created
863       * @param size the number of bytes allocated by the GC system for this object.
864       */
865      public static Object initializeArrayHeader(Address ptr, TIB tib, int size) {
866        Object ref = Magic.addressAsObject(ptr.plus(OBJECT_REF_OFFSET));
867        // (TIB and array length set by ObjectModel)
868        return ref;
869      }
870    
871      /**
872       * Perform any required initialization of the JAVA portion of the header.
873       *
874       * @param bootImage the bootimage being written
875       * @param ptr  the object ref to the storage to be initialized
876       * @param tib the TIB of the instance being created
877       * @param size the number of bytes allocated by the GC system for this object.
878       * @param numElements the number of elements in the array
879       * @return the address used for a reference to this object
880       */
881      @Interruptible
882      public static Address initializeArrayHeader(BootImageInterface bootImage, Address ptr, TIB tib, int size, int numElements, boolean needsIdentityHash, int identityHashValue) {
883        Address ref = ptr.plus(OBJECT_REF_OFFSET);
884        // (TIB set by BootImageWriter; array length set by ObjectModel)
885        if (needsIdentityHash) {
886          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED_AND_MOVED.toInt());
887          if (DYNAMIC_HASH_OFFSET) {
888            // Read the size of this object.
889            RVMType t = tib.getType();
890            bootImage.setFullWord(ptr.plus(t.asArray().getInstanceSize(numElements)), identityHashValue);
891          } else {
892            ref = ref.plus(HASHCODE_BYTES);
893            bootImage.setFullWord(ref.plus(HASHCODE_OFFSET), (identityHashValue << 1) | ALIGNMENT_MASK);
894          }
895        } else {
896          // As boot image objects can't move there is no benefit in lazily setting them to hashed
897          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED.toInt());
898        }
899        return ref;
900      }
901    
902      /**
903       * For low level debugging of GC subsystem.
904       * Dump the header word(s) of the given object reference.
905       * @param ref the object reference whose header should be dumped
906       */
907      public static void dumpHeader(Object ref) {
908        // TIB dumped in ObjectModel
909        VM.sysWrite(" STATUS=");
910        VM.sysWriteHex(Magic.getWordAtOffset(ref, STATUS_OFFSET).toAddress());
911      }
912    
913      /**
914       * The following method will emit code that moves a reference to an
915       * object's TIB into a destination register.
916       *
917       * @param asm the assembler object to emit code with
918       * @param dest the number of the destination register
919       * @param object the number of the register holding the object reference
920       */
921      @Interruptible
922      public static void baselineEmitLoadTIB(Assembler asm, int dest, int object) {
923        Configuration.archHelper.baselineEmitLoadTIB(asm, dest, object, TIB_OFFSET);
924      }
925    }