Skip to content
Open
Show file tree
Hide file tree
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
51 changes: 50 additions & 1 deletion src/hotspot/share/ci/ciInstanceKlass.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, 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
Expand Down Expand Up @@ -432,6 +432,55 @@ ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature,
return field;
}

#ifdef ASSERT
static void assert_injected_field(InternalFieldStream& fs) {
assert(!fs.done(), "invarinat");
fieldDescriptor fd = fs.field_descriptor();
assert(fd.is_injected(), "invariant");
}
#endif

// ------------------------------------------------------------------
// ciInstanceKlass::get_injected_instance_field_by_name
//
// Implements also compute_injected_fields().
//
ciField* ciInstanceKlass::get_injected_instance_field_by_name(ciSymbol* name, ciSymbol* signature) {
VM_ENTRY_MARK;
InstanceKlass* const k = get_instanceKlass();
const Symbol* const name_symbol = name->get_symbol();
assert(name_symbol != nullptr, "invariant");
const Symbol* const sig_sym = signature->get_symbol();
assert(sig_sym != nullptr, "invariant");

if (_has_injected_fields == -1) {
if (super() != nullptr && super()->has_injected_fields()) {
_has_injected_fields = 1;
}
}

ciField* injected = nullptr;
for (InternalFieldStream fs(k); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) continue;
DEBUG_ONLY(assert_injected_field(fs);)
if (_has_injected_fields == -1) {
_has_injected_fields = 1;
}
if (fs.name() == name_symbol && fs.signature() == sig_sym) {
fieldDescriptor fd = fs.field_descriptor();
assert(fd.is_injected(), "invariant");
injected = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
break;
}
}

if (_has_injected_fields == -1) {
_has_injected_fields = 0;
}

return injected;
}

// This is essentially a shortcut for:
// get_field_by_offset(field_offset, is_static)->layout_type()
// except this does not require allocating memory for a new ciField
Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/ci/ciInstanceKlass.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, 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
Expand Down Expand Up @@ -215,6 +215,7 @@ class ciInstanceKlass : public ciKlass {
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
ciField* get_injected_instance_field_by_name(ciSymbol* name, ciSymbol* signature);
BasicType get_field_type_by_offset(int field_offset, bool is_static);

// total number of nonstatic fields (including inherited):
Expand Down
27 changes: 27 additions & 0 deletions src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3588,6 +3588,7 @@ int java_lang_reflect_Field::_modifiers_offset;
int java_lang_reflect_Field::_trusted_final_offset;
int java_lang_reflect_Field::_signature_offset;
int java_lang_reflect_Field::_annotations_offset;
JFR_ONLY(int java_lang_reflect_Field::_jfr_epoch_offset;)

#define FIELD_FIELDS_DO(macro) \
macro(_clazz_offset, k, vmSymbols::clazz_name(), class_signature, false); \
Expand All @@ -3602,11 +3603,13 @@ int java_lang_reflect_Field::_annotations_offset;
void java_lang_reflect_Field::compute_offsets() {
InstanceKlass* k = vmClasses::reflect_Field_klass();
FIELD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
JFR_ONLY(FIELD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);)
}

#if INCLUDE_CDS
void java_lang_reflect_Field::serialize_offsets(SerializeClosure* f) {
FIELD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
JFR_ONLY(FIELD_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);)
}
#endif

Expand Down Expand Up @@ -3672,6 +3675,29 @@ void java_lang_reflect_Field::set_annotations(oop field, oop value) {
field->obj_field_put(_annotations_offset, value);
}

#if INCLUDE_JFR
u2 java_lang_reflect_Field::epoch(oop ref) {
return static_cast<u2>(ref->int_field(_jfr_epoch_offset));
}

int jdk_internal_event_JfrEpoch::_jfr_epoch_offset;

