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      protected 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        if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) {
294          start = start.plus(SizeConstants.BYTES_IN_WORD);
295          if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) {
296            start = start.plus(SizeConstants.BYTES_IN_WORD);
297            if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) {
298              start = start.plus(SizeConstants.BYTES_IN_WORD);
299              if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) {
300                start = start.plus(SizeConstants.BYTES_IN_WORD);
301                if ((start.loadWord().toInt() & ALIGNMENT_MASK) == ALIGNMENT_MASK) {
302                  return ObjectReference.nullReference();
303                }
304              }
305            }
306          }
307        }
308    
309        return start.plus(OBJECT_REF_OFFSET).toObjectReference();
310      }
311    
312      /**
313       * Get an object reference from the address the lowest word of the
314       * object was allocated.
315       */
316      public static ObjectReference getScalarFromStartAddress(Address start) {
317        return getObjectFromStartAddress(start);
318      }
319    
320      /**
321       * Get an object reference from the address the lowest word of the
322       * object was allocated.
323       */
324      public static ObjectReference getArrayFromStartAddress(Address start) {
325        return getObjectFromStartAddress(start);
326      }
327    
328      /**
329       * Get the next object in the heap under contiguous
330       * allocation. Handles alignment issues only when there are no GC or
331       * Misc header words. In the case there are we probably have to ask
332       * MemoryManager to distinguish this for us.
333       */
334      protected static ObjectReference getNextObject(ObjectReference obj, int size) {
335        if (VM.VerifyAssertions) VM._assert(OTHER_HEADER_BYTES == 0);
336    
337        return getObjectFromStartAddress(obj.toAddress().plus(size).minus(OBJECT_REF_OFFSET));
338      }
339    
340      /**
341       * Get the next scalar in the heap under contiguous
342       * allocation. Handles alignment issues
343       */
344      public static ObjectReference getNextObject(ObjectReference obj, RVMClass type) {
345        return getObjectFromStartAddress(getObjectEndAddress(obj.toObject(), type));
346      }
347    
348      /**
349       * Get the next array in the heap under contiguous
350       * allocation. Handles alignment issues
351       */
352      public static ObjectReference getNextObject(ObjectReference obj, RVMArray type, int numElements) {
353        return getObjectFromStartAddress(getObjectEndAddress(obj.toObject(), type, numElements));
354      }
355    
356      /**
357       * Get the reference of an array when copied to the specified region.
358       */
359      @Inline
360      public static Object getReferenceWhenCopiedTo(Object obj, Address to, RVMArray type) {
361        return getReferenceWhenCopiedTo(obj, to);
362      }
363    
364      /**
365       * Get the reference of a scalar when copied to the specified region.
366       */
367      @Inline
368      public static Object getReferenceWhenCopiedTo(Object obj, Address to, RVMClass type) {
369        return getReferenceWhenCopiedTo(obj, to);
370      }
371    
372      @Inline
373      protected static Object getReferenceWhenCopiedTo(Object obj, Address to) {
374        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
375          // Read the hash state (used below)
376          Word statusWord = Magic.getWordAtOffset(obj, STATUS_OFFSET);
377          Word hashState = statusWord.and(HASH_STATE_MASK);
378          if (hashState.NE(HASH_STATE_UNHASHED)) {
379            to = to.plus(HASHCODE_BYTES);
380          }
381        }
382        return Magic.addressAsObject(to.plus(OBJECT_REF_OFFSET));
383      }
384    
385      /**
386       * Copy a scalar to the given raw storage address
387       */
388      @Inline
389      public static Object moveObject(Address toAddress, Object fromObj, int numBytes, RVMClass type) {
390    
391        // We copy arrays and scalars the same way
392        return moveObject(toAddress, fromObj, null, numBytes);
393      }
394    
395      /**
396       * Copy an array to the given location.
397       */
398      @Inline
399      public static Object moveObject(Object fromObj, Object toObj, int numBytes, RVMClass type) {
400    
401        // We copy arrays and scalars the same way
402        return moveObject(Address.zero(), fromObj, toObj, numBytes);
403      }
404    
405      /**
406       * Copy an array to the given raw storage address
407       */
408      @Inline
409      public static Object moveObject(Address toAddress, Object fromObj, int numBytes, RVMArray type) {
410    
411        // We copy arrays and scalars the same way
412        return moveObject(toAddress, fromObj, null, numBytes);
413      }
414    
415      /**
416       * Copy an array to the given location.
417       */
418      @Inline
419      public static Object moveObject(Object fromObj, Object toObj, int numBytes, RVMArray type) {
420    
421        // We copy arrays and scalars the same way
422        return moveObject(Address.zero(), fromObj, toObj, numBytes);
423      }
424    
425      /**
426       * Copy an object to the given raw storage address
427       */
428      @Inline
429      public static Object moveObject(Address toAddress, Object fromObj, Object toObj, int numBytes) {
430        if (VM.VerifyAssertions) VM._assert(toAddress.isZero() || toObj == null);
431    
432        // Default values
433        int copyBytes = numBytes;
434        int objRefOffset = OBJECT_REF_OFFSET;
435        Word statusWord = Word.zero();
436        Word hashState = HASH_STATE_UNHASHED;
437    
438        if (ADDRESS_BASED_HASHING) {
439          // Read the hash state (used below)
440          statusWord = Magic.getWordAtOffset(fromObj, STATUS_OFFSET);
441          hashState = statusWord.and(HASH_STATE_MASK);
442          if (hashState.EQ(HASH_STATE_HASHED)) {
443            // We do not copy the hashcode, but we do allocate it
444            copyBytes -= HASHCODE_BYTES;
445    
446            if (!DYNAMIC_HASH_OFFSET) {
447              // The hashcode is the first word, so we copy to object one word higher
448              if (toObj == null) {
449                toAddress = toAddress.plus(HASHCODE_BYTES);
450              }
451            }
452          } else if (!DYNAMIC_HASH_OFFSET && hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
453            // Simple operation (no hash state change), but one word larger header
454            objRefOffset += HASHCODE_BYTES;
455          }
456        }
457    
458        if (toObj != null) {
459          toAddress = Magic.objectAsAddress(toObj).minus(objRefOffset);
460        }
461    
462        // Low memory word of source object
463        Address fromAddress = Magic.objectAsAddress(fromObj).minus(objRefOffset);
464    
465        // Do the copy
466        Memory.aligned32Copy(toAddress, fromAddress, copyBytes);
467    
468        if (toObj == null) {
469          toObj = Magic.addressAsObject(toAddress.plus(objRefOffset));
470        } else {
471          if (VM.VerifyAssertions) VM._assert(toObj == Magic.addressAsObject(toAddress.plus(objRefOffset)));
472        }
473    
474        // Do we need to copy the hash code?
475        if (hashState.EQ(HASH_STATE_HASHED)) {
476          int hashCode = Magic.objectAsAddress(fromObj).toWord().rshl(SizeConstants.LOG_BYTES_IN_ADDRESS).toInt();
477          if (DYNAMIC_HASH_OFFSET) {
478            Magic.setIntAtOffset(toObj, Offset.fromIntSignExtend(numBytes - OBJECT_REF_OFFSET - HASHCODE_BYTES), hashCode);
479          } else {
480            Magic.setIntAtOffset(toObj, HASHCODE_OFFSET, (hashCode << 1) | ALIGNMENT_MASK);
481          }
482          Magic.setWordAtOffset(toObj, STATUS_OFFSET, statusWord.or(HASH_STATE_HASHED_AND_MOVED));
483          if (ObjectModel.HASH_STATS) ObjectModel.hashTransition2++;
484        }
485    
486        return toObj;
487      }
488    
489      /**
490       * Get the hash code of an object.
491       */
492      @Inline
493      @Interruptible
494      public static int getObjectHashCode(Object o) {
495        if (ADDRESS_BASED_HASHING) {
496          if (MemoryManagerConstants.MOVES_OBJECTS) {
497            Word hashState = Magic.getWordAtOffset(o, STATUS_OFFSET).and(HASH_STATE_MASK);
498            if (hashState.EQ(HASH_STATE_HASHED)) {
499              // HASHED, NOT MOVED
500              return Magic.objectAsAddress(o).toWord().rshl(SizeConstants.LOG_BYTES_IN_ADDRESS).toInt();
501            } else if (hashState.EQ(HASH_STATE_HASHED_AND_MOVED)) {
502              // HASHED AND MOVED
503              if (DYNAMIC_HASH_OFFSET) {
504                // Read the size of this object.
505                RVMType t = Magic.getObjectType(o);
506                int offset =
507                    t.isArrayType() ? t.asArray().getInstanceSize(Magic.getArrayLength(o)) -
508                                      OBJECT_REF_OFFSET : t.asClass().getInstanceSize() - OBJECT_REF_OFFSET;
509                return Magic.getIntAtOffset(o, Offset.fromIntSignExtend(offset));
510              } else {
511                return (Magic.getIntAtOffset(o, HASHCODE_OFFSET) >>> 1);
512              }
513            } else {
514              // UNHASHED
515              Word tmp;
516              do {
517                tmp = Magic.prepareWord(o, STATUS_OFFSET);
518              } while (!Magic.attemptWord(o, STATUS_OFFSET, tmp, tmp.or(HASH_STATE_HASHED)));
519              if (ObjectModel.HASH_STATS) ObjectModel.hashTransition1++;
520              return getObjectHashCode(o);
521            }
522          } else {
523            return Magic.objectAsAddress(o).toWord().rshl(SizeConstants.LOG_BYTES_IN_ADDRESS).toInt();
524          }
525        } else { // 10 bit hash code in status word
526          int hashCode = Magic.getWordAtOffset(o, STATUS_OFFSET).and(HASH_CODE_MASK).rshl(HASH_CODE_SHIFT).toInt();
527          if (hashCode != 0) {
528            return hashCode;
529          }
530          return installHashCode(o);
531        }
532      }
533    
534      /** Install a new hashcode (only used if !ADDRESS_BASED_HASHING) */
535      @NoInline
536      @Interruptible
537      protected static int installHashCode(Object o) {
538        Word hashCode;
539        do {
540          hashCodeGenerator = hashCodeGenerator.plus(Word.one().lsh(HASH_CODE_SHIFT));
541          hashCode = hashCodeGenerator.and(HASH_CODE_MASK);
542        } while (hashCode.isZero());
543        while (true) {
544          Word statusWord = Magic.prepareWord(o, STATUS_OFFSET);
545          if (!(statusWord.and(HASH_CODE_MASK).isZero())) {
546            // some other thread installed a hashcode
547            return statusWord.and(HASH_CODE_MASK).rshl(HASH_CODE_SHIFT).toInt();
548          }
549          if (Magic.attemptWord(o, STATUS_OFFSET, statusWord, statusWord.or(hashCode))) {
550            // we installed the hash code
551            return hashCode.rshl(HASH_CODE_SHIFT).toInt();
552          }
553        }
554      }
555    
556      /**
557       * Get the offset of the thin lock word in this object
558       */
559      public static Offset getThinLockOffset(Object o) {
560        return STATUS_OFFSET;
561      }
562    
563      /**
564       * what is the default offset for a thin lock?
565       */
566      public static Offset defaultThinLockOffset() {
567        return STATUS_OFFSET;
568      }
569    
570      /**
571       * Allocate a thin lock word for instances of the type
572       * (if they already have one, then has no effect).
573       */
574      public static void allocateThinLock(RVMType t) {
575        // nothing to do (all objects have thin locks in this object model);
576      }
577    
578      /**
579       * Generic lock
580       */
581      @Unpreemptible("Become another thread when lock is contended, don't preempt in other cases")
582      public static void genericLock(Object o) {
583        ThinLock.lock(o, STATUS_OFFSET);
584      }
585    
586      /**
587       * Generic unlock
588       */
589      @Unpreemptible("No interruption unless of exceptions")
590      public static void genericUnlock(Object o) {
591        ThinLock.unlock(o, STATUS_OFFSET);
592      }
593    
594      /**
595       * @param obj an object
596       * @param thread a thread
597       * @return <code>true</code> if the lock on obj is currently owned
598       *         by thread <code>false</code> if it is not.
599       */
600      public static boolean holdsLock(Object obj, RVMThread thread) {
601        return ThinLock.holdsLock(obj, STATUS_OFFSET, thread);
602      }
603    
604      /**
605       * Obtains the heavy-weight lock, if there is one, associated with the
606       * indicated object.  Returns <code>null</code>, if there is no
607       * heavy-weight lock associated with the object.
608       *
609       * @param o the object from which a lock is desired
610       * @param create if true, create heavy lock if none found
611       * @return the heavy-weight lock on the object (if any)
612       */
613      @Unpreemptible("May be interrupted for allocations of locks")
614      public static Lock getHeavyLock(Object o, boolean create) {
615        return ThinLock.getHeavyLock(o, STATUS_OFFSET, create);
616      }
617    
618      /**
619       * Non-atomic read of word containing available bits
620       */
621      public static Word readAvailableBitsWord(Object o) {
622        return Magic.getWordAtOffset(o, STATUS_OFFSET);
623      }
624    
625      /**
626       * Non-atomic read of byte containing available bits
627       */
628      public static byte readAvailableByte(Object o) {
629        return Magic.getByteAtOffset(o, AVAILABLE_BITS_OFFSET);
630      }
631    
632      /**
633       * Non-atomic write of word containing available bits
634       */
635      public static void writeAvailableBitsWord(Object o, Word val) {
636        Magic.setWordAtOffset(o, STATUS_OFFSET, val);
637      }
638    
639      /**
640       * Non-atomic write of word containing available bits
641       */
642      @Interruptible
643      public static void writeAvailableByte(BootImageInterface bootImage, Address ref, byte val) {
644        bootImage.setByte(ref.plus(AVAILABLE_BITS_OFFSET), val);
645      }
646    
647      /**
648       * Non-atomic write of byte containing available bits
649       */
650      public static void writeAvailableByte(Object o, byte val) {
651        Magic.setByteAtOffset(o, AVAILABLE_BITS_OFFSET, val);
652      }
653    
654      /**
655       * Return true if argument bit is 1, false if it is 0
656       */
657      public static boolean testAvailableBit(Object o, int idx) {
658        Word mask = Word.fromIntSignExtend(1 << idx);
659        Word status = Magic.getWordAtOffset(o, STATUS_OFFSET);
660        return mask.and(status).NE(Word.zero());
661      }
662    
663      /**
664       * Set argument bit to 1 if value is true, 0 if value is false
665       */
666      public static void setAvailableBit(Object o, int idx, boolean flag) {
667        Word status = Magic.getWordAtOffset(o, STATUS_OFFSET);
668        if (flag) {
669          Word mask = Word.fromIntSignExtend(1 << idx);
670          Magic.setWordAtOffset(o, STATUS_OFFSET, status.or(mask));
671        } else {
672          Word mask = Word.fromIntSignExtend(1 << idx).not();
673          Magic.setWordAtOffset(o, STATUS_OFFSET, status.and(mask));
674        }
675      }
676    
677      /**
678       * Freeze the other bits in the byte containing the available bits
679       * so that it is safe to update them using setAvailableBits.
680       */
681      @Interruptible
682      public static void initializeAvailableByte(Object o) {
683        if (!ADDRESS_BASED_HASHING) getObjectHashCode(o);
684      }
685    
686      /**
687       * A prepare on the word containing the available bits
688       */
689      public static Word prepareAvailableBits(Object o) {
690        return Magic.prepareWord(o, STATUS_OFFSET);
691      }
692    
693      /**
694       * An attempt on the word containing the available bits
695       */
696      public static boolean attemptAvailableBits(Object o, Word oldVal, Word newVal) {
697        return Magic.attemptWord(o, STATUS_OFFSET, oldVal, newVal);
698      }
699    
700      /**
701       * Given the smallest base address in a region, return the smallest
702       * object reference that could refer to an object in the region.
703       */
704      public static Address minimumObjectRef(Address regionBaseAddr) {
705        return regionBaseAddr.plus(OBJECT_REF_OFFSET);
706      }
707    
708      /**
709       * Given the largest base address in a region, return the largest
710       * object reference that could refer to an object in the region.
711       */
712      public static Address maximumObjectRef(Address regionHighAddr) {
713        return regionHighAddr.plus(OBJECT_REF_OFFSET - SCALAR_HEADER_SIZE);
714      }
715    
716      /**
717       * Compute the header size of an instance of the given type.
718       */
719      public static int computeScalarHeaderSize(RVMClass type) {
720        return SCALAR_HEADER_SIZE;
721      }
722    
723      /**
724       * Compute the header size of an instance of the given type.
725       */
726      public static int computeArrayHeaderSize(RVMArray type) {
727        return ARRAY_HEADER_SIZE;
728      }
729    
730      /**
731       * Return the desired aligment of the alignment point returned by
732       * getOffsetForAlignment in instances of the argument RVMClass.
733       * @param t RVMClass instance being created
734       */
735      public static int getAlignment(RVMClass t) {
736        return t.getAlignment();
737      }
738    
739      /**
740       * Return the desired aligment of the alignment point returned by
741       * getOffsetForAlignment in instances of the argument RVMClass.
742       * @param t RVMClass instance being copied
743       * @param obj the object being copied
744       */
745      public static int getAlignment(RVMClass t, Object obj) {
746        return t.getAlignment();
747      }
748    
749      /**
750       * Return the desired aligment of the alignment point returned by
751       * getOffsetForAlignment in instances of the argument RVMArray.
752       * @param t RVMArray instance being created
753       */
754      public static int getAlignment(RVMArray t) {
755        return t.getAlignment();
756      }
757    
758      /**
759       * Return the desired aligment of the alignment point returned by
760       * getOffsetForAlignment in instances of the argument RVMArray.
761       * @param t RVMArray instance being copied
762       * @param obj the object being copied
763       */
764      public static int getAlignment(RVMArray t, Object obj) {
765        return t.getAlignment();
766      }
767    
768      /**
769       * Return the offset relative to physical beginning of object
770       * that must be aligned.
771       * @param t RVMClass instance being created
772       */
773      public static int getOffsetForAlignment(RVMClass t, boolean needsIdentityHash) {
774        /* Align the first field - note that this is one word off from
775           the reference. */
776        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET && needsIdentityHash) {
777          return SCALAR_HEADER_SIZE + HASHCODE_BYTES;
778        }
779        return SCALAR_HEADER_SIZE;
780      }
781    
782      /**
783       * Return the offset relative to physical beginning of object
784       * that must be aligned.
785       * @param t RVMClass instance being copied
786       * @param obj the object being copied
787       */
788      public static int getOffsetForAlignment(RVMClass t, ObjectReference obj) {
789        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
790          Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK);
791          if (hashState.NE(HASH_STATE_UNHASHED)) {
792            return SCALAR_HEADER_SIZE + HASHCODE_BYTES;
793          }
794        }
795        return SCALAR_HEADER_SIZE;
796      }
797    
798      /**
799       * Return the offset relative to physical beginning of object that must
800       * be aligned.
801       * @param t RVMArray instance being created
802       */
803      public static int getOffsetForAlignment(RVMArray t, boolean needsIdentityHash) {
804        /* although array_header_size == object_ref_offset we say this
805           because the whole point is to align the object ref */
806        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET && needsIdentityHash) {
807            return OBJECT_REF_OFFSET + HASHCODE_BYTES;
808        }
809        return OBJECT_REF_OFFSET;
810      }
811    
812      /**
813       * Return the offset relative to physical beginning of object that must
814       * be aligned.
815       * @param t RVMArray instance being copied
816       * @param obj the object being copied
817       */
818      public static int getOffsetForAlignment(RVMArray t, ObjectReference obj) {
819        /* although array_header_size == object_ref_offset we say this
820           because the whole point is to align the object ref */
821        if (ADDRESS_BASED_HASHING && !DYNAMIC_HASH_OFFSET) {
822          Word hashState = obj.toAddress().loadWord(STATUS_OFFSET).and(HASH_STATE_MASK);
823          if (hashState.NE(HASH_STATE_UNHASHED)) {
824            return OBJECT_REF_OFFSET + HASHCODE_BYTES;
825          }
826        }
827        return OBJECT_REF_OFFSET;
828      }
829    
830      /**
831       * Perform any required initialization of the JAVA portion of the header.
832       * @param ptr the raw 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       */
836      public static Object initializeScalarHeader(Address ptr, TIB tib, int size) {
837        // (TIB set by ObjectModel)
838        Object ref = Magic.addressAsObject(ptr.plus(OBJECT_REF_OFFSET));
839        return ref;
840      }
841    
842      /**
843       * Perform any required initialization of the JAVA portion of the header.
844       * @param bootImage The bootimage being written
845       * @param ptr  The object ref to the storage to be initialized
846       * @param tib  The TIB of the instance being created
847       * @param size The number of bytes allocated by the GC system for this object.
848       * @param needsIdentityHash needs an identity hash value
849       * @param identityHashValue the value for the identity hash
850       * @return the address used for a reference to this object
851       */
852      @Interruptible
853      public static Address initializeScalarHeader(BootImageInterface bootImage, Address ptr, TIB tib, int size, boolean needsIdentityHash, int identityHashValue) {
854        Address ref = ptr.plus(OBJECT_REF_OFFSET);
855        if (needsIdentityHash) {
856          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED_AND_MOVED.toInt());
857          if (DYNAMIC_HASH_OFFSET) {
858            // Read the size of this object.
859            RVMType t = tib.getType();
860            bootImage.setFullWord(ptr.plus(t.asClass().getInstanceSize()), identityHashValue);
861          } else {
862            ref = ref.plus(HASHCODE_BYTES);
863            bootImage.setFullWord(ref.plus(HASHCODE_OFFSET), (identityHashValue << 1) | ALIGNMENT_MASK);
864          }
865        } else {
866          // As boot image objects can't move there is no benefit in lazily setting them to hashed
867          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED.toInt());
868        }
869        return ref;
870      }
871    
872      /**
873       * Perform any required initialization of the JAVA portion of the header.
874       * @param ptr the raw storage to be initialized
875       * @param tib the TIB of the instance being created
876       * @param size the number of bytes allocated by the GC system for this object.
877       */
878      public static Object initializeArrayHeader(Address ptr, TIB tib, int size) {
879        Object ref = Magic.addressAsObject(ptr.plus(OBJECT_REF_OFFSET));
880        // (TIB and array length set by ObjectModel)
881        return ref;
882      }
883    
884      /**
885       * Perform any required initialization of the JAVA portion of the header.
886       *
887       * @param bootImage the bootimage being written
888       * @param ptr  the object ref to the storage to be initialized
889       * @param tib the TIB of the instance being created
890       * @param size the number of bytes allocated by the GC system for this object.
891       * @param numElements the number of elements in the array
892       * @return the address used for a reference to this object
893       */
894      @Interruptible
895      public static Address initializeArrayHeader(BootImageInterface bootImage, Address ptr, TIB tib, int size, int numElements, boolean needsIdentityHash, int identityHashValue) {
896        Address ref = ptr.plus(OBJECT_REF_OFFSET);
897        // (TIB set by BootImageWriter; array length set by ObjectModel)
898        if (needsIdentityHash) {
899          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED_AND_MOVED.toInt());
900          if (DYNAMIC_HASH_OFFSET) {
901            // Read the size of this object.
902            RVMType t = tib.getType();
903            bootImage.setFullWord(ptr.plus(t.asArray().getInstanceSize(numElements)), identityHashValue);
904          } else {
905            ref = ref.plus(HASHCODE_BYTES);
906            bootImage.setFullWord(ref.plus(HASHCODE_OFFSET), (identityHashValue << 1) | ALIGNMENT_MASK);
907          }
908        } else {
909          // As boot image objects can't move there is no benefit in lazily setting them to hashed
910          bootImage.setFullWord(ref.plus(STATUS_OFFSET), HASH_STATE_HASHED.toInt());
911        }
912        return ref;
913      }
914    
915      /**
916       * For low level debugging of GC subsystem.
917       * Dump the header word(s) of the given object reference.
918       * @param ref the object reference whose header should be dumped
919       */
920      public static void dumpHeader(Object ref) {
921        // TIB dumped in ObjectModel
922        VM.sysWrite(" STATUS=");
923        VM.sysWriteHex(Magic.getWordAtOffset(ref, STATUS_OFFSET).toAddress());
924      }
925    
926      /**
927       * The following method will emit code that moves a reference to an
928       * object's TIB into a destination register.
929       *
930       * @param asm the assembler object to emit code with
931       * @param dest the number of the destination register
932       * @param object the number of the register holding the object reference
933       */
934      @Interruptible
935      public static void baselineEmitLoadTIB(Assembler asm, int dest, int object) {
936        Configuration.archHelper.baselineEmitLoadTIB(asm, dest, object, TIB_OFFSET);
937      }
938    }