Skip to content

Commit cccb501

Browse files
Arrayingcoleenp
authored andcommitted
8367073: [lworld] Conform to JEP 450 encoding of mark word
Reviewed-by: coleenp, fparain, thartmann
1 parent c42a95f commit cccb501

File tree

3 files changed

+24
-90
lines changed

3 files changed

+24
-90
lines changed

src/hotspot/share/oops/markWord.hpp

Lines changed: 20 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@
4444
//
4545
// 64 bits:
4646
// --------
47-
// unused:22 hash:31 -->| unused_gap:4 age:4 self-fwd:1 lock:2 (normal object)
47+
// unused:22 hash:31 -->| valhalla:4 age:4 self-fwd:1 lock:2 (normal object)
4848
//
4949
// 64 bits (with compact headers):
5050
// -------------------------------
51-
// klass:22 hash:31 -->| unused_gap:4 age:4 self-fwd:1 lock:2 (normal object)
51+
// klass:22 hash:31 -->| valhalla:4 age:4 self-fwd:1 lock:2 (normal object)
5252
//
5353
// - hash contains the identity hash value: largest value is
5454
// 31 bits, see os::random(). Also, 64-bit vm's require
@@ -72,76 +72,23 @@
7272
// used when inflating an existing stack-lock into an ObjectMonitor.
7373
// See below for is_being_inflated() and INFLATING().
7474
//
75+
// VALHALLA EXTENSIONS:
7576
//
77+
// N.B.: 32 bit mode is not supported, this section assumes 64 bit systems.
7678
//
77-
// Valhalla
78-
//
79-
// <CMH: merge this doc into the text above>
80-
//
81-
// Project Valhalla has mark word encoding requirements for the following oops:
82-
//
79+
// Project Valhalla uses markWord bits to denote the following oops (listed least to most significant):
8380
// * inline types: have alternative bytecode behavior, e.g. can not be locked
84-
// - "larval state": mutable state, but only during object init, observable
85-
// by only by a single thread (generally do not mutate markWord)
86-
//
8781
// * flat arrays: load/decode of klass layout helper is expensive for aaload
88-
//
8982
// * "null free" arrays: load/decode of klass layout helper again for aaload
83+
// * inline type: "larval state": mutable state, but only during object init, observable
84+
// by only by a single thread (generally do not mutate markWord)
9085
//
91-
// EnableValhalla
92-
//
93-
// Formerly known as "biased lock bit", "unused_gap" is free to use: using this
94-
// bit to indicate inline type, combined with "unlocked" lock bits, means we
95-
// will not interfere with lock encodings (displaced, inflating, and monitor),
96-
// since inline types can't be locked.
97-
//
98-
// Further state encoding
99-
//
100-
// 32 bit plaforms currently have no further room for encoding. No room for
101-
// "denormalized layout helper bits", these fast mark word tests can only be made on
102-
// 64 bit platforms. 32-bit platforms need to load the klass->_layout_helper. This
103-
// said, the larval state bit is still required for operation, stealing from the hash
104-
// code is simplest mechanism.
105-
//
106-
// Valhalla specific encodings
107-
//
108-
// Revised Bit-format of an object header (most significant first, big endian layout below):
109-
//
110-
// 32 bits:
111-
// --------
112-
// hash:24 ------------>| larval:1 age:4 inline_type:1 lock:2
113-
//
114-
// 64 bits:
115-
// --------
116-
// unused:1 | <-- hash:31 -->| unused:22 larval:1 age:4 flat_array:1 null_free_array:1 inline_type:1 lock:2
117-
// klass:22 hash:31 -->| larval:1 age:4 flat_array:1 null_free_array:1 inline_type:1 self-fwd:1 lock:2 (normal object)
118-
//
119-
// The "fast" static type bits (flat_array, null_free_array, and inline_type)
120-
// are placed lowest next to lock bits to more easily decode forwarding pointers.
121-
// G1 for example, implicitly clears age bits ("G1FullGCCompactionPoint::forward()")
122-
// using "oopDesc->forwardee()", so it necessary for "markWord::decode_pointer()"
123-
// to return a non-nullptr for this case, but not confuse the static type bits for
124-
// a pointer.
86+
// Inline types cannot be locked, monitored or inflating.
12587
//
12688
// Note the position of 'self-fwd' is not by accident. When forwarding an
12789
// object to a new heap position, HeapWord alignment guarantees the lower
12890
// bits, including 'self-fwd' are 0. "is_self_forwarded()" will be correctly
12991
// set to false. Otherwise encode_pointer_as_mark() may have 'self-fwd' set.
130-
//
131-
//
132-
// Static types bits are recorded in the "klass->prototype_header()", displaced
133-
// mark should simply use the prototype header as "slow path", rather chasing
134-
// monitor or stack lock races.
135-
//
136-
// Lock patterns (note inline types can't be locked/monitor/inflating)...
137-
//
138-
// [ptr | 000] locked ptr points to real header on stack
139-
// [header | ?01] unlocked regular object header
140-
// [ptr | 010] monitor inflated lock (header is wapped out)
141-
// [ptr | ?11] marked used to mark an object
142-
// [0 ............ | 000] inflating inflation in progress
143-
//
144-
//
14592

