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