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 }