8334781: JFR crash: assert(((((JfrTraceIdBits::load(klass)) & ((JfrTraceIdEpoch::this_epoch_method_and_class_bits()))) != 0))) failed: invariant

Reviewed-by: egahlin
This commit is contained in:
Markus Grönlund 2024-07-17 11:17:10 +00:00
parent d41d2a7a82
commit 67979eb077
7 changed files with 31 additions and 17 deletions

View File

@ -310,7 +310,9 @@ static void set_serialized(const T* ptr) {
assert(ptr != nullptr, "invariant");
if (current_epoch()) {
CLEAR_THIS_EPOCH_CLEARED_BIT(ptr);
assert(!IS_THIS_EPOCH_CLEARED_BIT_SET(ptr), "invariant");
}
assert(IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(ptr), "invariant");
SET_SERIALIZED(ptr);
assert(IS_SERIALIZED(ptr), "invariant");
}
@ -929,9 +931,11 @@ void set_serialized<Method>(MethodPtr method) {
assert(method != nullptr, "invariant");
if (current_epoch()) {
CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method);
assert(!IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant");
}
assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant");
SET_METHOD_SERIALIZED(method);
assert(IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant");
assert(METHOD_IS_SERIALIZED(method), "invariant");
}

View File

@ -96,6 +96,8 @@ class ClearArtifact {
assert(IS_NOT_TRANSIENT(value), "invariant");
SET_PREVIOUS_EPOCH_CLEARED_BIT(value);
CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(value);
assert(IS_THIS_EPOCH_CLEARED_BIT_SET(value), "invariant");
assert(IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(value), "invariant");
return true;
}
};
@ -111,6 +113,8 @@ class ClearArtifact<const Method*> {
assert(METHOD_IS_NOT_TRANSIENT(method), "invariant");
SET_PREVIOUS_EPOCH_METHOD_CLEARED_BIT(method);
CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method);
assert(IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant");
assert(IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant");
return true;
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -50,22 +50,22 @@ static traceid atomic_inc(traceid volatile* const dest, traceid stride = 1) {
static traceid next_class_id() {
static volatile traceid class_id_counter = LAST_TYPE_ID + 1; // + 1 is for the void.class primitive
return atomic_inc(&class_id_counter) << TRACE_ID_SHIFT;
return (atomic_inc(&class_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS;
}
static traceid next_module_id() {
static volatile traceid module_id_counter = 0;
return atomic_inc(&module_id_counter) << TRACE_ID_SHIFT;
return (atomic_inc(&module_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS;
}
static traceid next_package_id() {
static volatile traceid package_id_counter = 0;
return atomic_inc(&package_id_counter) << TRACE_ID_SHIFT;
return (atomic_inc(&package_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS;
}
static traceid next_class_loader_data_id() {
static volatile traceid cld_id_counter = 0;
return atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT;
return (atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS;
}
static bool found_jdk_internal_event_klass = false;
@ -201,18 +201,18 @@ traceid JfrTraceId::load_raw(jclass jc) {
// used by CDS / APPCDS as part of "remove_unshareable_info"
void JfrTraceId::remove(const Klass* k) {
assert(k != nullptr, "invariant");
// Mask off and store the event flags.
// Mask off and store the event flags and epoch clear bits.
// This mechanism will retain the event specific flags
// in the archive, allowing for event flag restoration
// when renewing the traceid on klass revival.
k->set_trace_id(EVENT_KLASS_MASK(k));
k->set_trace_id(EPOCH_CLEARED_BITS | EVENT_KLASS_MASK(k));
}
// used by CDS / APPCDS as part of "remove_unshareable_info"
void JfrTraceId::remove(const Method* method) {
assert(method != nullptr, "invariant");
// Clear all bits.
method->set_trace_flags(0);
// Clear tag bits and set epoch cleared bits.
method->set_trace_flags(static_cast<uint16_t>(EPOCH_CLEARED_BITS));
}
// used by CDS / APPCDS as part of "restore_unshareable_info"

View File

@ -157,9 +157,9 @@ inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass) {
inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Method* method) {
assert(klass != nullptr, "invariant");
assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
assert(method != nullptr, "invariant");
assert(klass == method->method_holder(), "invariant");
assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
if (should_tag(method)) {
// the method is already logically tagged, just like the klass,
// but because of redefinition, the latest Method*
@ -174,9 +174,9 @@ inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Metho
inline traceid JfrTraceIdLoadBarrier::load_leakp_previuos_epoch(const Klass* klass, const Method* method) {
assert(klass != nullptr, "invariant");
assert(METHOD_AND_CLASS_USED_PREVIOUS_EPOCH(klass), "invariant");
assert(method != nullptr, "invariant");
assert(klass == method->method_holder(), "invariant");
assert(METHOD_AND_CLASS_USED_PREVIOUS_EPOCH(klass), "invariant");
if (METHOD_FLAG_NOT_USED_PREVIOUS_EPOCH(method)) {
// the method is already logically tagged, just like the klass,
// but because of redefinition, the latest Method*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -48,6 +48,7 @@
#define EPOCH_0_CLEARED_BIT (EPOCH_0_CLEARED_META_BIT << META_SHIFT)
#define EPOCH_1_CLEARED_META_BIT (BIT << 1)
#define EPOCH_1_CLEARED_BIT (EPOCH_1_CLEARED_META_BIT << META_SHIFT)
#define EPOCH_CLEARED_BITS (EPOCH_1_CLEARED_BIT | EPOCH_0_CLEARED_BIT)
#define LEAKP_META_BIT (BIT << 2)
#define LEAKP_BIT (LEAKP_META_BIT << META_SHIFT)
#define TRANSIENT_META_BIT (BIT << 3)
@ -136,6 +137,8 @@
#define IS_TRANSIENT(ptr) (TRACE_ID_PREDICATE(ptr, TRANSIENT_BIT))
#define IS_NOT_TRANSIENT(ptr) (!(IS_TRANSIENT(ptr)))
#define SET_SERIALIZED(ptr) (TRACE_ID_META_TAG(ptr, SERIALIZED_META_BIT))
#define IS_THIS_EPOCH_CLEARED_BIT_SET(ptr) (TRACE_ID_PREDICATE(ptr, (THIS_EPOCH_BIT << META_SHIFT)))
#define IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(ptr) (TRACE_ID_PREDICATE(ptr, (PREVIOUS_EPOCH_BIT << META_SHIFT)))
#define IS_SERIALIZED(ptr) (TRACE_ID_PREDICATE(ptr, SERIALIZED_BIT))
#define IS_NOT_SERIALIZED(ptr) (!(IS_SERIALIZED(ptr)))
#define SHOULD_TAG(ptr) (NOT_USED_THIS_EPOCH(ptr))
@ -161,5 +164,7 @@
#define CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(ptr) (METHOD_META_MASK_CLEAR(ptr,(~(THIS_EPOCH_BIT))))
#define IS_THIS_EPOCH_METHOD_CLEARED(ptr) (METHOD_FLAG_PREDICATE(method, THIS_EPOCH_BIT))
#define IS_PREVIOUS_EPOCH_METHOD_CLEARED(ptr) (METHOD_FLAG_PREDICATE(method, PREVIOUS_EPOCH_BIT))
#define IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(ptr) (METHOD_FLAG_PREDICATE(ptr, (THIS_EPOCH_BIT << META_SHIFT)))
#define IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(ptr) (METHOD_FLAG_PREDICATE(ptr, (PREVIOUS_EPOCH_BIT << META_SHIFT)))
#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP

View File

@ -44,11 +44,13 @@
#define REMOVE_METHOD_ID(method) JfrTraceId::remove(method);
#define RESTORE_ID(k) JfrTraceId::restore(k);
static constexpr const uint16_t cleared_epoch_bits = 512 | 256;
class JfrTraceFlag {
private:
mutable uint16_t _flags;
public:
JfrTraceFlag() : _flags(0) {}
JfrTraceFlag() : _flags(cleared_epoch_bits) {}
bool is_set(uint16_t flag) const {
return (_flags & flag) != 0;
}
@ -96,9 +98,8 @@ class JfrTraceFlag {
uint8_t* trace_meta_addr() const { \
return _trace_flags.meta_addr(); \
} \
void copy_trace_flags(uint8_t src_flags) const { \
uint8_t flags = *_trace_flags.flags_addr(); \
_trace_flags.set_flags(flags | src_flags); \
void copy_trace_flags(uint16_t rhs_flags) const { \
_trace_flags.set_flags(_trace_flags.flags() | rhs_flags); \
}
#endif // SHARE_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP

View File

@ -1174,7 +1174,7 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
}
}
}
JFR_ONLY(k_new_method->copy_trace_flags(*k_old_method->trace_flags_addr());)
JFR_ONLY(k_new_method->copy_trace_flags(k_old_method->trace_flags());)
log_trace(redefine, class, normalize)
("Method matched: new: %s [%d] == old: %s [%d]",
k_new_method->name_and_sig_as_C_string(), ni, k_old_method->name_and_sig_as_C_string(), oi);