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