14693
class BasicLock;
14794
class ObjectMonitor;
@@ -183,44 +130,43 @@ class markWord {
183130
// Constants, in least significant bit order
184131
static const int lock_bits = 2;
185132
static const int self_fwd_bits = 1;
133+
// instance state
134+
static const int age_bits = 4;
186135
// EnableValhalla: static prototype header bits (fast path instead of klass layout_helper)
187136
static const int inline_type_bits = 1;
188137
static const int null_free_array_bits = LP64_ONLY(1) NOT_LP64(0);
189138
static const int flat_array_bits = LP64_ONLY(1) NOT_LP64(0);
190-
// instance state
191-
static const int age_bits = 4;
192139
static const int larval_bits = 1;
193140
static const int max_hash_bits = BitsPerWord - age_bits - lock_bits - inline_type_bits - larval_bits - flat_array_bits - null_free_array_bits - self_fwd_bits;
194141
static const int hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits;
195142

196143
static const int lock_shift = 0;
197-
static const int self_fwd_shift = lock_bits ;
198-
static const int inline_type_shift = self_fwd_shift + self_fwd_bits;
144+
static const int self_fwd_shift = lock_shift + lock_bits;
145+
static const int age_shift = self_fwd_shift + self_fwd_bits;
146+
static const int inline_type_shift = age_shift + age_bits;
199147
static const int null_free_array_shift = inline_type_shift + inline_type_bits;
200148
static const int flat_array_shift = null_free_array_shift + null_free_array_bits;
201-
static const int age_shift = flat_array_shift + flat_array_bits;
202-
static const int larval_shift = age_shift + age_bits;
149+
static const int larval_shift = flat_array_shift + flat_array_bits;
203150
static const int hash_shift = larval_shift + larval_bits;
204151

205152
static const uintptr_t lock_mask = right_n_bits(lock_bits);
206153
static const uintptr_t lock_mask_in_place = lock_mask << lock_shift;
207154
static const uintptr_t self_fwd_mask = right_n_bits(self_fwd_bits);
208155
static const uintptr_t self_fwd_mask_in_place = self_fwd_mask << self_fwd_shift;
209-
static const uintptr_t inline_type_bit_in_place = 1 << inline_type_shift;
210-
static const uintptr_t inline_type_mask = inline_type_bit_in_place + lock_mask;
211-
static const uintptr_t inline_type_mask_in_place = inline_type_mask << lock_shift;
156+
static const uintptr_t inline_type_bit_in_place = right_n_bits(inline_type_bits) << inline_type_shift;
157+
static const uintptr_t inline_type_mask_in_place = inline_type_bit_in_place + lock_mask;
212158
static const uintptr_t null_free_array_mask = right_n_bits(null_free_array_bits);
213159
static const uintptr_t null_free_array_mask_in_place = (null_free_array_mask << null_free_array_shift) | lock_mask_in_place;
214-
static const uintptr_t null_free_array_bit_in_place = (1 << null_free_array_shift);
160+
static const uintptr_t null_free_array_bit_in_place = (right_n_bits(null_free_array_bits) << null_free_array_shift);
215161
static const uintptr_t flat_array_mask = right_n_bits(flat_array_bits);
216162
static const uintptr_t flat_array_mask_in_place = (flat_array_mask << flat_array_shift) | null_free_array_mask_in_place | lock_mask_in_place;
217-
static const uintptr_t flat_array_bit_in_place = (1 << flat_array_shift);
163+
static const uintptr_t flat_array_bit_in_place = right_n_bits(flat_array_bits) << flat_array_shift;
218164
static const uintptr_t age_mask = right_n_bits(age_bits);
219165
static const uintptr_t age_mask_in_place = age_mask << age_shift;
220166

221167
static const uintptr_t larval_mask = right_n_bits(larval_bits);
222168
static const uintptr_t larval_mask_in_place = (larval_mask << larval_shift) | inline_type_mask_in_place;
223-
static const uintptr_t larval_bit_in_place = (1 << larval_shift);
169+
static const uintptr_t larval_bit_in_place = right_n_bits(larval_bits) << larval_shift;
224170

225171
static const uintptr_t hash_mask = right_n_bits(hash_bits);
226172
static const uintptr_t hash_mask_in_place = hash_mask << hash_shift;
@@ -249,11 +195,6 @@ class markWord {
249195
static const uintptr_t null_free_flat_array_pattern = flat_array_bit_in_place | null_free_array_pattern;
250196
static const uintptr_t nullable_flat_array_pattern = flat_array_bit_in_place | unlocked_value;
251197

252-
// Has static klass prototype, used for decode/encode pointer
253-
static const uintptr_t static_prototype_mask = LP64_ONLY(right_n_bits(inline_type_bits + flat_array_bits + null_free_array_bits)) NOT_LP64(right_n_bits(inline_type_bits));
254-
static const uintptr_t static_prototype_mask_in_place = static_prototype_mask << lock_bits;
255-
static const uintptr_t static_prototype_value_max = (1 << age_shift) - 1;
256-
257198
static const uintptr_t larval_pattern = larval_bit_in_place | inline_type_pattern;
258199

259200
static const uintptr_t no_hash = 0 ; // no hash value assigned
@@ -445,10 +386,8 @@ class markWord {
445386
// Prepare address of oop for placement into mark
446387
inline static markWord encode_pointer_as_mark(void* p) { return from_pointer(p).set_marked(); }
447388

448-
// Recover address of oop from encoded form used in mark
449389
inline void* decode_pointer() const {
450-
return (EnableValhalla && _value < static_prototype_value_max) ? nullptr :
451-
(void*) (clear_lock_bits().value());
390+
return (void*) (clear_lock_bits().value());
452391
}
453392

454393
inline bool is_self_forwarded() const {

src/hotspot/share/opto/library_call.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5323,7 +5323,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) {
53235323
Node* obj = argument(0);
53245324

53255325
// Don't intrinsify hashcode on inline types for now.
5326-
// The "is locked" runtime check below also serves as inline type check and goes to the slow path.
5326+
// The "is locked" runtime check also subsumes the inline type check (as inline types cannot be locked) and goes to the slow path.
53275327
if (gvn().type(obj)->is_inlinetypeptr()) {
53285328
return false;
53295329
}
@@ -5377,8 +5377,9 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) {
53775377

53785378
if (!UseObjectMonitorTable) {
53795379
// Test the header to see if it is safe to read w.r.t. locking.
5380-
// This also serves as guard against inline types
5381-
Node *lock_mask = _gvn.MakeConX(markWord::inline_type_mask_in_place);
5380+
// We cannot use the inline type mask as this may check bits that are overriden
5381+
// by an object monitor's pointer when inflating locking.
5382+
Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place);
53825383
Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask));
53835384
Node *monitor_val = _gvn.MakeConX(markWord::monitor_value);
53845385
Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val));

