Skip to content

Commit 89d3f3d

Browse files
committed
8299125: UnifiedOopRef in JFR leakprofiler should treat thread local oops correctly
Reviewed-by: eosterlund, mgronlun
1 parent 4b57334 commit 89d3f3d

File tree

4 files changed

+104
-24
lines changed

4 files changed

+104
-24
lines changed

src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp

+31-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ template <typename Delegate>
4848
void RootSetClosure<Delegate>::do_oop(oop* ref) {
4949
assert(ref != NULL, "invariant");
5050
assert(is_aligned(ref, HeapWordSize), "invariant");
51-
if (*ref != NULL) {
51+
if (NativeAccess<>::oop_load(ref) != nullptr) {
5252
_delegate->do_root(UnifiedOopRef::encode_in_native(ref));
5353
}
5454
}
@@ -64,14 +64,42 @@ void RootSetClosure<Delegate>::do_oop(narrowOop* ref) {
6464

6565
class RootSetClosureMarkScope : public MarkScope {};
6666

67+
template <typename Delegate>
68+
class RawRootClosure : public OopClosure {
69+
Delegate* _delegate;
70+
71+
public:
72+
RawRootClosure(Delegate* delegate) : _delegate(delegate) {}
73+
74+
void do_oop(oop* ref) {
75+
assert(ref != NULL, "invariant");
76+
assert(is_aligned(ref, HeapWordSize), "invariant");
77+
if (*ref != nullptr) {
78+
_delegate->do_root(UnifiedOopRef::encode_as_raw(ref));
79+
}
80+
}
81+
82+
void do_oop(narrowOop* ref) {
83+
assert(ref != NULL, "invariant");
84+
assert(is_aligned(ref, HeapWordSize), "invariant");
85+
if (!CompressedOops::is_null(*ref)) {
86+
_delegate->do_root(UnifiedOopRef::encode_as_raw(ref));
87+
}
88+
}
89+
};
90+
6791
template <typename Delegate>
6892
void RootSetClosure<Delegate>::process() {
6993
RootSetClosureMarkScope mark_scope;
94+
7095
CLDToOopClosure cldt_closure(this, ClassLoaderData::_claim_none);
7196
ClassLoaderDataGraph::always_strong_cld_do(&cldt_closure);
72-
// We don't follow code blob oops, because they have misaligned oops.
73-
Threads::oops_do(this, NULL);
97+
7498
OopStorageSet::strong_oops_do(this);
99+
100+
// We don't follow code blob oops, because they have misaligned oops.
101+
RawRootClosure<Delegate> rrc(_delegate);
102+
Threads::oops_do(&rrc, NULL);
75103
}
76104

77105
template class RootSetClosure<BFSClosure>;

src/hotspot/share/jfr/leakprofiler/utilities/unifiedOopRef.hpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,33 @@
2929
#include "utilities/globalDefinitions.hpp"
3030

3131
struct UnifiedOopRef {
32+
static const uintptr_t tag_mask = LP64_ONLY(0b111) NOT_LP64(0b011);
33+
static const uintptr_t native_tag = 0b001;
34+
static const uintptr_t raw_tag = 0b010;
35+
static const uintptr_t narrow_tag = LP64_ONLY(0b100) NOT_LP64(0);
36+
STATIC_ASSERT((native_tag & raw_tag) == 0);
37+
STATIC_ASSERT((native_tag & narrow_tag) == 0);
38+
STATIC_ASSERT((raw_tag & narrow_tag) == 0);
39+
STATIC_ASSERT((native_tag | raw_tag | narrow_tag) == tag_mask);
40+
3241
uintptr_t _value;
3342

3443
template <typename T>
3544
T addr() const;
3645

3746
bool is_narrow() const;
3847
bool is_native() const;
48+
bool is_raw() const;
3949
bool is_null() const;
4050

4151
oop dereference() const;
4252

4353
static UnifiedOopRef encode_in_native(const narrowOop* ref);
4454
static UnifiedOopRef encode_in_native(const oop* ref);
45-
static UnifiedOopRef encode_in_heap(const oop* ref);
55+
static UnifiedOopRef encode_as_raw(const narrowOop* ref);
56+
static UnifiedOopRef encode_as_raw(const oop* ref);
4657
static UnifiedOopRef encode_in_heap(const narrowOop* ref);
58+
static UnifiedOopRef encode_in_heap(const oop* ref);
4759
static UnifiedOopRef encode_null();
4860
};
4961

src/hotspot/share/jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp

+52-20
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
template <typename T>
3434
inline T UnifiedOopRef::addr() const {
35-
return reinterpret_cast<T>(_value & ~uintptr_t(3));
35+
return reinterpret_cast<T>(UnifiedOopRef::addr<uintptr_t>());
3636
}
3737

3838
// Visual Studio 2019 and earlier have a problem with reinterpret_cast
@@ -42,47 +42,70 @@ inline T UnifiedOopRef::addr() const {
4242
// this specialization provides a workaround.
4343
template<>
4444
inline uintptr_t UnifiedOopRef::addr<uintptr_t>() const {
45-
return _value & ~uintptr_t(3);
45+
return (_value & ~tag_mask) LP64_ONLY(>> 1);
4646
}
4747

4848
inline bool UnifiedOopRef::is_narrow() const {
49-
return _value & 1;
49+
return (_value & narrow_tag) != 0;
5050
}
5151

5252
inline bool UnifiedOopRef::is_native() const {
53-
return _value & 2;
53+
return (_value & native_tag) != 0;
54+
}
55+
56+
inline bool UnifiedOopRef::is_raw() const {
57+
return (_value & raw_tag) != 0;
5458
}
5559

5660
inline bool UnifiedOopRef::is_null() const {
5761
return _value == 0;
5862
}
5963

60-
inline UnifiedOopRef UnifiedOopRef::encode_in_native(const narrowOop* ref) {
64+
template <typename T>
65+
inline UnifiedOopRef create_with_tag(T ref, uintptr_t tag) {
6166
assert(ref != NULL, "invariant");
62-
UnifiedOopRef result = { reinterpret_cast<uintptr_t>(ref) | 3 };
63-
assert(result.addr<narrowOop*>() == ref, "sanity");
67+
68+
uintptr_t value = reinterpret_cast<uintptr_t>(ref);
69+
70+
#ifdef _LP64
71+
// tag_mask is 3 bits. When ref is a narrowOop* we only have 2 alignment
72+
// bits, because of the 4 byte alignment of compressed oops addresses.
73+
// Shift up to make way for one more bit.
74+
assert((value & (1ull << 63)) == 0, "Unexpected high-order bit");
75+
value <<= 1;
76+
#endif
77+
assert((value & UnifiedOopRef::tag_mask) == 0, "Unexpected low-order bits");
78+
79+
UnifiedOopRef result = { value | tag };
80+
assert(result.addr<T>() == ref, "sanity");
6481
return result;
6582
}
6683

84+
inline UnifiedOopRef UnifiedOopRef::encode_in_native(const narrowOop* ref) {
85+
NOT_LP64(ShouldNotReachHere());
86+
return create_with_tag(ref, native_tag | narrow_tag);
87+
}
88+
6789
inline UnifiedOopRef UnifiedOopRef::encode_in_native(const oop* ref) {
68-
assert(ref != NULL, "invariant");
69-
UnifiedOopRef result = { reinterpret_cast<uintptr_t>(ref) | 2 };
70-
assert(result.addr<oop*>() == ref, "sanity");
71-
return result;
90+
return create_with_tag(ref, native_tag);
91+
}
92+
93+
inline UnifiedOopRef UnifiedOopRef::encode_as_raw(const narrowOop* ref) {
94+
NOT_LP64(ShouldNotReachHere());
95+
return create_with_tag(ref, raw_tag | narrow_tag);
96+
}
97+
98+
inline UnifiedOopRef UnifiedOopRef::encode_as_raw(const oop* ref) {
99+
return create_with_tag(ref, raw_tag);
72100
}
73101

74102
inline UnifiedOopRef UnifiedOopRef::encode_in_heap(const narrowOop* ref) {
75-
assert(ref != NULL, "invariant");
76-
UnifiedOopRef result = { reinterpret_cast<uintptr_t>(ref) | 1 };
77-
assert(result.addr<narrowOop*>() == ref, "sanity");
78-
return result;
103+
NOT_LP64(ShouldNotReachHere());
104+
return create_with_tag(ref, narrow_tag);
79105
}
80106

81107
inline UnifiedOopRef UnifiedOopRef::encode_in_heap(const oop* ref) {
82-
assert(ref != NULL, "invariant");
83-
UnifiedOopRef result = { reinterpret_cast<uintptr_t>(ref) | 0 };
84-
assert(result.addr<oop*>() == ref, "sanity");
85-
return result;
108+
return create_with_tag(ref, 0);
86109
}
87110

88111
inline UnifiedOopRef UnifiedOopRef::encode_null() {
@@ -91,14 +114,23 @@ inline UnifiedOopRef UnifiedOopRef::encode_null() {
91114
}
92115

93116
inline oop UnifiedOopRef::dereference() const {
94-
if (is_native()) {
117+
if (is_raw()) {
118+
if (is_narrow()) {
119+
NOT_LP64(ShouldNotReachHere());
120+
return RawAccess<>::oop_load(addr<narrowOop*>());
121+
} else {
122+
return *addr<oop*>();
123+
}
124+
} else if (is_native()) {
95125
if (is_narrow()) {
126+
NOT_LP64(ShouldNotReachHere());
96127
return NativeAccess<AS_NO_KEEPALIVE>::oop_load(addr<narrowOop*>());
97128
} else {
98129
return NativeAccess<AS_NO_KEEPALIVE>::oop_load(addr<oop*>());
99130
}
100131
} else {
101132
if (is_narrow()) {
133+
NOT_LP64(ShouldNotReachHere());
102134
return HeapAccess<AS_NO_KEEPALIVE>::oop_load(addr<narrowOop*>());
103135
} else {
104136
return HeapAccess<AS_NO_KEEPALIVE>::oop_load(addr<oop*>());

src/hotspot/share/oops/accessBackend.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,14 @@ namespace AccessInternal {
12531253
inline bool operator !=(const T& other) const {
12541254
return load<decorators | INTERNAL_VALUE_IS_OOP, P, T>(_addr) != other;
12551255
}
1256+
1257+
inline bool operator ==(std::nullptr_t) const {
1258+
return load<decorators | INTERNAL_VALUE_IS_OOP, P, oop>(_addr) == nullptr;
1259+
}
1260+
1261+
inline bool operator !=(std::nullptr_t) const {
1262+
return load<decorators | INTERNAL_VALUE_IS_OOP, P, oop>(_addr) != nullptr;
1263+
}
12561264
};
12571265

12581266
// Infer the type that should be returned from an Access::load_at.

0 commit comments

Comments
 (0)