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}