Skip to content

Commit 7849f25

Browse files
committed
8340184: Bug in CompressedKlassPointers::is_in_encodable_range
Reviewed-by: coleenp, rkennke, jsjolen
1 parent a4cf191 commit 7849f25

File tree

10 files changed

+230
-27
lines changed

10 files changed

+230
-27
lines changed

src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,7 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {
129129
address const end = addr + len;
130130
_base = (end <= (address)unscaled_max) ? nullptr : addr;
131131

132-
_range = end - _base;
132+
// Remember the Klass range:
133+
_klass_range_start = addr;
134+
_klass_range_end = addr + len;
133135
}

src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5082,8 +5082,8 @@ MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode() {
50825082

50835083
if (operand_valid_for_logical_immediate(
50845084
/*is32*/false, (uint64_t)CompressedKlassPointers::base())) {
5085-
const uint64_t range_mask =
5086-
(1ULL << log2i(CompressedKlassPointers::range())) - 1;
5085+
const size_t range = CompressedKlassPointers::klass_range_end() - CompressedKlassPointers::base();
5086+
const uint64_t range_mask = (1ULL << log2i(range)) - 1;
50875087
if (((uint64_t)CompressedKlassPointers::base() & range_mask) == 0) {
50885088
return (_klass_decode_mode = KlassDecodeXor);
50895089
}

src/hotspot/share/ci/ciKlass.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class ciKlass : public ciType {
109109

110110
bool is_in_encoding_range() {
111111
Klass* k = get_Klass();
112-
bool is_in_encoding_range = CompressedKlassPointers::is_in_encoding_range(k);
112+
bool is_in_encoding_range = CompressedKlassPointers::is_encodable(k);
113113
assert(is_in_encoding_range || k->is_interface() || k->is_abstract(), "sanity");
114114
return is_in_encoding_range;
115115
}

src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ static size_t element_size(bool compressed) {
7575
}
7676

7777
static bool can_compress_element(const Klass* klass) {
78-
return CompressedKlassPointers::is_in_encoding_range(klass) &&
78+
return CompressedKlassPointers::is_encodable(klass) &&
7979
JfrTraceId::load_raw(klass) < uncompressed_threshold;
8080
}
8181

src/hotspot/share/oops/compressedKlass.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include "precompiled.hpp"
2626
#include "logging/log.hpp"
2727
#include "memory/metaspace.hpp"
28-
#include "oops/compressedKlass.hpp"
28+
#include "oops/compressedKlass.inline.hpp"
2929
#include "runtime/globals.hpp"
3030
#include "runtime/os.hpp"
3131
#include "utilities/debug.hpp"
@@ -34,7 +34,8 @@
3434

3535
address CompressedKlassPointers::_base = nullptr;
3636
int CompressedKlassPointers::_shift = 0;
37-
size_t CompressedKlassPointers::_range = 0;
37+
address CompressedKlassPointers::_klass_range_start = nullptr;
38+
address CompressedKlassPointers::_klass_range_end = nullptr;
3839

3940
#ifdef _LP64
4041

@@ -60,9 +61,12 @@ void CompressedKlassPointers::initialize_for_given_encoding(address addr, size_t
6061
assert(requested_base == addr, "Invalid requested base");
6162
assert(encoding_range_end >= end, "Encoding does not cover the full Klass range");
6263

64+
// Remember Klass range:
65+
_klass_range_start = addr;
66+
_klass_range_end = addr + len;
67+
6368
_base = requested_base;
6469
_shift = requested_shift;
65-
_range = encoding_range_size;
6670

6771
DEBUG_ONLY(assert_is_valid_encoding(addr, len, _base, _shift);)
6872
}
@@ -87,6 +91,11 @@ char* CompressedKlassPointers::reserve_address_space_for_16bit_move(size_t size,
8791
#if !defined(AARCH64) || defined(ZERO)
8892
// On aarch64 we have an own version; all other platforms use the default version
8993
void CompressedKlassPointers::initialize(address addr, size_t len) {
94+
95+
// Remember the Klass range:
96+
_klass_range_start = addr;
97+
_klass_range_end = addr + len;
98+
9099
// The default version of this code tries, in order of preference:
91100
// -unscaled (base=0 shift=0)
92101
// -zero-based (base=0 shift>0)
@@ -111,16 +120,20 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {
111120
_shift = 0;
112121
}
113122
}
114-
_range = end - _base;
115123

116124
DEBUG_ONLY(assert_is_valid_encoding(addr, len, _base, _shift);)
117125
}
118126
#endif // !AARCH64 || ZERO
119127

120128
void CompressedKlassPointers::print_mode(outputStream* st) {
121-
st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d, "
122-
"Narrow klass range: " SIZE_FORMAT_X, p2i(base()), shift(),
123-
range());
129+
if (UseCompressedClassPointers) {
130+
st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d",
131+
p2i(base()), shift());
132+
st->print_cr("Encoding Range: " RANGE2FMT, RANGE2FMTARGS(_base, encoding_range_end()));
133+
st->print_cr("Klass Range: " RANGE2FMT, RANGE2FMTARGS(_klass_range_start, _klass_range_end));
134+
} else {
135+
st->print_cr("UseCompressedClassPointers off");
136+
}
124137
}
125138

126139
#endif // _LP64

src/hotspot/share/oops/compressedKlass.hpp

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,69 @@
3131
class outputStream;
3232
class Klass;
3333

34+
// Narrow Klass Encoding
35+
//
36+
// Klass Range:
37+
// a contiguous memory range into which we place Klass that should be encodable. Not every Klass
38+
// needs to be encodable. There is only one such memory range.
39+
// If CDS is disabled, this Klass Range is the same as the metaspace class space. If CDS is enabled, the
40+
// Klass Range contains both CDS and class space adjacent to each other (with a potential small
41+
// unused alignment gap between them).
42+
//
43+
// Encoding Range:
44+
// This is the range covered by the current encoding scheme. The encoding scheme is defined by
45+
// the encoding base, encoding shift and (implicitly) the bit size of the narrowKlass. The
46+
// Encoding Range is:
47+
// [ <encoding base> ... <encoding base> + (1 << (<narrowKlass-bitsize> + <shift>) )
48+
//
49+
// Note that while the Klass Range must be contained within the Encoding Range, the Encoding Range
50+
// is typically a lot larger than the Klass Range:
51+
// - the encoding base can start before the Klass Range start (specifically, it can start at 0 for
52+
// zero-based encoding)
53+
// - the end of the Encoding Range usually extends far beyond the end of the Klass Range.
54+
//
55+
//
56+
// Examples:
57+
//
58+
// "unscaled" (zero-based zero-shift) encoding, CDS off, class space of 1G starts at 0x4B00_0000:
59+
// - Encoding Range: [0 .. 0x1_0000_0000 ) (4 GB)
60+
// - Klass Range: [0x4B00_0000 .. 0x 8B00_0000 ) (1 GB)
61+
//
62+
//
63+
// _base _klass_range_start _klass_range_end encoding end
64+
// | |//////////////////////////////| |
65+
// | ... |///////1gb class space////////| ... |
66+
// | |//////////////////////////////| |
67+
// 0x0 0x4B00_0000 0x8B00_0000 0x1_0000_0000
68+
//
69+
//
70+
//
71+
// "zero-based" (but scaled) encoding, shift=3, CDS off, 1G Class space at 0x7_C000_0000 (31GB):
72+
// - Encoding Range: [0 .. 0x8_0000_0000 ) (32 GB)
73+
// - Klass Range: [0x7_C000_0000 .. 0x8_0000_0000 ) (1 GB)
74+
//
75+
// encoding end
76+
// _base _klass_range_start _klass_range_end
77+
// | |//////////////////////////////|
78+
// | ... |///////1gb class space////////|
79+
// | |//////////////////////////////|
80+
// 0x0 0x7_C000_0000 0x8_0000_0000
81+
//
82+
//
83+
// CDS enabled, 128MB CDS region starts 0x8_0000_0000, followed by a 1GB class space. Encoding
84+
// base will point to CDS region start, shift=0:
85+
// - Encoding Range: [0x8_0000_0000 .. 0x9_0000_0000 ) (4 GB)
86+
// - Klass Range: [0x8_0000_0000 .. 0x8_4800_0000 ) (128 MB + 1 GB)
87+
//
88+
// _base
89+
// _klass_range_start _klass_range_end encoding end
90+
// |//////////|///////////////////////////| |
91+
// |///CDS////|////1gb class space////////| ... ... |
92+
// |//////////|///////////////////////////| |
93+
// | | |
94+
// 0x8_0000_0000 0x8_4800_0000 0x9_0000_0000
95+
//
96+
3497
// If compressed klass pointers then use narrowKlass.
3598
typedef juint narrowKlass;
3699

@@ -50,12 +113,10 @@ class CompressedKlassPointers : public AllStatic {
50113
static address _base;
51114
static int _shift;
52115

53-
// Together with base, this defines the address range within which Klass
54-
// structures will be located: [base, base+range). While the maximal
55-
// possible encoding range is 4|32G for shift 0|3, if we know beforehand
56-
// the expected range of Klass* pointers will be smaller, a platform
57-
// could use this info to optimize encoding.
58-
static size_t _range;
116+
// Start and end of the Klass Range.
117+
// Note: guaranteed to be aligned to KlassAlignmentInBytes
118+
static address _klass_range_start;
119+
static address _klass_range_end;
59120

60121
// Helper function for common cases.
61122
static char* reserve_address_space_X(uintptr_t from, uintptr_t to, size_t size, size_t alignment, bool aslr);
@@ -92,9 +153,13 @@ class CompressedKlassPointers : public AllStatic {
92153
static void print_mode(outputStream* st);
93154

94155
static address base() { return _base; }
95-
static size_t range() { return _range; }
96156
static int shift() { return _shift; }
97157

158+
static address klass_range_start() { return _klass_range_start; }
159+
static address klass_range_end() { return _klass_range_end; }
160+
161+
static inline address encoding_range_end();
162+
98163
static bool is_null(Klass* v) { return v == nullptr; }
99164
static bool is_null(narrowKlass v) { return v == 0; }
100165

@@ -110,14 +175,9 @@ class CompressedKlassPointers : public AllStatic {
110175

111176
// Returns whether the pointer is in the memory region used for encoding compressed
112177
// class pointers. This includes CDS.
113-
114-
// encoding encoding
115-
// base end (base+range)
116-
// |-----------------------------------------------------------------------|
117-
// |----CDS---| |--------------------class space---------------------------|
118-
119-
static inline bool is_in_encoding_range(const void* p) {
120-
return p >= _base && p < (_base + _range);
178+
static inline bool is_encodable(const void* p) {
179+
return (address) p >= _klass_range_start &&
180+
(address) p < _klass_range_end;
121181
}
122182
};
123183

src/hotspot/share/oops/compressedKlass.inline.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,9 @@ inline narrowKlass CompressedKlassPointers::encode(Klass* v) {
8282
return is_null(v) ? (narrowKlass)0 : encode_not_null(v);
8383
}
8484

85+
inline address CompressedKlassPointers::encoding_range_end() {
86+
const int max_bits = (sizeof(narrowKlass) * BitsPerByte) + _shift; // narrowKlass are 32 bit
87+
return _base + nth_bit(max_bits);
88+
}
89+
8590
#endif // SHARE_OOPS_COMPRESSEDKLASS_INLINE_HPP

src/hotspot/share/utilities/globalDefinitions.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,14 @@ inline T byte_size_in_proper_unit(T s) {
384384
#define PROPERFMT SIZE_FORMAT "%s"
385385
#define PROPERFMTARGS(s) byte_size_in_proper_unit(s), proper_unit_for_byte_size(s)
386386

387+
// Printing a range, with start and bytes given
387388
#define RANGEFMT "[" PTR_FORMAT " - " PTR_FORMAT "), (" SIZE_FORMAT " bytes)"
388389
#define RANGEFMTARGS(p1, size) p2i(p1), p2i(p1 + size), size
389390

391+
// Printing a range, with start and end given
392+
#define RANGE2FMT "[" PTR_FORMAT " - " PTR_FORMAT "), (" SIZE_FORMAT " bytes)"
393+
#define RANGE2FMTARGS(p1, p2) p2i(p1), p2i(p2), ((uintptr_t)p2 - (uintptr_t)p1)
394+
390395
inline const char* exact_unit_for_byte_size(size_t s) {
391396
#ifdef _LP64
392397
if (s >= G && (s % G) == 0) {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2024, Red Hat, Inc. All rights reserved.
3+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*/
24+
25+
#include "precompiled.hpp"
26+
#include "oops/compressedKlass.inline.hpp"
27+
#include "utilities/globalDefinitions.hpp"
28+
29+
#include "unittest.hpp"
30+
31+
TEST_VM(CompressedKlass, basics) {
32+
if (!UseCompressedClassPointers) {
33+
return;
34+
}
35+
ASSERT_LE((address)0, CompressedKlassPointers::base());
36+
ASSERT_LE(CompressedKlassPointers::base(), CompressedKlassPointers::klass_range_start());
37+
ASSERT_LT(CompressedKlassPointers::klass_range_start(), CompressedKlassPointers::klass_range_end());
38+
ASSERT_LE(CompressedKlassPointers::klass_range_end(), CompressedKlassPointers::encoding_range_end());
39+
switch (CompressedKlassPointers::shift()) {
40+
case 0:
41+
ASSERT_EQ(CompressedKlassPointers::encoding_range_end() - CompressedKlassPointers::base(), (ptrdiff_t)(4 * G));
42+
break;
43+
case 3:
44+
ASSERT_EQ(CompressedKlassPointers::encoding_range_end() - CompressedKlassPointers::base(), (ptrdiff_t)(32 * G));
45+
break;
46+
default:
47+
ShouldNotReachHere();
48+
}
49+
}
50+
51+
TEST_VM(CompressedKlass, test_too_low_address) {
52+
if (!UseCompressedClassPointers) {
53+
return;
54+
}
55+
address really_low = (address) 32;
56+
ASSERT_FALSE(CompressedKlassPointers::is_encodable(really_low));
57+
address low = CompressedKlassPointers::klass_range_start() - 1;
58+
ASSERT_FALSE(CompressedKlassPointers::is_encodable(low));
59+
}
60+
61+
TEST_VM(CompressedKlass, test_too_high_address) {
62+
if (!UseCompressedClassPointers) {
63+
return;
64+
}
65+
address really_high = (address) UINTPTR_MAX;
66+
ASSERT_FALSE(CompressedKlassPointers::is_encodable(really_high));
67+
address high = CompressedKlassPointers::klass_range_end();
68+
ASSERT_FALSE(CompressedKlassPointers::is_encodable(high));
69+
}
70+
71+
TEST_VM(CompressedKlass, test_good_address) {
72+
if (!UseCompressedClassPointers) {
73+
return;
74+
}
75+
address addr = CompressedKlassPointers::klass_range_start();
76+
ASSERT_TRUE(CompressedKlassPointers::is_encodable(addr));
77+
addr = CompressedKlassPointers::klass_range_end() - 1;
78+
ASSERT_TRUE(CompressedKlassPointers::is_encodable(addr));
79+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2024, Red Hat, Inc. All rights reserved.
3+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*
24+
*/
25+
26+
/*
27+
* This runs the "compressedKlass" class of gtests.
28+
* Note: we try to trigger bugs by enforcing the JVM to use zero-based mode. To increase the chance of zero-based
29+
* mode, we start with CDS disabled, a small class space and a large (albeit uncommitted, to save memory) heap. The
30+
* JVM will likely place the class space in low-address territory.
31+
* (If it does not manage to do this, the test will still succeed, but it won't alert us on regressions)
32+
*/
33+
34+
/* @test id=use-zero-based-encoding
35+
* @library /test/lib
36+
* @modules java.base/jdk.internal.misc
37+
* java.xml
38+
* @run main/native GTestWrapper --gtest_filter=CompressedKlass* -Xlog:metaspace* -Xmx6g -Xms128m -Xshare:off -XX:CompressedClassSpaceSize=128m
39+
*/

0 commit comments

Comments
 (0)