test/hotspot/gtest/oops/test_markWord.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ TEST_VM(markWord, prototype) {
147147

148148
EXPECT_TRUE(mark.has_no_hash());
149149
EXPECT_FALSE(mark.is_marked());
150-
EXPECT_TRUE(mark.decode_pointer() == nullptr);
151150

152151
assert_copy_set_hash(mark);
153152
assert_type(mark);
@@ -170,7 +169,6 @@ TEST_VM(markWord, inline_type_prototype) {
170169

171170
EXPECT_TRUE(mark.has_no_hash());
172171
EXPECT_FALSE(mark.is_marked());
173-
EXPECT_TRUE(mark.decode_pointer() == nullptr);
174172

175173
markWord larval = mark.enter_larval_state();
176174
EXPECT_TRUE(larval.is_larval_state());
@@ -183,7 +181,6 @@ TEST_VM(markWord, inline_type_prototype) {
183181

184182
EXPECT_TRUE(mark.has_no_hash());
185183
EXPECT_FALSE(mark.is_marked());
186-
EXPECT_TRUE(mark.decode_pointer() == nullptr);
187184
}
188185

189186
#if _LP64
@@ -204,7 +201,6 @@ TEST_VM(markWord, null_free_flat_array_prototype) {
204201

205202
EXPECT_TRUE(mark.has_no_hash());
206203
EXPECT_FALSE(mark.is_marked());
207-
EXPECT_TRUE(mark.decode_pointer() == nullptr);
208204

209205
assert_copy_set_hash(mark);
210206
assert_flat_array_type(mark);
@@ -223,7 +219,6 @@ TEST_VM(markWord, nullable_flat_array_prototype) {
223219

224220
EXPECT_TRUE(mark.has_no_hash());
225221
EXPECT_FALSE(mark.is_marked());
226-
EXPECT_TRUE(mark.decode_pointer() == nullptr);
227222

228223
assert_copy_set_hash(mark);
229224
assert_flat_array_type(mark);
@@ -248,7 +243,6 @@ TEST_VM(markWord, null_free_array_prototype) {
248243

249244
EXPECT_TRUE(mark.has_no_hash());
250245
EXPECT_FALSE(mark.is_marked());
251-
EXPECT_TRUE(mark.decode_pointer() == nullptr);
252246

253247
assert_copy_set_hash(mark);
254248
assert_null_free_array_type(mark);

0 commit comments

Comments
 (0)