--- a/src/hotspot/share/memory/metaspace/metachunk.cpp Wed Sep 18 07:46:02 2019 +0200
+++ b/src/hotspot/share/memory/metaspace/metachunk.cpp Thu Sep 19 15:21:27 2019 +0200
@@ -30,8 +30,10 @@
#include "logging/log.hpp"
#include "memory/metaspace/chunkLevel.hpp"
#include "memory/metaspace/metachunk.hpp"
+#include "memory/metaspace/metaDebug.hpp"
#include "memory/metaspace/metaspaceCommon.hpp"
#include "memory/metaspace/virtualSpaceNode.hpp"
+#include "runtime/mutexLocker.hpp"
#include "utilities/align.hpp"
#include "utilities/copy.hpp"
@@ -52,6 +54,12 @@
return '?';
}
+#ifdef ASSERT
+void Metachunk::assert_have_expand_lock() {
+ assert_lock_strong(MetaspaceExpand_lock);
+}
+#endif
+
// Commit uncommitted section of the chunk.
// Fails if we hit a commit limit.
bool Metachunk::commit_up_to(size_t new_committed_words) {
@@ -222,6 +230,8 @@
_used_words += request_word_size;
+ SOMETIMES(verify(false);)
+
return p;
}
@@ -275,74 +285,70 @@
}
}
-volatile MetaWord dummy = 0;
-
-void Metachunk::verify(bool slow) const {
-
- assert(!is_dead(), "dead chunk.");
- // Note: only call this on a life Metachunk.
- chklvl::check_valid_level(level());
+// Verifies linking with neighbors in virtual space.
+// Can only be done under expand lock protection.
+void Metachunk::verify_neighborhood() const {
- assert(base() != NULL, "No base ptr");
- assert(committed_words() >= used_words(),
- "mismatch: committed: " SIZE_FORMAT ", used: " SIZE_FORMAT ".",
- committed_words(), used_words());
- assert(word_size() >= committed_words(),
- "mismatch: word_size: " SIZE_FORMAT ", committed: " SIZE_FORMAT ".",
- word_size(), committed_words());
+ assert_lock_strong(MetaspaceExpand_lock);
+ assert(!is_dead(), "Do not call on dead chunks.");
- // Test base pointer
- assert(vsnode() != NULL, "No space");
- vsnode()->check_pointer(base());
- assert(base() != NULL, "Base pointer NULL");
-
- // Neighbors shall be adjacent to us...
- if (prev_in_vs() != NULL) {
- assert(prev_in_vs()->end() == base() &&
- prev_in_vs()->next_in_vs() == this,
- "Chunk " METACHUNK_FORMAT ": broken link to left neighbor: " METACHUNK_FORMAT ".",
- METACHUNK_FORMAT_ARGS(this), METACHUNK_FORMAT_ARGS(prev_in_vs()));
- }
+ if (is_root_chunk()) {
- if (next_in_vs() != NULL) {
- assert(end() == next_in_vs()->base() &&
- next_in_vs()->prev_in_vs() == this,
- "Chunk " METACHUNK_FORMAT ": broken link to right neighbor: " METACHUNK_FORMAT ".",
- METACHUNK_FORMAT_ARGS(this), METACHUNK_FORMAT_ARGS(next_in_vs()));
- }
+ // Root chunks are all alone in the world.
+ assert(next_in_vs() == NULL || prev_in_vs() == NULL, "Root chunks should have no neighbors");
- // Starting address shall be aligned to chunk size.
- const size_t required_alignment = word_size() * sizeof(MetaWord);
- assert_is_aligned(base(), required_alignment);
+ } else {
- if (!is_root_chunk()) {
+ // Non-root chunks have neighbors, at least one, possibly two.
assert(next_in_vs() != NULL || prev_in_vs() != NULL,
"A non-root chunk should have neighbors (chunk @" PTR_FORMAT
", base " PTR_FORMAT ", level " CHKLVL_FORMAT ".",
p2i(this), p2i(base()), level());
- // check buddy. Note: the chunk following us or preceeding us may
- // be our buddy or a splintered part of it.
+ if (prev_in_vs() != NULL) {
+ assert(prev_in_vs()->end() == base(),
+ "Chunk " METACHUNK_FULL_FORMAT ": should be adjacent to predecessor: " METACHUNK_FULL_FORMAT ".",
+ METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(prev_in_vs()));
+ assert(prev_in_vs()->next_in_vs() == this,
+ "Chunk " METACHUNK_FULL_FORMAT ": broken link to left neighbor: " METACHUNK_FULL_FORMAT " (" PTR_FORMAT ").",
+ METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(prev_in_vs()), p2i(prev_in_vs()->next_in_vs()));
+ }
+
+ if (next_in_vs() != NULL) {
+ assert(end() == next_in_vs()->base(),
+ "Chunk " METACHUNK_FULL_FORMAT ": should be adjacent to successor: " METACHUNK_FULL_FORMAT ".",
+ METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(next_in_vs()));
+ assert(next_in_vs()->prev_in_vs() == this,
+ "Chunk " METACHUNK_FULL_FORMAT ": broken link to right neighbor: " METACHUNK_FULL_FORMAT " (" PTR_FORMAT ").",
+ METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(next_in_vs()), p2i(next_in_vs()->prev_in_vs()));
+ }
+
+ // One of the neighbors must be the buddy. It can be whole or splintered.
+
+ // The chunk following us or preceeding us may be our buddy or a splintered part of it.
Metachunk* buddy = is_leader() ? next_in_vs() : prev_in_vs();
assert(buddy != NULL, "Missing neighbor.");
- assert(!buddy->is_dead(), "buddy dead.");
+ assert(!buddy->is_dead(), "Invalid buddy state.");
// This neighbor is either or buddy (same level) or a splinter of our buddy - hence
- // the level can never be smaller (larger chunk size).
+ // the level can never be smaller (aka the chunk size cannot be larger).
assert(buddy->level() >= level(), "Wrong level.");
+
if (buddy->level() == level()) {
- // we have a direct, unsplintered buddy.
- assert(buddy->is_leader() == !is_leader(), "Only one chunk can be leader in a pair");
+ // If the buddy is of the same size as us, it is unsplintered.
+ assert(buddy->is_leader() == !is_leader(),
+ "Only one chunk can be leader in a pair");
// When direct buddies are neighbors, one or both should be in use, otherwise they should
// have been merged.
- // Since we call verify() from internal functions where we are about to merge or just did split,
- // do not test this.
+ // But since we call this verification function from internal functions where we are about to merge or just did split,
+ // do not test this. We have RootChunkArea::verify_area_is_ideally_merged() for testing that.
+
// assert(buddy->is_in_use() || is_in_use(), "incomplete merging?");
if (is_leader()) {
@@ -352,15 +358,53 @@
assert(buddy->end() == base(), "Sanity");
assert(is_aligned(buddy->base(), word_size() * 2 * BytesPerWord), "Sanity");
}
+
} else {
+
// Buddy, but splintered, and this is a part of it.
if (is_leader()) {
assert(buddy->base() == end(), "Sanity");
} else {
assert(buddy->end() > (base() - word_size()), "Sanity");
}
+
}
}
+}
+
+volatile MetaWord dummy = 0;
+
+void Metachunk::verify(bool slow) const {
+
+ // Note. This should be called under CLD lock protection.
+
+ // We can verify everything except the _prev_in_vs/_next_in_vs pair.
+ // This is because neighbor chunks may be added concurrently, so we cannot rely
+ // on the content of _next_in_vs/_prev_in_vs unless we have the expand lock.
+
+ assert(!is_dead(), "Do not call on dead chunks.");
+
+ // Note: only call this on a life Metachunk.
+ chklvl::check_valid_level(level());
+
+ assert(base() != NULL, "No base ptr");
+
+ assert(committed_words() >= used_words(),
+ "mismatch: committed: " SIZE_FORMAT ", used: " SIZE_FORMAT ".",
+ committed_words(), used_words());
+
+ assert(word_size() >= committed_words(),
+ "mismatch: word_size: " SIZE_FORMAT ", committed: " SIZE_FORMAT ".",
+ word_size(), committed_words());
+
+ // Test base pointer
+ assert(base() != NULL, "Base pointer NULL");
+ assert(vsnode() != NULL, "No space");
+ vsnode()->check_pointer(base());
+
+ // Starting address shall be aligned to chunk size.
+ const size_t required_alignment = word_size() * sizeof(MetaWord);
+ assert_is_aligned(base(), required_alignment);
// If slow, test the committed area
if (slow && _committed_words > 0) {
@@ -399,7 +443,7 @@
return false;
}
-void MetachunkList::verify(bool slow) const {
+void MetachunkList::verify() const {
int num = 0;
const Metachunk* last_c = NULL;
for (const Metachunk* c = first(); c != NULL; c = c->next()) {
@@ -407,9 +451,7 @@
assert(c->prev() == last_c,
"Broken link to predecessor. Chunk " METACHUNK_FULL_FORMAT ".",
METACHUNK_FULL_FORMAT_ARGS(c));
- if (slow) {
- c->verify(false);
- }
+ c->verify(false);
last_c = c;
}
_num.check(num);
@@ -458,7 +500,7 @@
}
// Check each list.
- list_for_level(l)->verify(slow);
+ list_for_level(l)->verify();
num += list_for_level(l)->size();
word_size += list_for_level(l)->size() * chklvl::word_size_for_level(l);