-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8340184: Bug in CompressedKlassPointers::is_in_encodable_range #21015
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
Changes from all commits
4942fc0
ab82126
31fd2d2
8145ce6
03c3dba
ca949b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5082,8 +5082,8 @@ MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode() { | |
|
|
||
| if (operand_valid_for_logical_immediate( | ||
| /*is32*/false, (uint64_t)CompressedKlassPointers::base())) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reviewer hint: The before and after code should be exactly identical. What we do here is we calculate the max. value a left-shifted nKlass can have, and compute a mask over it. |
||
| const uint64_t range_mask = | ||
| (1ULL << log2i(CompressedKlassPointers::range())) - 1; | ||
| const size_t range = CompressedKlassPointers::klass_range_end() - CompressedKlassPointers::base(); | ||
| const uint64_t range_mask = (1ULL << log2i(range)) - 1; | ||
| if (((uint64_t)CompressedKlassPointers::base() & range_mask) == 0) { | ||
| return (_klass_decode_mode = KlassDecodeXor); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,69 @@ | |
| class outputStream; | ||
| class Klass; | ||
|
|
||
| // Narrow Klass Encoding | ||
| // | ||
| // Klass Range: | ||
| // a contiguous memory range into which we place Klass that should be encodable. Not every Klass | ||
| // needs to be encodable. There is only one such memory range. | ||
| // If CDS is disabled, this Klass Range is the same as the metaspace class space. If CDS is enabled, the | ||
| // Klass Range contains both CDS and class space adjacent to each other (with a potential small | ||
| // unused alignment gap between them). | ||
| // | ||
| // Encoding Range: | ||
| // This is the range covered by the current encoding scheme. The encoding scheme is defined by | ||
| // the encoding base, encoding shift and (implicitly) the bit size of the narrowKlass. The | ||
| // Encoding Range is: | ||
| // [ <encoding base> ... <encoding base> + (1 << (<narrowKlass-bitsize> + <shift>) ) | ||
| // | ||
| // Note that while the Klass Range must be contained within the Encoding Range, the Encoding Range | ||
| // is typically a lot larger than the Klass Range: | ||
| // - the encoding base can start before the Klass Range start (specifically, it can start at 0 for | ||
| // zero-based encoding) | ||
| // - the end of the Encoding Range usually extends far beyond the end of the Klass Range. | ||
| // | ||
| // | ||
| // Examples: | ||
| // | ||
| // "unscaled" (zero-based zero-shift) encoding, CDS off, class space of 1G starts at 0x4B00_0000: | ||
| // - Encoding Range: [0 .. 0x1_0000_0000 ) (4 GB) | ||
| // - Klass Range: [0x4B00_0000 .. 0x 8B00_0000 ) (1 GB) | ||
| // | ||
| // | ||
| // _base _klass_range_start _klass_range_end encoding end | ||
| // | |//////////////////////////////| | | ||
| // | ... |///////1gb class space////////| ... | | ||
| // | |//////////////////////////////| | | ||
| // 0x0 0x4B00_0000 0x8B00_0000 0x1_0000_0000 | ||
| // | ||
| // | ||
| // | ||
| // "zero-based" (but scaled) encoding, shift=3, CDS off, 1G Class space at 0x7_C000_0000 (31GB): | ||
| // - Encoding Range: [0 .. 0x8_0000_0000 ) (32 GB) | ||
| // - Klass Range: [0x7_C000_0000 .. 0x8_0000_0000 ) (1 GB) | ||
| // | ||
| // encoding end | ||
| // _base _klass_range_start _klass_range_end | ||
| // | |//////////////////////////////| | ||
| // | ... |///////1gb class space////////| | ||
| // | |//////////////////////////////| | ||
| // 0x0 0x7_C000_0000 0x8_0000_0000 | ||
| // | ||
| // | ||
| // CDS enabled, 128MB CDS region starts 0x8_0000_0000, followed by a 1GB class space. Encoding | ||
| // base will point to CDS region start, shift=0: | ||
| // - Encoding Range: [0x8_0000_0000 .. 0x9_0000_0000 ) (4 GB) | ||
| // - Klass Range: [0x8_0000_0000 .. 0x8_4800_0000 ) (128 MB + 1 GB) | ||
| // | ||
| // _base | ||
| // _klass_range_start _klass_range_end encoding end | ||
| // |//////////|///////////////////////////| | | ||
| // |///CDS////|////1gb class space////////| ... ... | | ||
| // |//////////|///////////////////////////| | | ||
| // | | | | ||
| // 0x8_0000_0000 0x8_4800_0000 0x9_0000_0000 | ||
| // | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that I like this comment better than the one we have in Lilliput, since its more concise; I will use this in Lilliput too (with some minor additions for 22bit narrowKlass). |
||
| // If compressed klass pointers then use narrowKlass. | ||
| typedef juint narrowKlass; | ||
|
|
||
|
|
@@ -50,12 +113,10 @@ class CompressedKlassPointers : public AllStatic { | |
| static address _base; | ||
| static int _shift; | ||
|
|
||
| // Together with base, this defines the address range within which Klass | ||
| // structures will be located: [base, base+range). While the maximal | ||
| // possible encoding range is 4|32G for shift 0|3, if we know beforehand | ||
| // the expected range of Klass* pointers will be smaller, a platform | ||
| // could use this info to optimize encoding. | ||
| static size_t _range; | ||
| // Start and end of the Klass Range. | ||
| // Note: guaranteed to be aligned to KlassAlignmentInBytes | ||
| static address _klass_range_start; | ||
| static address _klass_range_end; | ||
|
|
||
| // Helper function for common cases. | ||
| 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 { | |
| static void print_mode(outputStream* st); | ||
|
|
||
| static address base() { return _base; } | ||
| static size_t range() { return _range; } | ||
| static int shift() { return _shift; } | ||
|
|
||
| static address klass_range_start() { return _klass_range_start; } | ||
| static address klass_range_end() { return _klass_range_end; } | ||
|
|
||
| static inline address encoding_range_end(); | ||
|
|
||
| static bool is_null(Klass* v) { return v == nullptr; } | ||
| static bool is_null(narrowKlass v) { return v == 0; } | ||
|
|
||
|
|
@@ -110,14 +175,9 @@ class CompressedKlassPointers : public AllStatic { | |
|
|
||
| // Returns whether the pointer is in the memory region used for encoding compressed | ||
| // class pointers. This includes CDS. | ||
|
|
||
| // encoding encoding | ||
| // base end (base+range) | ||
| // |-----------------------------------------------------------------------| | ||
| // |----CDS---| |--------------------class space---------------------------| | ||
|
|
||
| static inline bool is_in_encoding_range(const void* p) { | ||
| return p >= _base && p < (_base + _range); | ||
| static inline bool is_encodable(const void* p) { | ||
| return (address) p >= _klass_range_start && | ||
| (address) p < _klass_range_end; | ||
| } | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /* | ||
| * Copyright (c) 2024, Red Hat, Inc. All rights reserved. | ||
| * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. | ||
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| * | ||
| * This code is free software; you can redistribute it and/or modify it | ||
| * under the terms of the GNU General Public License version 2 only, as | ||
| * published by the Free Software Foundation. | ||
| * | ||
| * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| * version 2 for more details (a copy is included in the LICENSE file that | ||
| * accompanied this code). | ||
| * | ||
| * You should have received a copy of the GNU General Public License version | ||
| * 2 along with this work; if not, write to the Free Software Foundation, | ||
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| * | ||
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| * or visit www.oracle.com if you need additional information or have any | ||
| * questions. | ||
| */ | ||
|
|
||
| #include "precompiled.hpp" | ||
| #include "oops/compressedKlass.inline.hpp" | ||
| #include "utilities/globalDefinitions.hpp" | ||
|
|
||
| #include "unittest.hpp" | ||
|
|
||
| TEST_VM(CompressedKlass, basics) { | ||
| if (!UseCompressedClassPointers) { | ||
| return; | ||
| } | ||
| ASSERT_LE((address)0, CompressedKlassPointers::base()); | ||
| ASSERT_LE(CompressedKlassPointers::base(), CompressedKlassPointers::klass_range_start()); | ||
| ASSERT_LT(CompressedKlassPointers::klass_range_start(), CompressedKlassPointers::klass_range_end()); | ||
| ASSERT_LE(CompressedKlassPointers::klass_range_end(), CompressedKlassPointers::encoding_range_end()); | ||
| switch (CompressedKlassPointers::shift()) { | ||
| case 0: | ||
| ASSERT_EQ(CompressedKlassPointers::encoding_range_end() - CompressedKlassPointers::base(), (ptrdiff_t)(4 * G)); | ||
| break; | ||
| case 3: | ||
| ASSERT_EQ(CompressedKlassPointers::encoding_range_end() - CompressedKlassPointers::base(), (ptrdiff_t)(32 * G)); | ||
| break; | ||
| default: | ||
| ShouldNotReachHere(); | ||
| } | ||
| } | ||
|
|
||
| TEST_VM(CompressedKlass, test_too_low_address) { | ||
| if (!UseCompressedClassPointers) { | ||
| return; | ||
| } | ||
| address really_low = (address) 32; | ||
| ASSERT_FALSE(CompressedKlassPointers::is_encodable(really_low)); | ||
| address low = CompressedKlassPointers::klass_range_start() - 1; | ||
| ASSERT_FALSE(CompressedKlassPointers::is_encodable(low)); | ||
| } | ||
|
|
||
| TEST_VM(CompressedKlass, test_too_high_address) { | ||
| if (!UseCompressedClassPointers) { | ||
| return; | ||
| } | ||
| address really_high = (address) UINTPTR_MAX; | ||
| ASSERT_FALSE(CompressedKlassPointers::is_encodable(really_high)); | ||
| address high = CompressedKlassPointers::klass_range_end(); | ||
| ASSERT_FALSE(CompressedKlassPointers::is_encodable(high)); | ||
| } | ||
|
|
||
| TEST_VM(CompressedKlass, test_good_address) { | ||
| if (!UseCompressedClassPointers) { | ||
| return; | ||
| } | ||
| address addr = CompressedKlassPointers::klass_range_start(); | ||
| ASSERT_TRUE(CompressedKlassPointers::is_encodable(addr)); | ||
| addr = CompressedKlassPointers::klass_range_end() - 1; | ||
| ASSERT_TRUE(CompressedKlassPointers::is_encodable(addr)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /* | ||
| * Copyright (c) 2024, Red Hat, Inc. All rights reserved. | ||
| * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. | ||
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| * | ||
| * This code is free software; you can redistribute it and/or modify it | ||
| * under the terms of the GNU General Public License version 2 only, as | ||
| * published by the Free Software Foundation. | ||
| * | ||
| * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| * version 2 for more details (a copy is included in the LICENSE file that | ||
| * accompanied this code). | ||
| * | ||
| * You should have received a copy of the GNU General Public License version | ||
| * 2 along with this work; if not, write to the Free Software Foundation, | ||
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| * | ||
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| * or visit www.oracle.com if you need additional information or have any | ||
| * questions. | ||
| * | ||
| */ | ||
|
|
||
| /* | ||
| * This runs the "compressedKlass" class of gtests. | ||
| * Note: we try to trigger bugs by enforcing the JVM to use zero-based mode. To increase the chance of zero-based | ||
| * mode, we start with CDS disabled, a small class space and a large (albeit uncommitted, to save memory) heap. The | ||
| * JVM will likely place the class space in low-address territory. | ||
| * (If it does not manage to do this, the test will still succeed, but it won't alert us on regressions) | ||
| */ | ||
|
|
||
| /* @test id=use-zero-based-encoding | ||
| * @library /test/lib | ||
| * @modules java.base/jdk.internal.misc | ||
| * java.xml | ||
| * @run main/native GTestWrapper --gtest_filter=CompressedKlass* -Xlog:metaspace* -Xmx6g -Xms128m -Xshare:off -XX:CompressedClassSpaceSize=128m | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the Lilliput review, I think you were moving this to shared code with an ifdef so that these variables are all set in one place. This is ok here for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I did this. I like the Lilliput variant better too.