Mon, 17 May 2010 00:47:28 -0700
6948539: CMS+UseCompressedOops: placement of cms_free bit interferes with promoted object link
Summary: When using compressed oops, use compressed promoted pointers in b63:b31 of the mark word, so as not to interfere with the CMS "freeness bit" at b7. Updated mark-word layout documentation.
Reviewed-by: minqi, poonam, jmasa, coleenp
1.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Fri May 14 10:28:46 2010 -0700 1.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.cpp Mon May 17 00:47:28 2010 -0700 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it
2.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.hpp Fri May 14 10:28:46 2010 -0700 2.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/promotionInfo.hpp Mon May 17 00:47:28 2010 -0700 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved. 2.6 + * Copyright 2010 Sun Microsystems, Inc. All Rights Reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -32,30 +32,75 @@ 2.11 displaced_mark = nth_bit(2), // i.e. 0x4 2.12 next_mask = ~(right_n_bits(3)) // i.e. ~(0x7) 2.13 }; 2.14 - intptr_t _next; 2.15 + 2.16 + // Below, we want _narrow_next in the "higher" 32 bit slot, 2.17 + // whose position will depend on endian-ness of the platform. 2.18 + // This is so that there is no interference with the 2.19 + // cms_free_bit occupying bit position 7 (lsb == 0) 2.20 + // when we are using compressed oops; see FreeChunk::isFree(). 2.21 + // We cannot move the cms_free_bit down because currently 2.22 + // biased locking code assumes that age bits are contiguous 2.23 + // with the lock bits. Even if that assumption were relaxed, 2.24 + // the least position we could move this bit to would be 2.25 + // to bit position 3, which would require 16 byte alignment. 2.26 + typedef struct { 2.27 +#ifdef VM_LITTLE_ENDIAN 2.28 + LP64_ONLY(narrowOop _pad;) 2.29 + narrowOop _narrow_next; 2.30 +#else 2.31 + narrowOop _narrow_next; 2.32 + LP64_ONLY(narrowOop _pad;) 2.33 +#endif 2.34 + } Data; 2.35 + 2.36 + union { 2.37 + intptr_t _next; 2.38 + Data _data; 2.39 + }; 2.40 public: 2.41 inline PromotedObject* next() const { 2.42 - return (PromotedObject*)(_next & next_mask); 2.43 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.44 + PromotedObject* res; 2.45 + if (UseCompressedOops) { 2.46 + // The next pointer is a compressed oop stored in the top 32 bits 2.47 + res = (PromotedObject*)oopDesc::decode_heap_oop(_data._narrow_next); 2.48 + } else { 2.49 + res = (PromotedObject*)(_next & next_mask); 2.50 + } 2.51 + assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Not an oop?"); 2.52 + return res; 2.53 } 2.54 inline void setNext(PromotedObject* x) { 2.55 - assert(((intptr_t)x & ~next_mask) == 0, 2.56 - "Conflict in bit usage, " 2.57 - " or insufficient alignment of objects"); 2.58 - _next |= (intptr_t)x; 2.59 + assert(((intptr_t)x & ~next_mask) == 0, "Conflict in bit usage, " 2.60 + "or insufficient alignment of objects"); 2.61 + if (UseCompressedOops) { 2.62 + assert(_data._narrow_next == 0, "Overwrite?"); 2.63 + _data._narrow_next = oopDesc::encode_heap_oop(oop(x)); 2.64 + } else { 2.65 + _next |= (intptr_t)x; 2.66 + } 2.67 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.68 } 2.69 inline void setPromotedMark() { 2.70 _next |= promoted_mask; 2.71 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.72 } 2.73 inline bool hasPromotedMark() const { 2.74 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.75 return (_next & promoted_mask) == promoted_mask; 2.76 } 2.77 inline void setDisplacedMark() { 2.78 _next |= displaced_mark; 2.79 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.80 } 2.81 inline bool hasDisplacedMark() const { 2.82 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.83 return (_next & displaced_mark) != 0; 2.84 } 2.85 - inline void clearNext() { _next = 0; } 2.86 + inline void clearNext() { 2.87 + _next = 0; 2.88 + assert(!((FreeChunk*)this)->isFree(), "Error"); 2.89 + } 2.90 debug_only(void *next_addr() { return (void *) &_next; }) 2.91 }; 2.92
3.1 --- a/src/share/vm/oops/markOop.hpp Fri May 14 10:28:46 2010 -0700 3.2 +++ b/src/share/vm/oops/markOop.hpp Mon May 17 00:47:28 2010 -0700 3.3 @@ -27,12 +27,26 @@ 3.4 // Note that the mark is not a real oop but just a word. 3.5 // It is placed in the oop hierarchy for historical reasons. 3.6 // 3.7 -// Bit-format of an object header (most significant first): 3.8 +// Bit-format of an object header (most significant first, big endian layout below): 3.9 // 3.10 -// 32 bits: unused:0 hash:25 age:4 biased_lock:1 lock:2 3.11 -// 64 bits: unused:24 hash:31 cms:2 age:4 biased_lock:1 lock:2 3.12 -// unused:20 size:35 cms:2 age:4 biased_lock:1 lock:2 (if cms 3.13 -// free chunk) 3.14 +// 32 bits: 3.15 +// -------- 3.16 +// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) 3.17 +// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) 3.18 +// size:32 ------------------------------------------>| (CMS free block) 3.19 +// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object) 3.20 +// 3.21 +// 64 bits: 3.22 +// -------- 3.23 +// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object) 3.24 +// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object) 3.25 +// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object) 3.26 +// size:64 ----------------------------------------------------->| (CMS free block) 3.27 +// 3.28 +// unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object) 3.29 +// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object) 3.30 +// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object) 3.31 +// unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block) 3.32 // 3.33 // - hash contains the identity hash value: largest value is 3.34 // 31 bits, see os::random(). Also, 64-bit vm's require 3.35 @@ -61,8 +75,9 @@ 3.36 // significant fraction of the eden semispaces and were not 3.37 // promoted promptly, causing an increase in the amount of copying 3.38 // performed. The runtime system aligns all JavaThread* pointers to 3.39 -// a very large value (currently 128 bytes) to make room for the 3.40 -// age bits when biased locking is enabled. 3.41 +// a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM)) 3.42 +// to make room for the age bits & the epoch bits (used in support of 3.43 +// biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs). 3.44 // 3.45 // [JavaThread* | epoch | age | 1 | 01] lock is biased toward given thread 3.46 // [0 | epoch | age | 1 | 01] lock is anonymously biased