void jdk_internal_event_JfrEpoch::compute_offsets() {
InstanceKlass* k = vmClasses::jfrEpoch_klass();
JFR_EPOCH_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void jdk_internal_event_JfrEpoch::serialize_offsets(SerializeClosure* f) {
JFR_EPOCH_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
}
#endif

u2 jdk_internal_event_JfrEpoch::epoch(oop ref) {
return static_cast<u2>(ref->int_field(_jfr_epoch_offset));
}
#endif // INCLUDE_JFR

oop java_lang_reflect_RecordComponent::create(InstanceKlass* holder, RecordComponent* component, TRAPS) {
// Allocate java.lang.reflect.RecordComponent instance
HandleMark hm(THREAD);
Expand Down Expand Up @@ -5397,6 +5423,7 @@ void java_lang_InternalError::serialize_offsets(SerializeClosure* f) {
f(jdk_internal_misc_UnsafeConstants) \
f(java_lang_boxing_object) \
f(vector_VectorPayload) \
JFR_ONLY(f(jdk_internal_event_JfrEpoch)) \
//end

#define BASIC_JAVA_CLASSES_DO(f) \
Expand Down
30 changes: 30 additions & 0 deletions src/hotspot/share/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,32 @@ class java_lang_reflect_Constructor : public java_lang_reflect_AccessibleObject
};


#if INCLUDE_JFR

#define JFR_EPOCH_INJECTED_FIELDS(macro) \
macro(jdk_internal_event_JfrEpoch, jfr_epoch, int_signature, false)

class jdk_internal_event_JfrEpoch : AllStatic {
private:
static int _jfr_epoch_offset;

static void compute_offsets();

public:
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;

static u2 epoch(oop field);
static int epoch_offset() { CHECK_INIT(_jfr_epoch_offset); }

// Debugging
friend class JavaClasses;
};

#define FIELD_INJECTED_FIELDS(macro) \
macro(java_lang_reflect_Field, jfr_epoch, int_signature, false)

#endif // INCLUDE_JFR

// Interface to java.lang.reflect.Field objects

class java_lang_reflect_Field : public java_lang_reflect_AccessibleObject {
Expand All @@ -834,6 +860,7 @@ class java_lang_reflect_Field : public java_lang_reflect_AccessibleObject {
static int _trusted_final_offset;
static int _signature_offset;
static int _annotations_offset;
JFR_ONLY(static int _jfr_epoch_offset;)

static void compute_offsets();

Expand Down Expand Up @@ -864,6 +891,9 @@ class java_lang_reflect_Field : public java_lang_reflect_AccessibleObject {
static void set_signature(oop constructor, oop value);
static void set_annotations(oop constructor, oop value);

JFR_ONLY(static u2 epoch(oop field);)
JFR_ONLY(static int epoch_offset() { CHECK_INIT(_jfr_epoch_offset); })

// Debugging
friend class JavaClasses;
};
Expand Down
6 changes: 4 additions & 2 deletions src/hotspot/share/classfile/javaClassesImpl.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, 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
Expand Down Expand Up @@ -43,7 +43,9 @@
VTHREAD_INJECTED_FIELDS(macro) \
INTERNALERROR_INJECTED_FIELDS(macro) \
STACKCHUNK_INJECTED_FIELDS(macro) \
CONSTANTPOOL_INJECTED_FIELDS(macro)
CONSTANTPOOL_INJECTED_FIELDS(macro) \
JFR_ONLY(FIELD_INJECTED_FIELDS(macro)) \
JFR_ONLY(JFR_EPOCH_INJECTED_FIELDS(macro))

#define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \
klass::_##name##_offset = JavaClasses::compute_injected_offset(InjectedFieldID::klass##_##name##_enum);
Expand Down
5 changes: 4 additions & 1 deletion src/hotspot/share/classfile/vmClassMacros.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2026, 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
Expand Down Expand Up @@ -193,6 +193,9 @@
/* Scoped Values */ \
do_klass(ScopedValue_Carrier_klass, java_lang_ScopedValue_Carrier ) \
\
/* Jfr */ \
JFR_ONLY(do_klass(jfrEpoch_klass, jdk_internal_event_JfrEpoch )) \
\
/*end*/

#endif // SHARE_CLASSFILE_VMCLASSMACROS_HPP
3 changes: 3 additions & 0 deletions src/hotspot/share/include/jvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,9 @@ JVM_FindScopedValueBindings(JNIEnv *env, jclass threadClass);
JNIEXPORT jlong JNICALL
JVM_GetNextThreadIdOffset(JNIEnv *env, jclass threadClass);

JNIEXPORT jboolean JNICALL
JVM_JfrEpochUpdate(JNIEnv* env, jclass jfrEpoch, jobject obj);

/*
* jdk.internal.vm.Continuation
*/
Expand Down
6 changes: 5 additions & 1 deletion src/hotspot/share/jfr/jfr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
Expand All @@ -44,7 +45,6 @@
#include "runtime/java.hpp"
#include "runtime/javaThread.hpp"


bool Jfr::is_enabled() {
return JfrRecorder::is_enabled();
}
Expand Down Expand Up @@ -181,6 +181,10 @@ void Jfr::on_report_java_out_of_memory() {
}
}

bool Jfr::update_epoch(oop oop) {
return JfrTraceIdEpoch::update(oop);
}

#if INCLUDE_CDS
void Jfr::on_restoration(const Klass* k, JavaThread* jt) {
assert(k != nullptr, "invariant");
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/jfr/jfr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class Jfr : AllStatic {
static bool has_sample_request(JavaThread* jt);
static void check_and_process_sample_request(JavaThread* jt);
static void on_report_java_out_of_memory();
static bool update_epoch(oop obj);
CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);)
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, 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
Expand Down Expand Up @@ -28,6 +28,7 @@
#include "jfr/utilities/jfrTypes.hpp"
#include "memory/allocation.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/atomicAccess.hpp"

template <typename T>
class JfrOopTraceId : AllStatic {
Expand All @@ -37,6 +38,7 @@ class JfrOopTraceId : AllStatic {
static u2 current_epoch();
static void set_epoch(oop ref);
static void set_epoch(oop ref, u2 epoch);
static bool cas_epoch(oop ref);
static bool is_excluded(oop ref);
static void exclude(oop ref);
static void include(oop ref);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, 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
Expand Down Expand Up @@ -57,6 +57,17 @@ inline void JfrOopTraceId<T>::set_epoch(oop ref) {
set_epoch(ref, JfrTraceIdEpoch::epoch_generation());
}

template <typename T>
inline bool JfrOopTraceId<T>::cas_epoch(oop ref) {
const int expected = epoch(ref);
const int current = current_epoch();
if (expected == current) {
return false;
}
int* const epoch_address = ref->field_addr<int>(T::epoch_offset());
return AtomicAccess::cmpxchg(epoch_address, expected, current) == expected;
}

template <typename T>
inline bool JfrOopTraceId<T>::is_excluded(oop ref) {
return T::is_excluded(ref);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2026, 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
Expand All @@ -22,6 +22,9 @@
*
*/

#include "classfile/javaClasses.inline.hpp"
#include "classfile/vmSymbols.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrOopTraceId.inline.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
#include "jfr/support/jfrThreadId.inline.hpp"
#include "runtime/atomicAccess.hpp"
Expand Down Expand Up @@ -65,3 +68,28 @@ void JfrTraceIdEpoch::reset_method_tracer_tag_state() {
bool JfrTraceIdEpoch::has_method_tracer_changed_tag_state() {
return AtomicAccess::load_acquire(&_method_tracer_state);
}

#ifdef ASSERT
static void assert_epoch_supported_type(oop obj) {
assert(obj != nullptr, "invariant");
assert(obj->is_instance(), "invariant");
const InstanceKlass* const ik = InstanceKlass::cast(obj->klass());
assert(ik != nullptr, "invariant");
vmSymbolID sid = vmSymbols::find_sid(ik->name());
assert(sid == vmSymbolID::java_lang_reflect_Field_enum ||
sid == vmSymbolID::jdk_internal_event_JfrEpoch_enum, "invariant");
}
#endif

// Switch on the vmSymbolID for dispatch.
bool JfrTraceIdEpoch::update(oop obj) {
DEBUG_ONLY(assert_epoch_supported_type(obj);)
const InstanceKlass* const ik = InstanceKlass::cast(obj->klass());
assert(ik != nullptr, "invariant");
const vmSymbolID sid = vmSymbols::find_sid(ik->name());
if (sid == vmSymbolID::java_lang_reflect_Field_enum) {
return JfrOopTraceId<java_lang_reflect_Field>::cas_epoch(obj);
}
assert(sid == vmSymbolID::jdk_internal_event_JfrEpoch_enum, "invariant");
return JfrOopTraceId<jdk_internal_event_JfrEpoch>::cas_epoch(obj);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2026, 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
Expand Down Expand Up @@ -135,6 +135,9 @@ class JfrTraceIdEpoch : AllStatic {
static void set_method_tracer_tag_state();
static void reset_method_tracer_tag_state();
static bool has_method_tracer_changed_tag_state();

static bool update(oop obj);

};

#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDEPOCH_HPP
Loading