Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for smaller-than-22-bit class pointers #172

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions src/hotspot/share/memory/metaspace.cpp
Original file line number Diff line number Diff line change
@@ -651,23 +651,44 @@ void Metaspace::ergo_initialize() {
MaxMetaspaceSize = MAX2(MaxMetaspaceSize, commit_alignment());

if (UseCompressedClassPointers) {
// Adjust size of the compressed class space.

const size_t res_align = reserve_alignment();

// Let CCS size not be larger than 80% of MaxMetaspaceSize. Note that is
// grossly over-dimensioned for most usage scenarios; typical ratio of
// class space : non class space usage is about 1:6. With many small classes,
// it can get as low as 1:2. It is not a big deal though since ccs is only
// reserved and will be committed on demand only.
size_t max_ccs_size = 8 * (MaxMetaspaceSize / 10);
size_t adjusted_ccs_size = MIN2(CompressedClassSpaceSize, max_ccs_size);
const size_t max_ccs_size = 8 * (MaxMetaspaceSize / 10);

// CCS is also limited by the max. possible Klass encoding range size
const size_t max_encoding_range = CompressedKlassPointers::max_encoding_range_size();
assert(max_encoding_range >= res_align,
"Encoding range (%zu) must cover at least a full root chunk (%zu)",
max_encoding_range, res_align);

size_t adjusted_ccs_size = MIN3(CompressedClassSpaceSize, max_ccs_size, max_encoding_range);

// CCS must be aligned to root chunk size, and be at least the size of one
// root chunk.
adjusted_ccs_size = align_up(adjusted_ccs_size, reserve_alignment());
adjusted_ccs_size = MAX2(adjusted_ccs_size, reserve_alignment());
// root chunk. But impose a miminum size of 1 root chunk (16MB).
adjusted_ccs_size = MAX2(align_down(adjusted_ccs_size, res_align), res_align);

// Print a warning if the adjusted size differs from the users input
if (CompressedClassSpaceSize != adjusted_ccs_size) {
#define X "CompressedClassSpaceSize adjusted from user input " \
"%zu bytes to %zu bytes", CompressedClassSpaceSize, adjusted_ccs_size
if (FLAG_IS_CMDLINE(CompressedClassSpaceSize)) {
log_warning(metaspace)(X);
} else {
log_info(metaspace)(X);
}
#undef X
}

// Note: re-adjusting may have us left with a CompressedClassSpaceSize
// larger than MaxMetaspaceSize for very small values of MaxMetaspaceSize.
// Lets just live with that, its not a big deal.

if (adjusted_ccs_size != CompressedClassSpaceSize) {
FLAG_SET_ERGO(CompressedClassSpaceSize, adjusted_ccs_size);
log_info(metaspace)("Setting CompressedClassSpaceSize to " SIZE_FORMAT ".",
71 changes: 34 additions & 37 deletions src/hotspot/share/oops/compressedKlass.cpp
Original file line number Diff line number Diff line change
@@ -48,17 +48,20 @@ address CompressedKlassPointers::_base = (address)-1;
int CompressedKlassPointers::_shift = -1;
size_t CompressedKlassPointers::_range = (size_t)-1;

// The maximum allowed length of the Klass range (the address range engulfing
// CDS + class space) must not exceed 32-bit.
// There is a theoretical limit of: must not exceed the size of a fully-shifted
// narrow Klass pointer, which would be 32 + 3 = 35 bits in legacy mode;
// however, keeping this size below 32-bit allows us to use decoding techniques
// like 16-bit moves into the third quadrant on some architectures, and keeps
// the code less complex. 32-bit have always been enough for CDS+class space.
static constexpr size_t max_klass_range_size = 4 * G;

#ifdef _LP64

// Returns the maximum encoding range that can be covered with the currently
// chosen nKlassID geometry (nKlass bit size, max shift)
size_t CompressedKlassPointers::max_encoding_range_size() {
// Whatever the nKlass geometry is, we don't support cases where the offset
// into the Klass encoding range (the shifted nKlass) exceeds 32 bits. That
// is because many CPU-specific decoding functions use e.g. 16-bit moves to
// combine base and offset.
constexpr int max_preshifted_nklass_bits = 32;
return nth_bit(MIN2(max_preshifted_nklass_bits,
narrow_klass_pointer_bits() + max_shift()));
}

void CompressedKlassPointers::pre_initialize() {
if (UseCompactObjectHeaders) {
_tiny_cp = 1;
@@ -81,10 +84,6 @@ void CompressedKlassPointers::sanity_check_after_initialization() {
#define ASSERT_HERE(cond) assert(cond, " (%s)", tmp);
#define ASSERT_HERE_2(cond, msg) assert(cond, msg " (%s)", tmp);

// There is no technical reason preventing us from using other klass pointer bit lengths,
// but it should be a deliberate choice
ASSERT_HERE(_narrow_klass_pointer_bits == 32 || _narrow_klass_pointer_bits == 22);

// All values must be inited
ASSERT_HERE(_max_shift != -1);
ASSERT_HERE(_klass_range_start != (address)-1);
@@ -95,7 +94,11 @@ void CompressedKlassPointers::sanity_check_after_initialization() {
ASSERT_HERE(_range != (size_t)-1);

const size_t klab = klass_alignment_in_bytes();
ASSERT_HERE(klab >= sizeof(uint64_t) && klab <= K);
// must be aligned enough hold 64-bit data
ASSERT_HERE(is_aligned(klab, sizeof(uint64_t)));

// should be smaller than the minimum metaspace chunk size (soft requirement)
ASSERT_HERE(klab <= K);

// Check that Klass range is fully engulfed in the encoding range
ASSERT_HERE(_klass_range_end > _klass_range_start);
@@ -108,7 +111,7 @@ void CompressedKlassPointers::sanity_check_after_initialization() {
// relevant regions and klass alignment - tied to smallest metachunk size of 1K - will always be smaller
// than smallest page size of 4K.
ASSERT_HERE_2(is_aligned(_klass_range_start, klab) && is_aligned(_klass_range_end, klab),
"Klass range must start at a properly aligned address");
"Klass range must start and end at a properly aligned address");

// Check that lowest and highest possible narrowKlass values make sense
ASSERT_HERE_2(_lowest_valid_narrow_klass_id > 0, "Null is not a valid narrowKlass");
@@ -153,10 +156,12 @@ void CompressedKlassPointers::calc_lowest_highest_narrow_klass_id() {
void CompressedKlassPointers::initialize_for_given_encoding(address addr, size_t len, address requested_base, int requested_shift) {
address const end = addr + len;

if (len > max_klass_range_size) {
// Class space size is limited to 3G. This can theoretically happen if the CDS archive
// is larger than 1G and class space size is set to the maximum possible 3G.
vm_exit_during_initialization("Sum of CDS archive size and class space size exceed 4 GB");
if (len > max_encoding_range_size()) {
stringStream ss;
ss.print("Class space size and CDS archive size combined (%zu) "
"exceed the maximum possible size (%zu)",
len, max_encoding_range_size());
vm_exit_during_initialization(ss.base());
}

const size_t encoding_range_size = nth_bit(narrow_klass_pointer_bits() + requested_shift);
@@ -202,10 +207,11 @@ char* CompressedKlassPointers::reserve_address_space_for_16bit_move(size_t size,

void CompressedKlassPointers::initialize(address addr, size_t len) {

if (len > max_klass_range_size) {
// Class space size is limited to 3G. This can theoretically happen if the CDS archive
// is larger than 1G and class space size is set to the maximum possible 3G.
vm_exit_during_initialization("Sum of CDS archive size and class space size exceed 4 GB");
if (len > max_encoding_range_size()) {
stringStream ss;
ss.print("Class space size (%zu) exceeds the maximum possible size (%zu)",
len, max_encoding_range_size());
vm_exit_during_initialization(ss.base());
}

// Give CPU a shot at a specialized init sequence
@@ -217,11 +223,6 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {

if (tiny_classpointer_mode()) {

// This handles the case that we - experimentally - reduce the number of
// class pointer bits further, such that (shift + num bits) < 32.
assert(len <= (size_t)nth_bit(narrow_klass_pointer_bits() + max_shift()),
"klass range size exceeds encoding");

// In tiny classpointer mode, we don't attempt for zero-based mode.
// Instead, we set the base to the start of the klass range and then try
// for the smallest shift possible that still covers the whole range.
@@ -230,16 +231,12 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {
_base = addr;
_range = len;

if (TinyClassPointerShift != 0) {
_shift = TinyClassPointerShift;
} else {
constexpr int log_cacheline = 6;
int s = max_shift();
while (s > log_cacheline && ((size_t)nth_bit(narrow_klass_pointer_bits() + s - 1) > len)) {
s--;
}
_shift = s;
constexpr int log_cacheline = 6;
int s = max_shift();
while (s > log_cacheline && ((size_t)nth_bit(narrow_klass_pointer_bits() + s - 1) > len)) {
s--;
}
_shift = s;

} else {

4 changes: 4 additions & 0 deletions src/hotspot/share/oops/compressedKlass.hpp
Original file line number Diff line number Diff line change
@@ -133,6 +133,10 @@ class CompressedKlassPointers : public AllStatic {
// The maximum possible shift; the actual shift employed later can be smaller (see initialize())
static int max_shift() { check_init(_max_shift); return _max_shift; }

// Returns the maximum encoding range that can be covered with the currently
// choosen nKlassID geometry (nKlass bit size, max shift)
static size_t max_encoding_range_size();

// Reserve a range of memory that is to contain Klass strucutures which are referenced by narrow Klass IDs.
// If optimize_for_zero_base is true, the implementation will attempt to reserve optimized for zero-based encoding.
static char* reserve_address_space_for_compressed_classes(size_t size, bool aslr, bool optimize_for_zero_base);
2 changes: 0 additions & 2 deletions src/hotspot/share/runtime/globals.hpp
Original file line number Diff line number Diff line change
@@ -131,8 +131,6 @@ const size_t minimumSymbolTableSize = 1024;
product(bool, UseCompactObjectHeaders, false, EXPERIMENTAL, \
"Use compact 64-bit object headers in 64-bit VM") \
\
develop(int, TinyClassPointerShift, 0, "") \
\
product(int, ObjectAlignmentInBytes, 8, \
"Default object alignment in bytes, 8 is minimum") \
range(8, 256) \