8211238: @Deprecated JFR event

Reviewed-by: egahlin, jbachorik
This commit is contained in:
Markus Grönlund 2023-12-07 10:45:55 +00:00
parent 656b446289
commit 49fff0132b
67 changed files with 2227 additions and 321 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -198,6 +198,7 @@ public class GenerateJfrFiles {
String period = ""; String period = "";
boolean cutoff; boolean cutoff;
boolean throttle; boolean throttle;
String level = "";
boolean experimental; boolean experimental;
boolean internal; boolean internal;
long id; long id;
@ -222,6 +223,7 @@ public class GenerateJfrFiles {
pos.writeUTF(period); pos.writeUTF(period);
pos.writeBoolean(cutoff); pos.writeBoolean(cutoff);
pos.writeBoolean(throttle); pos.writeBoolean(throttle);
pos.writeUTF(level);
pos.writeBoolean(experimental); pos.writeBoolean(experimental);
pos.writeBoolean(internal); pos.writeBoolean(internal);
pos.writeLong(id); pos.writeLong(id);
@ -520,6 +522,7 @@ public class GenerateJfrFiles {
currentType.startTime = getBoolean(attributes, "startTime", true); currentType.startTime = getBoolean(attributes, "startTime", true);
currentType.period = getString(attributes, "period"); currentType.period = getString(attributes, "period");
currentType.cutoff = getBoolean(attributes, "cutoff", false); currentType.cutoff = getBoolean(attributes, "cutoff", false);
currentType.level = getString(attributes, "level");
currentType.throttle = getBoolean(attributes, "throttle", false); currentType.throttle = getBoolean(attributes, "throttle", false);
currentType.commitState = getString(attributes, "commitState"); currentType.commitState = getString(attributes, "commitState");
currentType.isEvent = "Event".equals(qName); currentType.isEvent = "Event".equals(qName);
@ -651,7 +654,7 @@ public class GenerateJfrFiles {
out.write(""); out.write("");
out.write("struct jfrNativeEventSetting {"); out.write("struct jfrNativeEventSetting {");
out.write(" jlong threshold_ticks;"); out.write(" jlong threshold_ticks;");
out.write(" jlong cutoff_ticks;"); out.write(" jlong miscellaneous;");
out.write(" u1 stacktrace;"); out.write(" u1 stacktrace;");
out.write(" u1 enabled;"); out.write(" u1 enabled;");
out.write(" u1 large;"); out.write(" u1 large;");

View File

@ -200,6 +200,7 @@ class ciMethod : public ciMetadata {
bool intrinsic_candidate() const { return get_Method()->intrinsic_candidate(); } bool intrinsic_candidate() const { return get_Method()->intrinsic_candidate(); }
bool is_static_initializer() const { return get_Method()->is_static_initializer(); } bool is_static_initializer() const { return get_Method()->is_static_initializer(); }
bool changes_current_thread() const { return get_Method()->changes_current_thread(); } bool changes_current_thread() const { return get_Method()->changes_current_thread(); }
bool deprecated() const { return is_loaded() && get_Method()->deprecated(); }
bool check_intrinsic_candidate() const { bool check_intrinsic_candidate() const {
if (intrinsic_id() == vmIntrinsics::_blackhole) { if (intrinsic_id() == vmIntrinsics::_blackhole) {

View File

@ -951,6 +951,8 @@ public:
_field_Stable, _field_Stable,
_jdk_internal_vm_annotation_ReservedStackAccess, _jdk_internal_vm_annotation_ReservedStackAccess,
_jdk_internal_ValueBased, _jdk_internal_ValueBased,
_java_lang_Deprecated,
_java_lang_Deprecated_for_removal,
_annotation_LIMIT _annotation_LIMIT
}; };
const Location _location; const Location _location;
@ -1122,6 +1124,7 @@ static void parse_annotations(const ConstantPool* const cp,
s_tag_val = 's', // payload is String s_tag_val = 's', // payload is String
s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;' s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
s_size = 9, s_size = 9,
b_tag_val = 'Z', // payload is boolean
min_size = 6 // smallest possible size (zero members) min_size = 6 // smallest possible size (zero members)
}; };
// Cannot add min_size to index in case of overflow MAX_INT // Cannot add min_size to index in case of overflow MAX_INT
@ -1144,6 +1147,32 @@ static void parse_annotations(const ConstantPool* const cp,
AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations); AnnotationCollector::ID id = coll->annotation_index(loader_data, aname, can_access_vm_annotations);
if (AnnotationCollector::_unknown == id) continue; if (AnnotationCollector::_unknown == id) continue;
coll->set_annotation(id); coll->set_annotation(id);
if (AnnotationCollector::_java_lang_Deprecated == id) {
assert(count <= 2, "change this if more element-value pairs are added to the @Deprecated annotation");
// @Deprecated can specify forRemoval=true
const u1* offset = abase + member_off;
for (int i = 0; i < count; ++i) {
int member_index = Bytes::get_Java_u2((address)offset);
offset += 2;
member = check_symbol_at(cp, member_index);
if (member == vmSymbols::since()) {
assert(*((address)offset) == s_tag_val, "invariant");
offset += 3;
continue;
}
if (member == vmSymbols::for_removal()) {
assert(*((address)offset) == b_tag_val, "invariant");
const u2 boolean_value_index = Bytes::get_Java_u2((address)offset + 1);
if (cp->int_at(boolean_value_index) == 1) {
// forRemoval == true
coll->set_annotation(AnnotationCollector::_java_lang_Deprecated_for_removal);
}
break;
}
}
continue;
}
if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) { if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
// @Contended can optionally specify the contention group. // @Contended can optionally specify the contention group.
@ -1959,6 +1988,9 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
if (!privileged) break; // only allow in privileged code if (!privileged) break; // only allow in privileged code
return _jdk_internal_ValueBased; return _jdk_internal_ValueBased;
} }
case VM_SYMBOL_ENUM_NAME(java_lang_Deprecated): {
return _java_lang_Deprecated;
}
default: { default: {
break; break;
} }
@ -2003,6 +2035,10 @@ void MethodAnnotationCollector::apply_to(const methodHandle& m) {
m->set_intrinsic_candidate(); m->set_intrinsic_candidate();
if (has_annotation(_jdk_internal_vm_annotation_ReservedStackAccess)) if (has_annotation(_jdk_internal_vm_annotation_ReservedStackAccess))
m->set_has_reserved_stack_access(); m->set_has_reserved_stack_access();
if (has_annotation(_java_lang_Deprecated))
m->set_deprecated();
if (has_annotation(_java_lang_Deprecated_for_removal))
m->set_deprecated_for_removal();
} }
void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) { void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
@ -2016,6 +2052,22 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
ik->set_is_value_based(); ik->set_is_value_based();
} }
} }
if (has_annotation(_java_lang_Deprecated)) {
Array<Method*>* methods = ik->methods();
int length = ik->methods()->length();
for (int i = 0; i < length; i++) {
Method* m = methods->at(i);
m->set_deprecated();
}
}
if (has_annotation(_java_lang_Deprecated_for_removal)) {
Array<Method*>* methods = ik->methods();
int length = ik->methods()->length();
for (int i = 0; i < length; i++) {
Method* m = methods->at(i);
m->set_deprecated_for_removal();
}
}
} }
#define MAX_ARGS_SIZE 255 #define MAX_ARGS_SIZE 255

View File

@ -162,7 +162,9 @@ class SerializeClosure;
template(jdk_internal_loader_BuiltinClassLoader, "jdk/internal/loader/BuiltinClassLoader") \ template(jdk_internal_loader_BuiltinClassLoader, "jdk/internal/loader/BuiltinClassLoader") \
template(jdk_internal_loader_ClassLoaders_AppClassLoader, "jdk/internal/loader/ClassLoaders$AppClassLoader") \ template(jdk_internal_loader_ClassLoaders_AppClassLoader, "jdk/internal/loader/ClassLoaders$AppClassLoader") \
template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \ template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
\ template(java_lang_Deprecated, "Ljava/lang/Deprecated;") \
template(since, "since") \
template(for_removal, "forRemoval") \
/* Java runtime version access */ \ /* Java runtime version access */ \
template(java_lang_VersionProps, "java/lang/VersionProps") \ template(java_lang_VersionProps, "java/lang/VersionProps") \
template(java_version_name, "java_version") \ template(java_version_name, "java_version") \

View File

@ -1,134 +0,0 @@
/*
* Copyright (c) 2022, 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 "ci/ciKlass.hpp"
#include "ci/ciMethod.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/instrumentation/jfrResolution.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
#include "oops/method.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/vframe.inline.hpp"
#ifdef COMPILER1
#include "c1/c1_GraphBuilder.hpp"
#endif
#ifdef COMPILER2
#include "opto/parse.hpp"
#endif
static const char* const link_error_msg = "illegal access linking method 'jdk.jfr.internal.event.EventWriterFactory.getEventWriter(long)'";
static const Method* ljf_sender_method(JavaThread* jt) {
assert(jt != nullptr, "invariant");
if (!jt->has_last_Java_frame()) {
return nullptr;
}
const vframeStream ljf(jt, false, false);
return ljf.method();
}
void JfrResolution::on_runtime_resolution(const CallInfo & info, TRAPS) {
assert(info.selected_method() != nullptr, "invariant");
assert(info.resolved_klass() != nullptr, "invariant");
static const Symbol* const event_writer_method_name = vmSymbols::getEventWriter_name();
assert(event_writer_method_name != nullptr, "invariant");
// Fast path
if (info.selected_method()->name() != event_writer_method_name) {
return;
}
static const Symbol* const event_writer_factory_klass_name = vmSymbols::jdk_jfr_internal_event_EventWriterFactory();
assert(event_writer_factory_klass_name != nullptr, "invariant");
if (info.resolved_klass()->name() != event_writer_factory_klass_name) {
return;
}
// Attempting to link against jdk.jfr.internal.event.EventWriterFactory.getEventWriter().
// The sender, i.e. the method attempting to link, is in the ljf (if one exists).
const Method* const sender = ljf_sender_method(THREAD);
if (sender == nullptr) {
// A compiler thread is doing linktime resolution but there is no information about the sender available.
// For the compiler threads, the sender is instead found as part of bytecode parsing.
return;
}
// Is the sender method blessed for linkage?
if (IS_METHOD_BLESSED(sender)) {
return;
}
#if INCLUDE_JVMCI
// JVMCI compiler is doing linktime resolution
if (sender->method_holder()->name() == vmSymbols::jdk_vm_ci_hotspot_CompilerToVM()) {
if (sender->name()->equals("lookupMethodInPool")) {
return;
}
}
#endif
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), link_error_msg);
}
static inline bool is_compiler_linking_event_writer(const Symbol* holder, const Symbol* name) {
static const Symbol* const event_writer_factory_klass_name = vmSymbols::jdk_jfr_internal_event_EventWriterFactory();
assert(event_writer_factory_klass_name != nullptr, "invariant");
if (holder != event_writer_factory_klass_name) {
return false;
}
static const Symbol* const event_writer_method_name = vmSymbols::getEventWriter_name();
assert(event_writer_method_name != nullptr, "invariant");
return name == event_writer_method_name;
}
static inline bool is_compiler_linking_event_writer(const ciKlass * holder, const ciMethod * target) {
assert(holder != nullptr, "invariant");
assert(target != nullptr, "invariant");
return is_compiler_linking_event_writer(holder->name()->get_symbol(), target->name()->get_symbol());
}
#ifdef COMPILER1
// C1
void JfrResolution::on_c1_resolution(const GraphBuilder * builder, const ciKlass * holder, const ciMethod * target) {
if (is_compiler_linking_event_writer(holder, target) && !IS_METHOD_BLESSED(builder->method()->get_Method())) {
builder->bailout(link_error_msg);
}
}
#endif
#ifdef COMPILER2
// C2
void JfrResolution::on_c2_resolution(const Parse * parse, const ciKlass * holder, const ciMethod * target) {
if (is_compiler_linking_event_writer(holder, target) && !IS_METHOD_BLESSED(parse->method()->get_Method())) {
parse->C->record_failure(link_error_msg);
}
}
#endif
#if INCLUDE_JVMCI
// JVMCI
void JfrResolution::on_jvmci_resolution(const Method* caller, const Method* target, TRAPS) {
if (is_compiler_linking_event_writer(target->method_holder()->name(), target->name())) {
if (caller == nullptr || !IS_METHOD_BLESSED(caller)) {
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), link_error_msg);
}
}
}
#endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,6 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "jfr/instrumentation/jfrResolution.hpp"
#include "jfr/jfr.hpp" #include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/leakProfiler.hpp"
@ -33,6 +32,7 @@
#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/support/jfrResolution.hpp"
#include "jfr/support/jfrThreadLocal.hpp" #include "jfr/support/jfrThreadLocal.hpp"
#include "runtime/java.hpp" #include "runtime/java.hpp"
@ -67,9 +67,7 @@ void Jfr::on_create_vm_3() {
} }
void Jfr::on_unloading_classes() { void Jfr::on_unloading_classes() {
if (JfrRecorder::is_created()) { JfrCheckpointManager::on_unloading_classes();
JfrCheckpointManager::on_unloading_classes();
}
} }
bool Jfr::is_excluded(Thread* t) { bool Jfr::is_excluded(Thread* t) {
@ -104,6 +102,10 @@ void Jfr::on_resolution(const CallInfo& info, TRAPS) {
JfrResolution::on_runtime_resolution(info, THREAD); JfrResolution::on_runtime_resolution(info, THREAD);
} }
void Jfr::on_backpatching(const Method* callee_method, JavaThread* jt) {
JfrResolution::on_backpatching(callee_method, jt);
}
#ifdef COMPILER1 #ifdef COMPILER1
void Jfr::on_resolution(const GraphBuilder* builder, const ciKlass* holder, const ciMethod* target) { void Jfr::on_resolution(const GraphBuilder* builder, const ciKlass* holder, const ciMethod* target) {
JfrResolution::on_c1_resolution(builder, holder, target); JfrResolution::on_c1_resolution(builder, holder, target);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -70,6 +70,7 @@ class Jfr : AllStatic {
static void on_vm_error_report(outputStream* st); static void on_vm_error_report(outputStream* st);
static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter);
static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter); static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter);
static void on_backpatching(const Method* callee_method, JavaThread* jt);
}; };
#endif // SHARE_JFR_JFR_HPP #endif // SHARE_JFR_JFR_HPP

View File

@ -45,6 +45,7 @@
#include "jfr/instrumentation/jfrEventClassTransformer.hpp" #include "jfr/instrumentation/jfrEventClassTransformer.hpp"
#include "jfr/instrumentation/jfrJvmtiAgent.hpp" #include "jfr/instrumentation/jfrJvmtiAgent.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrJdkJfrEvent.hpp" #include "jfr/support/jfrJdkJfrEvent.hpp"
#include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrKlassUnloading.hpp"
#include "jfr/utilities/jfrJavaLog.hpp" #include "jfr/utilities/jfrJavaLog.hpp"
@ -159,15 +160,19 @@ NO_TRANSITION(jdouble, jfr_time_conv_factor(JNIEnv* env, jclass jvm))
return (jdouble)JfrTimeConverter::nano_to_counter_multiplier(); return (jdouble)JfrTimeConverter::nano_to_counter_multiplier();
NO_TRANSITION_END NO_TRANSITION_END
NO_TRANSITION(jboolean, jfr_set_cutoff(JNIEnv* env, jclass jvm, jlong event_type_id, jlong cutoff_ticks))
return JfrEventSetting::set_cutoff(event_type_id, cutoff_ticks) ? JNI_TRUE : JNI_FALSE;
NO_TRANSITION_END
NO_TRANSITION(jboolean, jfr_set_throttle(JNIEnv* env, jclass jvm, jlong event_type_id, jlong event_sample_size, jlong period_ms)) NO_TRANSITION(jboolean, jfr_set_throttle(JNIEnv* env, jclass jvm, jlong event_type_id, jlong event_sample_size, jlong period_ms))
JfrEventThrottler::configure(static_cast<JfrEventId>(event_type_id), event_sample_size, period_ms); JfrEventThrottler::configure(static_cast<JfrEventId>(event_type_id), event_sample_size, period_ms);
return JNI_TRUE; return JNI_TRUE;
NO_TRANSITION_END NO_TRANSITION_END
NO_TRANSITION(void, jfr_set_miscellaneous(JNIEnv* env, jobject jvm, jlong event_type_id, jlong value))
JfrEventSetting::set_miscellaneous(event_type_id, value);
const JfrEventId typed_event_id = (JfrEventId)event_type_id;
if (EventDeprecatedInvocation::eventId == typed_event_id) {
JfrDeprecationManager::on_level_setting_update(value);
}
NO_TRANSITION_END
NO_TRANSITION(jboolean, jfr_should_rotate_disk(JNIEnv* env, jclass jvm)) NO_TRANSITION(jboolean, jfr_should_rotate_disk(JNIEnv* env, jclass jvm))
return JfrChunkRotation::should_rotate() ? JNI_TRUE : JNI_FALSE; return JfrChunkRotation::should_rotate() ? JNI_TRUE : JNI_FALSE;
NO_TRANSITION_END NO_TRANSITION_END

View File

@ -127,10 +127,10 @@ void JNICALL jfr_set_force_instrumentation(JNIEnv* env, jclass jvm, jboolean for
jlong JNICALL jfr_get_unloaded_event_classes_count(JNIEnv* env, jclass jvm); jlong JNICALL jfr_get_unloaded_event_classes_count(JNIEnv* env, jclass jvm);
jboolean JNICALL jfr_set_cutoff(JNIEnv* env, jclass jvm, jlong event_type_id, jlong cutoff_ticks);
jboolean JNICALL jfr_set_throttle(JNIEnv* env, jclass jvm, jlong event_type_id, jlong event_sample_size, jlong period_ms); jboolean JNICALL jfr_set_throttle(JNIEnv* env, jclass jvm, jlong event_type_id, jlong event_sample_size, jlong period_ms);
void JNICALL jfr_set_miscellaneous(JNIEnv* env, jobject jvm, jlong id, jlong value);
void JNICALL jfr_emit_old_object_samples(JNIEnv* env, jclass jvm, jlong cutoff_ticks, jboolean, jboolean); void JNICALL jfr_emit_old_object_samples(JNIEnv* env, jclass jvm, jlong cutoff_ticks, jboolean, jboolean);
jboolean JNICALL jfr_should_rotate_disk(JNIEnv* env, jclass jvm); jboolean JNICALL jfr_should_rotate_disk(JNIEnv* env, jclass jvm);

View File

@ -82,7 +82,7 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception, (char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception,
(char*)"setForceInstrumentation", (char*)"(Z)V", (void*)jfr_set_force_instrumentation, (char*)"setForceInstrumentation", (char*)"(Z)V", (void*)jfr_set_force_instrumentation,
(char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count, (char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count,
(char*)"setCutoff", (char*)"(JJ)Z", (void*)jfr_set_cutoff, (char*)"setMiscellaneous", (char*)"(JJ)V", (void*)jfr_set_miscellaneous,
(char*)"setThrottle", (char*)"(JJJ)Z", (void*)jfr_set_throttle, (char*)"setThrottle", (char*)"(JJJ)Z", (void*)jfr_set_throttle,
(char*)"emitOldObjectSamples", (char*)"(JZZ)V", (void*)jfr_emit_old_object_samples, (char*)"emitOldObjectSamples", (char*)"(JZZ)V", (void*)jfr_emit_old_object_samples,
(char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk, (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk,

View File

@ -416,9 +416,9 @@ static void install_type_set_blobs() {
iterate_samples(installer); iterate_samples(installer);
} }
static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) { static void save_type_set_blob(JfrCheckpointWriter& writer) {
assert(writer.has_data(), "invariant"); assert(writer.has_data(), "invariant");
const JfrBlobHandle blob = copy ? writer.copy() : writer.move(); const JfrBlobHandle blob = writer.copy();
if (saved_type_set_blobs.valid()) { if (saved_type_set_blobs.valid()) {
saved_type_set_blobs->set_next(blob); saved_type_set_blobs->set_next(blob);
} else { } else {
@ -438,9 +438,8 @@ void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
} }
void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) { void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
assert(LeakProfiler::is_running(), "invariant"); assert(LeakProfiler::is_running(), "invariant");
if (writer.has_data() && ObjectSampler::sampler()->last() != nullptr) { if (writer.has_data() && ObjectSampler::sampler()->last() != nullptr) {
save_type_set_blob(writer, true); save_type_set_blob(writer);
} }
} }

View File

@ -1252,6 +1252,13 @@
<Field type="string" name="path" label="Path" description="The path of the library" /> <Field type="string" name="path" label="Path" description="The path of the library" />
</Event> </Event>
<Event name="DeprecatedInvocation" description= "A unique invocation of a method that is annotated with @Deprecated. Packages and modules that are deprecated are ignored. At most 10 000 invocation sites and only the first invocation from a class is guaranteed to be included."
category="Java Application, Statistics" label="Deprecated Method Invocation" thread="false" stackTrace="true" startTime="false" level="forRemoval,all">
<Field type="Method" name="method" label="Deprecated Method" />
<Field type="Ticks" name="invocationTime" label="Invocation Time" description="The time the deprecated method was invoked for the first time" />
<Field type="boolean" name="forRemoval" label="For Removal" />
</Event>
<Type name="DeoptimizationReason" label="Deoptimization Reason"> <Type name="DeoptimizationReason" label="Deoptimization Reason">
<Field type="string" name="reason" label="Reason" /> <Field type="string" name="reason" label="Reason" />
</Type> </Type>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
@ -72,6 +72,7 @@
<xs:attribute name="period" type="periodType" use="optional" /> <xs:attribute name="period" type="periodType" use="optional" />
<xs:attribute name="cutoff" type="xs:boolean" use="optional" /> <xs:attribute name="cutoff" type="xs:boolean" use="optional" />
<xs:attribute name="throttle" type="xs:boolean" use="optional" /> <xs:attribute name="throttle" type="xs:boolean" use="optional" />
<xs:attribute name="level" type="xs:string" use="optional" />
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element maxOccurs="unbounded" name="Type"> <xs:element maxOccurs="unbounded" name="Type">

View File

@ -139,7 +139,7 @@ TRACE_REQUEST_FUNC(ModuleExport) {
/* /*
* This is left empty on purpose, having ExecutionSample as a requestable * This is left empty on purpose, having ExecutionSample as a requestable
* is a way of getting the period. The period is passed to ThreadSampling::update_period. * is a way of getting the period. The period is passed to ThreadSampling::update_period.
* Implementation in jfrSamples.cpp * Implementation in periodic/sampling/jfrThreadSampler.cpp.
*/ */
TRACE_REQUEST_FUNC(ExecutionSample) { TRACE_REQUEST_FUNC(ExecutionSample) {
} }

View File

@ -39,6 +39,7 @@
#include "jfr/recorder/storage/jfrMemorySpace.inline.hpp" #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp"
#include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp"
#include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrKlassUnloading.hpp"
#include "jfr/support/jfrThreadLocal.hpp" #include "jfr/support/jfrThreadLocal.hpp"
#include "jfr/utilities/jfrBigEndian.hpp" #include "jfr/utilities/jfrBigEndian.hpp"
@ -66,30 +67,24 @@ JfrCheckpointManager& JfrCheckpointManager::instance() {
return *_instance; return *_instance;
} }
JfrCheckpointManager* JfrCheckpointManager::create(JfrChunkWriter& cw) { JfrCheckpointManager* JfrCheckpointManager::create() {
assert(_instance == nullptr, "invariant"); assert(_instance == nullptr, "invariant");
_instance = new JfrCheckpointManager(cw); _instance = new JfrCheckpointManager();
return _instance; return _instance;
} }
void JfrCheckpointManager::destroy() { void JfrCheckpointManager::destroy() {
assert(_instance != nullptr, "invariant"); JfrTypeManager::destroy();
delete _instance; JfrTraceIdLoadBarrier::destroy();
_instance = nullptr;
} }
JfrCheckpointManager::JfrCheckpointManager(JfrChunkWriter& cw) : JfrCheckpointManager::JfrCheckpointManager() :
_global_mspace(nullptr), _global_mspace(nullptr),
_thread_local_mspace(nullptr), _thread_local_mspace(nullptr),
_virtual_thread_local_mspace(nullptr), _virtual_thread_local_mspace(nullptr),
_chunkwriter(cw) {} _chunkwriter(nullptr) {}
JfrCheckpointManager::~JfrCheckpointManager() { JfrCheckpointManager::~JfrCheckpointManager() {}
JfrTraceIdLoadBarrier::destroy();
JfrTypeManager::destroy();
delete _global_mspace;
delete _thread_local_mspace;
}
static const size_t global_buffer_prealloc_count = 2; static const size_t global_buffer_prealloc_count = 2;
static const size_t global_buffer_size = 512 * K; static const size_t global_buffer_size = 512 * K;
@ -100,7 +95,10 @@ static const size_t thread_local_buffer_size = 256;
static const size_t virtual_thread_local_buffer_prealloc_count = 0; static const size_t virtual_thread_local_buffer_prealloc_count = 0;
static const size_t virtual_thread_local_buffer_size = 4 * K; static const size_t virtual_thread_local_buffer_size = 4 * K;
bool JfrCheckpointManager::initialize() { // We expose an early initialization routine to support class unloading
// even though the full JFR system is not yet started. It requires
// backing of global buffers should it write a class unload type set blob.
bool JfrCheckpointManager::initialize_early() {
assert(_global_mspace == nullptr, "invariant"); assert(_global_mspace == nullptr, "invariant");
_global_mspace = create_mspace<JfrCheckpointMspace, JfrCheckpointManager>(global_buffer_size, 0, 0, false, this); // post-pone preallocation _global_mspace = create_mspace<JfrCheckpointMspace, JfrCheckpointManager>(global_buffer_size, 0, 0, false, this); // post-pone preallocation
if (_global_mspace == nullptr) { if (_global_mspace == nullptr) {
@ -131,9 +129,21 @@ bool JfrCheckpointManager::initialize() {
virtual_thread_local_buffer_prealloc_count)) { virtual_thread_local_buffer_prealloc_count)) {
return false; return false;
} }
return true;
}
// The instance is already created and so we only complete the setup of additional subsystems.
bool JfrCheckpointManager::initialize(JfrChunkWriter* cw) {
assert(cw != nullptr, "invariant");
_chunkwriter = cw;
return JfrTypeManager::initialize() && JfrTraceIdLoadBarrier::initialize(); return JfrTypeManager::initialize() && JfrTraceIdLoadBarrier::initialize();
} }
JfrChunkWriter& JfrCheckpointManager::chunkwriter() {
assert(_chunkwriter != nullptr, "invariant");
return *_chunkwriter;
}
#ifdef ASSERT #ifdef ASSERT
static void assert_lease(ConstBufferPtr buffer) { static void assert_lease(ConstBufferPtr buffer) {
if (buffer == nullptr) { if (buffer == nullptr) {
@ -502,7 +512,7 @@ void JfrCheckpointManager::end_epoch_shift() {
size_t JfrCheckpointManager::write() { size_t JfrCheckpointManager::write() {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(JavaThread::current())); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(JavaThread::current()));
WriteOperation wo(_chunkwriter); WriteOperation wo(chunkwriter());
MutexedWriteOperation mwo(wo); MutexedWriteOperation mwo(wo);
_thread_local_mspace->iterate(mwo, true); // previous epoch list _thread_local_mspace->iterate(mwo, true); // previous epoch list
assert(_global_mspace->free_list_is_empty(), "invariant"); assert(_global_mspace->free_list_is_empty(), "invariant");
@ -510,7 +520,7 @@ size_t JfrCheckpointManager::write() {
WriteReleaseOperation wro(&mwo, &ro); WriteReleaseOperation wro(&mwo, &ro);
process_live_list(wro, _global_mspace, true); // previous epoch list process_live_list(wro, _global_mspace, true); // previous epoch list
// Do virtual thread local list last. Careful, the vtlco destructor writes to chunk. // Do virtual thread local list last. Careful, the vtlco destructor writes to chunk.
VirtualThreadLocalCheckpointOperation vtlco(_chunkwriter); VirtualThreadLocalCheckpointOperation vtlco(chunkwriter());
VirtualThreadLocalWriteOperation vtlwo(vtlco); VirtualThreadLocalWriteOperation vtlwo(vtlco);
_virtual_thread_local_mspace->iterate(vtlwo, true); // previous epoch list _virtual_thread_local_mspace->iterate(vtlwo, true); // previous epoch list
return wo.processed() + vtlco.processed(); return wo.processed() + vtlco.processed();
@ -534,7 +544,7 @@ size_t JfrCheckpointManager::clear() {
size_t JfrCheckpointManager::write_static_type_set(Thread* thread) { size_t JfrCheckpointManager::write_static_type_set(Thread* thread) {
assert(thread != nullptr, "invariant"); assert(thread != nullptr, "invariant");
JfrCheckpointWriter writer(true, thread, STATICS); JfrCheckpointWriter writer(true /* prev epoch */, thread, true /* header */, STATICS);
JfrTypeManager::write_static_types(writer); JfrTypeManager::write_static_types(writer);
return writer.used_size(); return writer.used_size();
} }
@ -545,7 +555,7 @@ size_t JfrCheckpointManager::write_threads(JavaThread* thread) {
ThreadInVMfromNative transition(thread); ThreadInVMfromNative transition(thread);
ResourceMark rm(thread); ResourceMark rm(thread);
HandleMark hm(thread); HandleMark hm(thread);
JfrCheckpointWriter writer(true, thread, THREADS); JfrCheckpointWriter writer(true /* prev epoch */, thread, true /* header */, THREADS);
JfrTypeManager::write_threads(writer); JfrTypeManager::write_threads(writer);
return writer.used_size(); return writer.used_size();
} }
@ -566,13 +576,26 @@ void JfrCheckpointManager::on_rotation() {
void JfrCheckpointManager::clear_type_set() { void JfrCheckpointManager::clear_type_set() {
assert(!JfrRecorder::is_recording(), "invariant"); assert(!JfrRecorder::is_recording(), "invariant");
JavaThread* t = JavaThread::current(); JavaThread* thread = JavaThread::current();
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(t)); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread));
// can safepoint here // can safepoint here
ThreadInVMfromNative transition(t); ThreadInVMfromNative transition(thread);
MutexLocker cld_lock(ClassLoaderDataGraph_lock); MutexLocker cld_lock(thread, ClassLoaderDataGraph_lock);
MutexLocker module_lock(Module_lock); // Marks leakp. Place prepare_type_set before writer construction.
JfrTypeSet::clear(); JfrDeprecationManager::prepare_type_set(thread);
JfrCheckpointWriter leakp_writer(true /* prev epoch */, thread);
JfrCheckpointWriter writer(true /* prev epoch */, thread);
{
MutexLocker module_lock(Module_lock);
JfrTypeSet::clear(&writer, &leakp_writer);
}
JfrDeprecationManager::on_type_set(leakp_writer, nullptr, thread);
// We placed a blob in the Deprecated subsystem by moving the information
// from the leakp writer. For the real writer, the data will not be
// committed, because the JFR system is yet to be started.
// Therefore, the writer is cancelled before its destructor is run,
// to avoid writing unnecessary information into the checkpoint system.
writer.cancel();
} }
void JfrCheckpointManager::write_type_set() { void JfrCheckpointManager::write_type_set() {
@ -582,16 +605,19 @@ void JfrCheckpointManager::write_type_set() {
// can safepoint here // can safepoint here
ThreadInVMfromNative transition(thread); ThreadInVMfromNative transition(thread);
MutexLocker cld_lock(thread, ClassLoaderDataGraph_lock); MutexLocker cld_lock(thread, ClassLoaderDataGraph_lock);
MutexLocker module_lock(thread, Module_lock); // Marks leakp. Place prepare_type_set before writer construction.
if (LeakProfiler::is_running()) { JfrDeprecationManager::prepare_type_set(thread);
JfrCheckpointWriter leakp_writer(true, thread); JfrCheckpointWriter leakp_writer(true /* prev epoch */, thread);
JfrCheckpointWriter writer(true, thread); JfrCheckpointWriter writer(true /* prev epoch */, thread);
{
MutexLocker module_lock(thread, Module_lock);
JfrTypeSet::serialize(&writer, &leakp_writer, false, false); JfrTypeSet::serialize(&writer, &leakp_writer, false, false);
ObjectSampleCheckpoint::on_type_set(leakp_writer);
} else {
JfrCheckpointWriter writer(true, thread);
JfrTypeSet::serialize(&writer, nullptr, false, false);
} }
if (LeakProfiler::is_running()) {
ObjectSampleCheckpoint::on_type_set(leakp_writer);
}
// Place this call after ObjectSampleCheckpoint::on_type_set.
JfrDeprecationManager::on_type_set(leakp_writer, _chunkwriter, thread);
} }
write(); write();
} }
@ -603,6 +629,7 @@ void JfrCheckpointManager::on_unloading_classes() {
if (LeakProfiler::is_running()) { if (LeakProfiler::is_running()) {
ObjectSampleCheckpoint::on_type_set_unload(writer); ObjectSampleCheckpoint::on_type_set_unload(writer);
} }
JfrDeprecationManager::on_type_set_unload(writer);
} }
static size_t flush_type_set(Thread* thread) { static size_t flush_type_set(Thread* thread) {
@ -626,14 +653,14 @@ size_t JfrCheckpointManager::flush_type_set() {
} }
} }
if (_new_checkpoint.is_signaled_with_reset()) { if (_new_checkpoint.is_signaled_with_reset()) {
WriteOperation wo(_chunkwriter); WriteOperation wo(chunkwriter());
MutexedWriteOperation mwo(wo); MutexedWriteOperation mwo(wo);
_thread_local_mspace->iterate(mwo); // current epoch list _thread_local_mspace->iterate(mwo); // current epoch list
assert(_global_mspace->free_list_is_empty(), "invariant"); assert(_global_mspace->free_list_is_empty(), "invariant");
assert(_global_mspace->live_list_is_nonempty(), "invariant"); assert(_global_mspace->live_list_is_nonempty(), "invariant");
process_live_list(mwo, _global_mspace); // current epoch list process_live_list(mwo, _global_mspace); // current epoch list
// Do virtual thread local list last. Careful, the vtlco destructor writes to chunk. // Do virtual thread local list last. Careful, the vtlco destructor writes to chunk.
VirtualThreadLocalCheckpointOperation vtlco(_chunkwriter); VirtualThreadLocalCheckpointOperation vtlco(chunkwriter());
VirtualThreadLocalWriteOperation vtlwo(vtlco); VirtualThreadLocalWriteOperation vtlwo(vtlco);
_virtual_thread_local_mspace->iterate(vtlwo); // current epoch list _virtual_thread_local_mspace->iterate(vtlwo); // current epoch list
} }

View File

@ -62,15 +62,18 @@ class JfrCheckpointManager : public JfrCHeapObj {
JfrCheckpointMspace* _global_mspace; JfrCheckpointMspace* _global_mspace;
JfrThreadLocalCheckpointMspace* _thread_local_mspace; JfrThreadLocalCheckpointMspace* _thread_local_mspace;
JfrThreadLocalCheckpointMspace* _virtual_thread_local_mspace; JfrThreadLocalCheckpointMspace* _virtual_thread_local_mspace;
JfrChunkWriter& _chunkwriter; JfrChunkWriter* _chunkwriter;
JfrCheckpointManager(JfrChunkWriter& cw); JfrCheckpointManager();
~JfrCheckpointManager(); ~JfrCheckpointManager();
static JfrCheckpointManager& instance(); static JfrCheckpointManager& instance();
static JfrCheckpointManager* create(JfrChunkWriter& cw); static JfrCheckpointManager* create();
bool initialize(); bool initialize_early();
bool initialize(JfrChunkWriter* cw);
static void destroy(); static void destroy();
JfrChunkWriter& chunkwriter();
static BufferPtr get_virtual_thread_local(Thread* thread); static BufferPtr get_virtual_thread_local(Thread* thread);
static void set_virtual_thread_local(Thread* thread, BufferPtr buffer); static void set_virtual_thread_local(Thread* thread, BufferPtr buffer);
static BufferPtr acquire_virtual_thread_local(Thread* thread, size_t size); static BufferPtr acquire_virtual_thread_local(Thread* thread, size_t size);

View File

@ -60,13 +60,13 @@ JfrCheckpointWriter::JfrCheckpointWriter(Thread* thread, bool header /* true */,
} }
} }
JfrCheckpointWriter::JfrCheckpointWriter(bool previous_epoch, Thread* thread, JfrCheckpointType type /* GENERIC */) : JfrCheckpointWriter::JfrCheckpointWriter(bool previous_epoch, Thread* thread, bool header /* true */, JfrCheckpointType type /* GENERIC */) :
JfrCheckpointWriterBase(JfrCheckpointManager::lease_global(thread, previous_epoch), thread), JfrCheckpointWriterBase(JfrCheckpointManager::lease_global(thread, previous_epoch), thread),
_time(JfrTicks::now()), _time(JfrTicks::now()),
_offset(0), _offset(0),
_count(0), _count(0),
_type(type), _type(type),
_header(true) { _header(header) {
assert(this->is_acquired(), "invariant"); assert(this->is_acquired(), "invariant");
assert(0 == this->current_offset(), "invariant"); assert(0 == this->current_offset(), "invariant");
if (_header) { if (_header) {
@ -162,8 +162,10 @@ const u1* JfrCheckpointWriter::session_data(size_t* size, bool move /* false */,
} }
*size = this->used_size(); *size = this->used_size();
assert(this->start_pos() + *size == this->current_pos(), "invariant"); assert(this->start_pos() + *size == this->current_pos(), "invariant");
write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, (u4)_type, count()); if (_header) {
_header = false; // the header was just written write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, (u4)_type, count());
_header = false; // the header was just written
}
if (move) { if (move) {
this->seek(_offset); this->seek(_offset);
} }

View File

@ -69,8 +69,8 @@ class JfrCheckpointWriter : public JfrCheckpointWriterBase {
void increment(); void increment();
const u1* session_data(size_t* size, bool move = false, const JfrCheckpointContext* ctx = nullptr); const u1* session_data(size_t* size, bool move = false, const JfrCheckpointContext* ctx = nullptr);
void release(); void release();
JfrCheckpointWriter(bool previous_epoch, Thread* thread, JfrCheckpointType type = GENERIC); public:
public: JfrCheckpointWriter(bool previous_epoch, Thread* thread, bool header = true, JfrCheckpointType type = GENERIC);
JfrCheckpointWriter(bool header = true, JfrCheckpointType mode = GENERIC, JfrCheckpointBufferKind kind = JFR_GLOBAL); JfrCheckpointWriter(bool header = true, JfrCheckpointType mode = GENERIC, JfrCheckpointBufferKind kind = JFR_GLOBAL);
JfrCheckpointWriter(Thread* thread, bool header = true, JfrCheckpointType mode = GENERIC, JfrCheckpointBufferKind kind = JFR_GLOBAL); JfrCheckpointWriter(Thread* thread, bool header = true, JfrCheckpointType mode = GENERIC, JfrCheckpointBufferKind kind = JFR_GLOBAL);
~JfrCheckpointWriter(); ~JfrCheckpointWriter();

View File

@ -286,15 +286,6 @@ static bool register_klass_unload(Klass* klass) {
return JfrKlassUnloading::on_unload(klass); return JfrKlassUnloading::on_unload(klass);
} }
static void on_klass_unload(Klass* klass) {
register_klass_unload(klass);
}
static size_t register_unloading_klasses() {
ClassLoaderDataGraph::classes_unloading_do(&on_klass_unload);
return 0;
}
static void do_unloading_klass(Klass* klass) { static void do_unloading_klass(Klass* klass) {
assert(klass != nullptr, "invariant"); assert(klass != nullptr, "invariant");
assert(_subsystem_callback != nullptr, "invariant"); assert(_subsystem_callback != nullptr, "invariant");
@ -362,6 +353,63 @@ static void do_klasses() {
do_object(); do_object();
} }
template <typename T>
static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) {
assert(callback != nullptr, "invariant");
assert(value != nullptr, "invariant");
if (USED_PREVIOUS_EPOCH(value)) {
callback->do_artifact(value);
}
if (IS_SERIALIZED(value)) {
CLEAR_SERIALIZED(value);
}
assert(IS_NOT_SERIALIZED(value), "invariant");
}
static void do_previous_epoch_klass(JfrArtifactClosure* callback, const Klass* value) {
assert(callback != nullptr, "invariant");
assert(value != nullptr, "invariant");
if (USED_PREVIOUS_EPOCH(value)) {
callback->do_artifact(value);
}
}
static void do_klass_on_clear(Klass* klass) {
assert(klass != nullptr, "invariant");
assert(_subsystem_callback != nullptr, "invariant");
do_previous_epoch_klass(_subsystem_callback, klass);
}
static void do_loader_klass_on_clear(const Klass* klass) {
if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) {
if (_leakp_writer != nullptr) {
SET_LEAKP(klass);
}
SET_TRANSIENT(klass);
do_previous_epoch_klass(_subsystem_callback, klass);
}
}
static void do_classloaders_on_clear() {
for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) {
Klass* subk = iter.klass();
if (is_classloader_klass_allowed(subk)) {
do_loader_klass_on_clear(subk);
}
}
}
static void do_object_on_clear() {
SET_TRANSIENT(vmClasses::Object_klass());
do_klass_on_clear(vmClasses::Object_klass());
}
static void do_all_klasses() {
ClassLoaderDataGraph::classes_do(&do_klass_on_clear);
do_classloaders_on_clear();
do_object_on_clear();
}
typedef SerializePredicate<KlassPtr> KlassPredicate; typedef SerializePredicate<KlassPtr> KlassPredicate;
typedef JfrPredicatedTypeWriterImplHost<KlassPtr, KlassPredicate, write__klass> KlassWriterImpl; typedef JfrPredicatedTypeWriterImplHost<KlassPtr, KlassPredicate, write__klass> KlassWriterImpl;
typedef JfrTypeWriterHost<KlassWriterImpl, TYPE_CLASS> KlassWriter; typedef JfrTypeWriterHost<KlassWriterImpl, TYPE_CLASS> KlassWriter;
@ -414,32 +462,23 @@ static bool write_klasses() {
return true; return true;
} }
template <typename T> static bool write_klasses_on_clear() {
static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) {
assert(callback != nullptr, "invariant");
assert(value != nullptr, "invariant");
if (USED_PREVIOUS_EPOCH(value)) {
callback->do_artifact(value);
}
if (IS_SERIALIZED(value)) {
CLEAR_SERIALIZED(value);
}
assert(IS_NOT_SERIALIZED(value), "invariant");
}
typedef JfrArtifactCallbackHost<KlassPtr, KlassArtifactRegistrator> RegisterKlassCallback;
static void register_klass(Klass* klass) {
assert(klass != nullptr, "invariant");
assert(_subsystem_callback != nullptr, "invariant");
do_previous_epoch_artifact(_subsystem_callback, klass);
}
static void register_klasses() {
assert(!_artifacts->has_klass_entries(), "invariant"); assert(!_artifacts->has_klass_entries(), "invariant");
assert(_writer != nullptr, "invariant");
assert(_leakp_writer != nullptr, "invariant");
KlassArtifactRegistrator reg(_artifacts); KlassArtifactRegistrator reg(_artifacts);
RegisterKlassCallback callback(&_subsystem_callback, &reg); KlassWriter kw(_writer, _class_unload);
ClassLoaderDataGraph::classes_do(&register_klass); KlassWriterRegistration kwr(&kw, &reg);
LeakKlassWriter lkw(_leakp_writer, _class_unload);
CompositeKlassWriter ckw(&lkw, &kw);
CompositeKlassWriterRegistration ckwr(&ckw, &reg);
CompositeKlassCallback callback(&_subsystem_callback, &ckwr);
do_all_klasses();
if (is_complete()) {
return false;
}
_artifacts->tally(kw);
return true;
} }
static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) {
@ -530,12 +569,21 @@ static void write_packages() {
_artifacts->tally(pw); _artifacts->tally(pw);
} }
typedef JfrArtifactCallbackHost<PkgPtr, ClearArtifact<PkgPtr> > ClearPackageCallback; static void write_packages_on_clear() {
assert(_writer != nullptr, "invariant");
static void clear_packages() { assert(_leakp_writer != nullptr, "invariant");
assert(previous_epoch(), "invariant");
PackageWriter pw(_writer, _class_unload);
KlassPackageWriter kpw(&pw);
LeakPackageWriter lpw(_leakp_writer, _class_unload);
CompositePackageWriter cpw(&lpw, &pw);
KlassCompositePackageWriter kcpw(&cpw);
_artifacts->iterate_klasses(kcpw);
ClearArtifact<PkgPtr> clear; ClearArtifact<PkgPtr> clear;
ClearPackageCallback callback(&_subsystem_callback, &clear); CompositePackageWriterWithClear cpwwc(&cpw, &clear);
CompositePackageCallback callback(&_subsystem_callback, &cpwwc);
do_packages(); do_packages();
_artifacts->tally(pw);
} }
static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) {
@ -626,12 +674,21 @@ static void write_modules() {
_artifacts->tally(mw); _artifacts->tally(mw);
} }
typedef JfrArtifactCallbackHost<ModPtr, ClearArtifact<ModPtr> > ClearModuleCallback; static void write_modules_on_clear() {
assert(_writer != nullptr, "invariant");
static void clear_modules() { assert(_leakp_writer != nullptr, "invariant");
assert(previous_epoch(), "invariant");
ModuleWriter mw(_writer, _class_unload);
KlassModuleWriter kmw(&mw);
LeakModuleWriter lmw(_leakp_writer, _class_unload);
CompositeModuleWriter cmw(&lmw, &mw);
KlassCompositeModuleWriter kcpw(&cmw);
_artifacts->iterate_klasses(kcpw);
ClearArtifact<ModPtr> clear; ClearArtifact<ModPtr> clear;
ClearModuleCallback callback(&_subsystem_callback, &clear); CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
CompositeModuleCallback callback(&_subsystem_callback, &cmwwc);
do_modules(); do_modules();
_artifacts->tally(mw);
} }
static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) {
@ -759,12 +816,24 @@ static void write_classloaders() {
_artifacts->tally(cldw); _artifacts->tally(cldw);
} }
typedef JfrArtifactCallbackHost<CldPtr, ClearArtifact<CldPtr> > ClearCLDCallback; static void write_classloaders_on_clear() {
assert(_writer != nullptr, "invariant");
static void clear_classloaders() { assert(_leakp_writer != nullptr, "invariant");
CldWriter cldw(_writer, _class_unload);
KlassCldWriter kcw(&cldw);
ModuleCldWriter mcw(&cldw);
KlassAndModuleCldWriter kmcw(&kcw, &mcw);
LeakCldWriter lcldw(_leakp_writer, _class_unload);
CompositeCldWriter ccldw(&lcldw, &cldw);
KlassCompositeCldWriter kccldw(&ccldw);
ModuleCompositeCldWriter mccldw(&ccldw);
KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw);
_artifacts->iterate_klasses(kmccldw);
ClearArtifact<CldPtr> clear; ClearArtifact<CldPtr> clear;
ClearCLDCallback callback(&_subsystem_callback, &clear); CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
CompositeCldCallback callback(&_subsystem_callback, &ccldwwc);
do_class_loaders(); do_class_loaders();
_artifacts->tally(cldw);
} }
static u1 get_visibility(MethodPtr method) { static u1 get_visibility(MethodPtr method) {
@ -776,7 +845,7 @@ template <>
void set_serialized<Method>(MethodPtr method) { void set_serialized<Method>(MethodPtr method) {
assert(method != nullptr, "invariant"); assert(method != nullptr, "invariant");
SET_METHOD_SERIALIZED(method); SET_METHOD_SERIALIZED(method);
assert(IS_METHOD_SERIALIZED(method), "invariant"); assert(METHOD_IS_SERIALIZED(method), "invariant");
if (current_epoch()) { if (current_epoch()) {
CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method);
} }
@ -917,6 +986,17 @@ static void write_methods() {
_artifacts->tally(mw); _artifacts->tally(mw);
} }
static void write_methods_on_clear() {
assert(_writer != nullptr, "invariant");
assert(_leakp_writer != nullptr, "invariant");
assert(previous_epoch(), "invariant");
MethodWriter mw(_writer, current_epoch(), _class_unload);
LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload);
CompositeMethodWriter cmw(&lpmw, &mw);
_artifacts->iterate_klasses(cmw);
_artifacts->tally(mw);
}
template <> template <>
void set_serialized<JfrSymbolTable::SymbolEntry>(SymbolEntryPtr ptr) { void set_serialized<JfrSymbolTable::SymbolEntry>(SymbolEntryPtr ptr) {
assert(ptr != nullptr, "invariant"); assert(ptr != nullptr, "invariant");
@ -1005,6 +1085,23 @@ static void write_symbols_with_leakp() {
_artifacts->tally(sw); _artifacts->tally(sw);
} }
static void write_symbols_on_clear() {
assert(_writer != nullptr, "invariant");
assert(_leakp_writer != nullptr, "invariant");
assert(previous_epoch(), "invariant");
SymbolEntryWriter sw(_writer, _class_unload);
LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload);
CompositeSymbolWriter csw(&lsw, &sw);
_artifacts->iterate_symbols(csw);
StringEntryWriter sew(_writer, _class_unload, true); // skip header
LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header
CompositeStringWriter csew(&lsew, &sew);
_artifacts->iterate_strings(csew);
sw.add(sew.count());
lsw.add(lsew.count());
_artifacts->tally(sw);
}
static void write_symbols() { static void write_symbols() {
assert(_writer != nullptr, "invariant"); assert(_writer != nullptr, "invariant");
if (_leakp_writer != nullptr) { if (_leakp_writer != nullptr) {
@ -1082,18 +1179,16 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l
/** /**
* Clear all tags from the previous epoch. * Clear all tags from the previous epoch.
*/ */
void JfrTypeSet::clear() { void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
ResourceMark rm; ResourceMark rm;
JfrKlassUnloading::clear(); setup(writer, leakp_writer, false, false);
if (_artifacts != nullptr) { write_klasses_on_clear();
_artifacts->clear(); write_packages_on_clear();
} write_modules_on_clear();
setup(nullptr, nullptr, false, false); write_classloaders_on_clear();
register_klasses(); write_methods_on_clear();
clear_packages(); write_symbols_on_clear();
clear_modules(); teardown();
clear_classloaders();
clear_klasses_and_methods();
} }
size_t JfrTypeSet::on_unloading_classes(JfrCheckpointWriter* writer) { size_t JfrTypeSet::on_unloading_classes(JfrCheckpointWriter* writer) {
@ -1101,8 +1196,5 @@ size_t JfrTypeSet::on_unloading_classes(JfrCheckpointWriter* writer) {
// The JfrRecorderThread does this as part of normal processing, but with concurrent class unloading, which can // The JfrRecorderThread does this as part of normal processing, but with concurrent class unloading, which can
// happen in arbitrary threads, we invoke it explicitly. // happen in arbitrary threads, we invoke it explicitly.
JfrTraceIdEpoch::has_changed_tag_state_no_reset(); JfrTraceIdEpoch::has_changed_tag_state_no_reset();
if (JfrRecorder::is_recording()) { return serialize(writer, nullptr, true, false);
return serialize(writer, nullptr, true, false);
}
return register_unloading_klasses();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,7 @@ class JfrCheckpointWriter;
class JfrTypeSet : AllStatic { class JfrTypeSet : AllStatic {
public: public:
static void clear(); static void clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
static size_t serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload, bool flushpoint); static size_t serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload, bool flushpoint);
static size_t on_unloading_classes(JfrCheckpointWriter* writer); static size_t on_unloading_classes(JfrCheckpointWriter* writer);
}; };

View File

@ -91,6 +91,8 @@ class ClearArtifact {
bool operator()(T const& value) { bool operator()(T const& value) {
CLEAR_SERIALIZED(value); CLEAR_SERIALIZED(value);
assert(IS_NOT_SERIALIZED(value), "invariant"); assert(IS_NOT_SERIALIZED(value), "invariant");
assert(IS_NOT_LEAKP(value), "invariant");
assert(IS_NOT_TRANSIENT(value), "invariant");
SET_PREVIOUS_EPOCH_CLEARED_BIT(value); SET_PREVIOUS_EPOCH_CLEARED_BIT(value);
CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(value); CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(value);
return true; return true;
@ -103,7 +105,9 @@ class ClearArtifact<const Method*> {
bool operator()(const Method* method) { bool operator()(const Method* method) {
assert(METHOD_FLAG_USED_PREVIOUS_EPOCH(method), "invariant"); assert(METHOD_FLAG_USED_PREVIOUS_EPOCH(method), "invariant");
CLEAR_SERIALIZED_METHOD(method); CLEAR_SERIALIZED_METHOD(method);
assert(METHOD_NOT_SERIALIZED(method), "invariant"); assert(METHOD_IS_NOT_SERIALIZED(method), "invariant");
assert(METHOD_IS_NOT_LEAKP(method), "invariant");
assert(METHOD_IS_NOT_TRANSIENT(method), "invariant");
SET_PREVIOUS_EPOCH_METHOD_CLEARED_BIT(method); SET_PREVIOUS_EPOCH_METHOD_CLEARED_BIT(method);
CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method); CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method);
return true; return true;
@ -128,7 +132,7 @@ class SerializePredicate<const Method*> {
SerializePredicate(bool class_unload) : _class_unload(class_unload) {} SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
bool operator()(const Method* method) { bool operator()(const Method* method) {
assert(method != nullptr, "invariant"); assert(method != nullptr, "invariant");
return _class_unload ? true : METHOD_NOT_SERIALIZED(method); return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method);
} }
}; };
@ -162,9 +166,9 @@ class MethodFlagPredicate {
MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {} MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
bool operator()(const Method* method) { bool operator()(const Method* method) {
if (_current_epoch) { if (_current_epoch) {
return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_THIS_EPOCH(method); return leakp ? METHOD_IS_LEAKP(method) : METHOD_FLAG_USED_THIS_EPOCH(method);
} }
return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_PREVIOUS_EPOCH(method); return leakp ? METHOD_IS_LEAKP(method) : METHOD_FLAG_USED_PREVIOUS_EPOCH(method);
} }
}; };
@ -183,7 +187,7 @@ class LeakPredicate<const Method*> {
LeakPredicate(bool class_unload) {} LeakPredicate(bool class_unload) {}
bool operator()(const Method* method) { bool operator()(const Method* method) {
assert(method != nullptr, "invariant"); assert(method != nullptr, "invariant");
return IS_METHOD_LEAKP_USED(method); return METHOD_IS_LEAKP(method);
} }
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -93,6 +93,9 @@ class JfrTraceId : public AllStatic {
static traceid load(const PackageEntry* package); static traceid load(const PackageEntry* package);
static traceid load(const ClassLoaderData* cld); static traceid load(const ClassLoaderData* cld);
static traceid load_leakp(const Klass* klass, const Method* method); // leak profiler static traceid load_leakp(const Klass* klass, const Method* method); // leak profiler
static traceid load_leakp_previous_epoch(const Klass* klass, const Method* method); // leak profiler
static traceid load_no_enqueue(const Method* method);
static traceid load_no_enqueue(const Klass* klass, const Method* method);
// load barrier elision // load barrier elision
static traceid load_raw(const Klass* klass); static traceid load_raw(const Klass* klass);

View File

@ -44,10 +44,18 @@ inline traceid JfrTraceId::load(const Method* method) {
return JfrTraceIdLoadBarrier::load(method); return JfrTraceIdLoadBarrier::load(method);
} }
inline traceid JfrTraceId::load_no_enqueue(const Method* method) {
return JfrTraceIdLoadBarrier::load_no_enqueue(method);
}
inline traceid JfrTraceId::load(const Klass* klass, const Method* method) { inline traceid JfrTraceId::load(const Klass* klass, const Method* method) {
return JfrTraceIdLoadBarrier::load(klass, method); return JfrTraceIdLoadBarrier::load(klass, method);
} }
inline traceid JfrTraceId::load_no_enqueue(const Klass* klass, const Method* method) {
return JfrTraceIdLoadBarrier::load_no_enqueue(klass, method);
}
inline traceid JfrTraceId::load(const ModuleEntry* module) { inline traceid JfrTraceId::load(const ModuleEntry* module) {
return JfrTraceIdLoadBarrier::load(module); return JfrTraceIdLoadBarrier::load(module);
} }
@ -64,6 +72,10 @@ inline traceid JfrTraceId::load_leakp(const Klass* klass, const Method* method)
return JfrTraceIdLoadBarrier::load_leakp(klass, method); return JfrTraceIdLoadBarrier::load_leakp(klass, method);
} }
inline traceid JfrTraceId::load_leakp_previous_epoch(const Klass* klass, const Method* method) {
return JfrTraceIdLoadBarrier::load_leakp_previuos_epoch(klass, method);
}
template <typename T> template <typename T>
inline traceid raw_load(const T* t) { inline traceid raw_load(const T* t) {
assert(t != nullptr, "invariant"); assert(t != nullptr, "invariant");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -88,7 +88,10 @@ class JfrTraceIdLoadBarrier : AllStatic {
static traceid load(const ModuleEntry* module); static traceid load(const ModuleEntry* module);
static traceid load(const PackageEntry* package); static traceid load(const PackageEntry* package);
static traceid load_leakp(const Klass* klass, const Method* method); // leak profiler static traceid load_leakp(const Klass* klass, const Method* method); // leak profiler
static traceid load_leakp_previuos_epoch(const Klass* klass, const Method* method); // leak profiler
static void do_klasses(void f(Klass*), bool previous_epoch = false); static void do_klasses(void f(Klass*), bool previous_epoch = false);
static traceid load_no_enqueue(const Klass* klass, const Method* method);
static traceid load_no_enqueue(const Method* method);
}; };
#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDLOADBARRIER_HPP #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDLOADBARRIER_HPP

View File

@ -99,6 +99,20 @@ inline traceid JfrTraceIdLoadBarrier::load(const Klass* klass, const Method* met
return (METHOD_ID(klass, method)); return (METHOD_ID(klass, method));
} }
inline traceid JfrTraceIdLoadBarrier::load_no_enqueue(const Method* method) {
return load_no_enqueue(method->method_holder(), method);
}
inline traceid JfrTraceIdLoadBarrier::load_no_enqueue(const Klass* klass, const Method* method) {
assert(klass != nullptr, "invariant");
assert(method != nullptr, "invariant");
SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass);
SET_METHOD_FLAG_USED_THIS_EPOCH(method);
assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
assert(METHOD_FLAG_USED_THIS_EPOCH(method), "invariant");
return (METHOD_ID(klass, method));
}
inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) { inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) {
return set_used_and_get(module); return set_used_and_get(module);
} }
@ -136,4 +150,21 @@ inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Metho
return (METHOD_ID(klass, method)); return (METHOD_ID(klass, method));
} }
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");
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*
// representation might not have a reified tag.
SET_TRANSIENT(method);
assert(METHOD_FLAG_USED_PREVIOUS_EPOCH(method), "invariant");
}
SET_LEAKP(klass);
SET_METHOD_LEAKP(method);
return (METHOD_ID(klass, method));
}
#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBARRIER_INLINE_HPP #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBARRIER_INLINE_HPP

View File

@ -100,9 +100,10 @@
#define METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (THIS_EPOCH_METHOD_AND_CLASS_BITS))) #define METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (THIS_EPOCH_METHOD_AND_CLASS_BITS)))
#define METHOD_AND_CLASS_USED_PREVIOUS_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (PREVIOUS_EPOCH_METHOD_AND_CLASS_BITS))) #define METHOD_AND_CLASS_USED_PREVIOUS_EPOCH(kls) (TRACE_ID_PREDICATE(kls, (PREVIOUS_EPOCH_METHOD_AND_CLASS_BITS)))
#define METHOD_AND_CLASS_USED_ANY_EPOCH(kls) (METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls)) #define METHOD_AND_CLASS_USED_ANY_EPOCH(kls) (METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls))
#define METHOD_FLAG_USED_THIS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (THIS_EPOCH_BIT))) #define METHOD_FLAG_USED_THIS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (TRANSIENT_BIT | THIS_EPOCH_BIT)))
#define METHOD_FLAG_NOT_USED_THIS_EPOCH(method) (!(METHOD_FLAG_USED_THIS_EPOCH(method))) #define METHOD_FLAG_NOT_USED_THIS_EPOCH(method) (!(METHOD_FLAG_USED_THIS_EPOCH(method)))
#define METHOD_FLAG_USED_PREVIOUS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (PREVIOUS_EPOCH_BIT))) #define METHOD_FLAG_USED_PREVIOUS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (TRANSIENT_BIT | PREVIOUS_EPOCH_BIT)))
#define METHOD_FLAG_NOT_USED_PREVIOUS_EPOCH(method) (!(METHOD_FLAG_USED_PREVIOUS_EPOCH(method)))
#define IS_METHOD_BLESSED(method) (METHOD_FLAG_PREDICATE(method, BLESSED_METHOD_BIT)) #define IS_METHOD_BLESSED(method) (METHOD_FLAG_PREDICATE(method, BLESSED_METHOD_BIT))
// setters // setters
@ -130,21 +131,28 @@
#define META_MASK (~(SERIALIZED_META_BIT | TRANSIENT_META_BIT | LEAKP_META_BIT)) #define META_MASK (~(SERIALIZED_META_BIT | TRANSIENT_META_BIT | LEAKP_META_BIT))
#define SET_LEAKP(ptr) (TRACE_ID_META_TAG(ptr, LEAKP_META_BIT)) #define SET_LEAKP(ptr) (TRACE_ID_META_TAG(ptr, LEAKP_META_BIT))
#define IS_LEAKP(ptr) (TRACE_ID_PREDICATE(ptr, LEAKP_BIT)) #define IS_LEAKP(ptr) (TRACE_ID_PREDICATE(ptr, LEAKP_BIT))
#define IS_NOT_LEAKP(ptr) (!(IS_LEAKP(ptr)))
#define SET_TRANSIENT(ptr) (TRACE_ID_META_TAG(ptr, TRANSIENT_META_BIT)) #define SET_TRANSIENT(ptr) (TRACE_ID_META_TAG(ptr, TRANSIENT_META_BIT))
#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_SERIALIZED(ptr) (TRACE_ID_PREDICATE(ptr, SERIALIZED_BIT)) #define IS_SERIALIZED(ptr) (TRACE_ID_PREDICATE(ptr, SERIALIZED_BIT))
#define IS_NOT_SERIALIZED(ptr) (!(IS_SERIALIZED(ptr))) #define IS_NOT_SERIALIZED(ptr) (!(IS_SERIALIZED(ptr)))
#define SHOULD_TAG(ptr) (NOT_USED_THIS_EPOCH(ptr)) #define SHOULD_TAG(ptr) (NOT_USED_THIS_EPOCH(ptr))
#define SHOULD_TAG_KLASS_METHOD(ptr) (METHOD_NOT_USED_THIS_EPOCH(ptr)) #define SHOULD_TAG_KLASS_METHOD(ptr) (METHOD_NOT_USED_THIS_EPOCH(ptr))
#define SET_SERIALIZED(ptr) (TRACE_ID_META_TAG(ptr, SERIALIZED_META_BIT))
#define CLEAR_SERIALIZED(ptr) (TRACE_ID_META_MASK_CLEAR(ptr, META_MASK)) #define CLEAR_SERIALIZED(ptr) (TRACE_ID_META_MASK_CLEAR(ptr, META_MASK))
#define SET_PREVIOUS_EPOCH_CLEARED_BIT(ptr) (TRACE_ID_META_TAG(ptr, PREVIOUS_EPOCH_BIT)) #define SET_PREVIOUS_EPOCH_CLEARED_BIT(ptr) (TRACE_ID_META_TAG(ptr, PREVIOUS_EPOCH_BIT))
#define IS_THIS_EPOCH_CLEARED(ptr) (TRACE_ID_PREDICATE(ptr, THIS_EPOCH_BIT)) #define IS_THIS_EPOCH_CLEARED(ptr) (TRACE_ID_PREDICATE(ptr, THIS_EPOCH_BIT))
#define IS_PREVIOUS_EPOCH_CLEARED(ptr) (TRACE_ID_PREDICATE(ptr, PREVIOUS_EPOCH_BIT)) #define IS_PREVIOUS_EPOCH_CLEARED(ptr) (TRACE_ID_PREDICATE(ptr, PREVIOUS_EPOCH_BIT))
#define IS_METHOD_SERIALIZED(method) (METHOD_FLAG_PREDICATE(method, SERIALIZED_BIT))
#define IS_METHOD_LEAKP_USED(method) (METHOD_FLAG_PREDICATE(method, LEAKP_BIT))
#define METHOD_NOT_SERIALIZED(method) (!(IS_METHOD_SERIALIZED(method)))
#define SET_METHOD_LEAKP(method) (METHOD_META_TAG(method, LEAKP_META_BIT))
#define SET_METHOD_SERIALIZED(method) (METHOD_META_TAG(method, SERIALIZED_META_BIT)) #define SET_METHOD_SERIALIZED(method) (METHOD_META_TAG(method, SERIALIZED_META_BIT))
#define METHOD_IS_SERIALIZED(method) (METHOD_FLAG_PREDICATE(method, SERIALIZED_BIT))
#define METHOD_IS_NOT_SERIALIZED(method) (!(METHOD_IS_SERIALIZED(method)))
#define SET_METHOD_LEAKP(method) (METHOD_META_TAG(method, LEAKP_META_BIT))
#define METHOD_IS_LEAKP(method) (METHOD_FLAG_PREDICATE(method, LEAKP_BIT))
#define METHOD_IS_NOT_LEAKP(method) (!(METHOD_IS_LEAKP(method)))
#define SET_METHOD_TRANSIENT(method) (METHOD_META_TAG(method, TRANSIENT_META_BIT))
#define METHOD_IS_TRANSIENT(method) (METHOD_FLAG_PREDICATE(method, TRANSIENT_BIT))
#define METHOD_IS_NOT_TRANSIENT(method) (!(METHOD_IS_TRANSIENT(method)))
#define CLEAR_SERIALIZED_METHOD(method) (METHOD_META_MASK_CLEAR(method, META_MASK)) #define CLEAR_SERIALIZED_METHOD(method) (METHOD_META_MASK_CLEAR(method, META_MASK))
#define SET_PREVIOUS_EPOCH_METHOD_CLEARED_BIT(ptr) (METHOD_META_TAG(ptr, PREVIOUS_EPOCH_BIT)) #define SET_PREVIOUS_EPOCH_METHOD_CLEARED_BIT(ptr) (METHOD_META_TAG(ptr, PREVIOUS_EPOCH_BIT))
#define CLEAR_LEAKP(ptr) (TRACE_ID_META_MASK_CLEAR(ptr, (~(LEAKP_META_BIT)))) #define CLEAR_LEAKP(ptr) (TRACE_ID_META_MASK_CLEAR(ptr, (~(LEAKP_META_BIT))))

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -35,11 +35,10 @@ bool JfrEventSetting::set_threshold(jlong id, jlong threshold_ticks) {
return true; return true;
} }
bool JfrEventSetting::set_cutoff(jlong id, jlong cutoff_ticks) { void JfrEventSetting::set_miscellaneous(jlong id, jlong level) {
JfrEventId event_id = (JfrEventId)id; JfrEventId event_id = (JfrEventId)id;
assert(bounds_check_event(event_id), "invariant"); assert(bounds_check_event(event_id), "invariant");
setting(event_id).cutoff_ticks = cutoff_ticks; setting(event_id).miscellaneous = level;
return true;
} }
void JfrEventSetting::set_stacktrace(jlong id, bool enabled) { void JfrEventSetting::set_stacktrace(jlong id, bool enabled) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -45,8 +45,9 @@ class JfrEventSetting : AllStatic {
static bool has_stacktrace(JfrEventId event_id); static bool has_stacktrace(JfrEventId event_id);
static bool set_threshold(jlong event_id, jlong threshold_ticks); static bool set_threshold(jlong event_id, jlong threshold_ticks);
static jlong threshold(JfrEventId event_id); static jlong threshold(JfrEventId event_id);
static bool set_cutoff(jlong event_id, jlong cutoff_ticks); static void set_miscellaneous(jlong event_id, jlong cutoff_ticks);
static jlong cutoff(JfrEventId event_id); static jlong cutoff(JfrEventId event_id);
static jlong level(JfrEventId event_id);
static bool is_large(JfrEventId event_id); static bool is_large(JfrEventId event_id);
static void set_large(JfrEventId event_id); static void set_large(JfrEventId event_id);
static void unhide_internal_types(); static void unhide_internal_types();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -43,8 +43,12 @@ inline jlong JfrEventSetting::threshold(JfrEventId event_id) {
return setting(event_id).threshold_ticks; return setting(event_id).threshold_ticks;
} }
inline jlong JfrEventSetting::level(JfrEventId event_id) {
return setting(event_id).miscellaneous;
}
inline jlong JfrEventSetting::cutoff(JfrEventId event_id) { inline jlong JfrEventSetting::cutoff(JfrEventId event_id) {
return setting(event_id).cutoff_ticks; return setting(event_id).miscellaneous;
} }
inline bool JfrEventSetting::is_large(JfrEventId event_id) { inline bool JfrEventSetting::is_large(JfrEventId event_id) {

View File

@ -77,20 +77,33 @@ bool JfrRecorder::is_enabled() {
return _enabled; return _enabled;
} }
bool JfrRecorder::is_started_on_commandline() {
return StartFlightRecording != nullptr;
}
bool JfrRecorder::create_oop_storages() { bool JfrRecorder::create_oop_storages() {
// currently only a single weak oop storage for Leak Profiler // currently only a single weak oop storage for Leak Profiler
return ObjectSampler::create_oop_storage(); return ObjectSampler::create_oop_storage();
} }
// Subsystem
static JfrCheckpointManager* _checkpoint_manager = nullptr;
bool JfrRecorder::on_create_vm_1() { bool JfrRecorder::on_create_vm_1() {
if (!is_disabled()) { if (!is_disabled()) {
if (FlightRecorder || StartFlightRecording != nullptr) { if (FlightRecorder || is_started_on_commandline()) {
enable(); enable();
} }
} }
if (!create_oop_storages()) { if (!create_oop_storages()) {
return false; return false;
} }
_checkpoint_manager = JfrCheckpointManager::create();
if (_checkpoint_manager == nullptr || !_checkpoint_manager->initialize_early()) {
return false;
}
// fast time initialization // fast time initialization
return JfrTime::initialize(); return JfrTime::initialize();
} }
@ -303,7 +316,6 @@ bool JfrRecorder::create_components() {
// subsystems // subsystems
static JfrPostBox* _post_box = nullptr; static JfrPostBox* _post_box = nullptr;
static JfrStorage* _storage = nullptr; static JfrStorage* _storage = nullptr;
static JfrCheckpointManager* _checkpoint_manager = nullptr;
static JfrRepository* _repository = nullptr; static JfrRepository* _repository = nullptr;
static JfrStackTraceRepository* _stack_trace_repository; static JfrStackTraceRepository* _stack_trace_repository;
static JfrStringPool* _stringpool = nullptr; static JfrStringPool* _stringpool = nullptr;
@ -345,10 +357,9 @@ bool JfrRecorder::create_storage() {
} }
bool JfrRecorder::create_checkpoint_manager() { bool JfrRecorder::create_checkpoint_manager() {
assert(_checkpoint_manager == nullptr, "invariant"); assert(_checkpoint_manager != nullptr, "invariant");
assert(_repository != nullptr, "invariant"); assert(_repository != nullptr, "invariant");
_checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter()); return _checkpoint_manager->initialize(&_repository->chunkwriter());
return _checkpoint_manager != nullptr && _checkpoint_manager->initialize();
} }
bool JfrRecorder::create_stacktrace_repository() { bool JfrRecorder::create_stacktrace_repository() {
@ -390,7 +401,7 @@ void JfrRecorder::destroy_components() {
} }
if (_checkpoint_manager != nullptr) { if (_checkpoint_manager != nullptr) {
JfrCheckpointManager::destroy(); JfrCheckpointManager::destroy();
_checkpoint_manager = nullptr; // do not delete the _checkpoint_manager instance
} }
if (_stack_trace_repository != nullptr) { if (_stack_trace_repository != nullptr) {
JfrStackTraceRepository::destroy(); JfrStackTraceRepository::destroy();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -61,8 +61,9 @@ class JfrRecorder : public JfrCHeapObj {
public: public:
static bool is_enabled(); static bool is_enabled();
static bool is_disabled(); static bool is_disabled();
static bool create(bool simulate_failure);
static bool is_created(); static bool is_created();
static bool is_started_on_commandline();
static bool create(bool simulate_failure);
static void destroy(); static void destroy();
static void start_recording(); static void start_recording();
static bool is_recording(); static bool is_recording();

View File

@ -40,6 +40,7 @@
#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/storage/jfrStorage.hpp"
#include "jfr/recorder/storage/jfrStorageControl.hpp" #include "jfr/recorder/storage/jfrStorageControl.hpp"
#include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrAllocation.hpp"
#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrThreadIterator.hpp"
#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTime.hpp"
@ -431,6 +432,7 @@ static void start_recorder() {
static void stop_recorder() { static void stop_recorder() {
assert(JfrRotationLock::is_owner(), "invariant"); assert(JfrRotationLock::is_owner(), "invariant");
JfrDeprecationManager::on_recorder_stop();
set_recorder_state(RUNNING, STOPPED); set_recorder_state(RUNNING, STOPPED);
log_debug(jfr, system)("Recording service STOPPED"); log_debug(jfr, system)("Recording service STOPPED");
} }
@ -478,6 +480,7 @@ void JfrRecorderService::safepoint_clear() {
_checkpoint_manager.begin_epoch_shift(); _checkpoint_manager.begin_epoch_shift();
_storage.clear(); _storage.clear();
_chunkwriter.set_time_stamp(); _chunkwriter.set_time_stamp();
JfrDeprecationManager::on_safepoint_clear();
JfrStackTraceRepository::clear(); JfrStackTraceRepository::clear();
_checkpoint_manager.end_epoch_shift(); _checkpoint_manager.end_epoch_shift();
} }
@ -506,6 +509,7 @@ void JfrRecorderService::vm_error_rotation() {
Thread* const thread = Thread::current(); Thread* const thread = Thread::current();
_storage.flush_regular_buffer(thread->jfr_thread_local()->native_buffer(), thread); _storage.flush_regular_buffer(thread->jfr_thread_local()->native_buffer(), thread);
_chunkwriter.mark_chunk_final(); _chunkwriter.mark_chunk_final();
JfrDeprecationManager::write_edges(_chunkwriter, thread, true);
invoke_flush(); invoke_flush();
_chunkwriter.set_time_stamp(); _chunkwriter.set_time_stamp();
_repository.close_chunk(); _repository.close_chunk();
@ -588,6 +592,7 @@ void JfrRecorderService::safepoint_write() {
_checkpoint_manager.on_rotation(); _checkpoint_manager.on_rotation();
_storage.write_at_safepoint(); _storage.write_at_safepoint();
_chunkwriter.set_time_stamp(); _chunkwriter.set_time_stamp();
JfrDeprecationManager::on_safepoint_write();
write_stacktrace(_stack_trace_repository, _chunkwriter, true); write_stacktrace(_stack_trace_repository, _chunkwriter, true);
_checkpoint_manager.end_epoch_shift(); _checkpoint_manager.end_epoch_shift();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -69,7 +69,6 @@ class JfrRecorderService : public StackObj {
void rotate(int msgs); void rotate(int msgs);
void flushpoint(); void flushpoint();
void process_full_buffers(); void process_full_buffers();
void scavenge();
void evaluate_chunk_size_for_rotation(); void evaluate_chunk_size_for_rotation();
static bool is_recording(); static bool is_recording();
}; };

View File

@ -243,3 +243,8 @@ size_t JfrStackTraceRepository::clear() {
clear_leak_profiler(); clear_leak_profiler();
return clear(instance()); return clear(instance());
} }
traceid JfrStackTraceRepository::next_id() {
MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
return ++_next_id;
}

View File

@ -34,6 +34,7 @@ class JfrCheckpointWriter;
class JfrChunkWriter; class JfrChunkWriter;
class JfrStackTraceRepository : public JfrCHeapObj { class JfrStackTraceRepository : public JfrCHeapObj {
friend class JfrDeprecatedEdge;
friend class JfrRecorder; friend class JfrRecorder;
friend class JfrRecorderService; friend class JfrRecorderService;
friend class JfrThreadSampleClosure; friend class JfrThreadSampleClosure;
@ -64,6 +65,8 @@ class JfrStackTraceRepository : public JfrCHeapObj {
static void record_for_leak_profiler(JavaThread* thread, int skip = 0); static void record_for_leak_profiler(JavaThread* thread, int skip = 0);
static void clear_leak_profiler(); static void clear_leak_profiler();
static traceid next_id();
traceid add_trace(const JfrStackTrace& stacktrace); traceid add_trace(const JfrStackTrace& stacktrace);
static traceid add(JfrStackTraceRepository& repo, const JfrStackTrace& stacktrace); static traceid add(JfrStackTraceRepository& repo, const JfrStackTrace& stacktrace);
static traceid add(const JfrStackTrace& stacktrace); static traceid add(const JfrStackTrace& stacktrace);

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 2023, 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 "jfrfiles/jfrEventIds.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/support/jfrDeprecationEventWriter.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "runtime/thread.inline.hpp"
// This dual state machine for the level setting is because when multiple recordings are running,
// and one of them stops, the newly calculated settings for level is updated before the chunk rotates.
// But we need remember what the level setting was before the recording stopped.
constexpr const int64_t uninitialized = -1;
static int64_t _previous_level_setting = uninitialized;
static int64_t _current_level_setting = uninitialized;
void JfrDeprecatedEventWriterState::on_initialization() {
_previous_level_setting = uninitialized;
_current_level_setting = uninitialized;
}
void JfrDeprecatedEventWriterState::on_level_setting_update(int64_t new_level) {
_previous_level_setting = _current_level_setting;
_current_level_setting = new_level;
}
static inline bool level() {
assert(_current_level_setting != uninitialized, "invariant");
return _previous_level_setting == uninitialized ? _current_level_setting : _previous_level_setting;
}
static inline bool only_for_removal() {
assert(JfrEventSetting::is_enabled(JfrDeprecatedInvocationEvent), "invariant");
// level 0: forRemoval, level 1: = all
return level() == 0;
}
void JfrDeprecatedStackTraceWriter::install_stacktrace_blob(JfrDeprecatedEdge* edge, JfrCheckpointWriter& writer, JavaThread* jt) {
assert(edge != nullptr, "invariant");
assert(!edge->has_stacktrace(), "invariant");
assert(writer.used_offset() == 0, "invariant");
writer.write(edge->stacktrace_id());
writer.write(true); // truncated
writer.write(1); // number of frames
writer.write(edge->sender_methodid());
writer.write<u4>(edge->linenumber());
writer.write<u4>(edge->bci());
writer.write<u1>(edge->frame_type());
JfrBlobHandle blob = writer.move();
edge->set_stacktrace(blob);
}
// This op will collapse all individual stacktrace blobs into a single TYPE_STACKTRACE checkpoint.
JfrDeprecatedStackTraceWriter::JfrDeprecatedStackTraceWriter(JfrChunkWriter& cw) :
_cw(cw), _begin_offset(cw.current_offset()), _elements_offset(0), _processed(0), _elements(0), _for_removal(only_for_removal()) {
const int64_t last_checkpoint = cw.last_checkpoint_offset();
const int64_t delta = last_checkpoint == 0 ? 0 : last_checkpoint - _begin_offset;
cw.reserve(sizeof(uint64_t));
cw.write(EVENT_CHECKPOINT);
cw.write(JfrTicks::now().value());
cw.write(0);
cw.write(delta);
cw.write(GENERIC); // Generic checkpoint type.
cw.write(1); // Number of types in this checkpoint, only one, TYPE_STACKTRACE.
cw.write(TYPE_STACKTRACE); // Constant pool type.
_elements_offset = cw.current_offset(); // Offset for the number of entries in the TYPE_STACKTRACE constant pool.
cw.reserve(sizeof(uint32_t));
}
JfrDeprecatedStackTraceWriter::~JfrDeprecatedStackTraceWriter() {
if (_elements == 0) {
// Rewind.
_cw.seek(_begin_offset);
return;
}
const int64_t event_size = _cw.current_offset() - _begin_offset;
_cw.write_padded_at_offset(_elements, _elements_offset);
_cw.write_padded_at_offset(event_size, _begin_offset);
_cw.set_last_checkpoint_offset(_begin_offset);
}
bool JfrDeprecatedStackTraceWriter::process(const JfrDeprecatedEdge* edge) {
assert(edge != nullptr, "invariant");
assert(edge->has_stacktrace(), "invariant");
if (_for_removal && !edge->for_removal()) {
return true;
}
++_elements;
edge->stacktrace()->write(_cw);
_processed += edge->stacktrace()->size();
return true;
}
JfrDeprecatedEventWriter::JfrDeprecatedEventWriter(JfrChunkWriter& cw, bool stacktrace) :
_now(JfrTicks::now()),_cw(cw), _for_removal(only_for_removal()), _stacktrace(stacktrace), _did_write(false) {}
static size_t calculate_event_size(const JfrDeprecatedEdge* edge, JfrChunkWriter& cw, const JfrTicks& now, bool stacktrace) {
assert(edge != nullptr, "invariant");
size_t bytes = cw.size_in_bytes(JfrDeprecatedInvocationEvent);
bytes += cw.size_in_bytes(now); // starttime
bytes += cw.size_in_bytes(stacktrace ? edge->stacktrace_id() : 0); // stacktrace
bytes += cw.size_in_bytes(edge->deprecated_methodid());
bytes += cw.size_in_bytes(edge->invocation_time());
bytes += cw.size_in_bytes(edge->for_removal());
return bytes + cw.size_in_bytes(bytes + cw.size_in_bytes(bytes));
}
static void write_event(const JfrDeprecatedEdge* edge, JfrChunkWriter& cw, const JfrTicks& now, bool stacktrace) {
assert(edge != nullptr, "invariant");
cw.write(calculate_event_size(edge, cw, now, stacktrace));
cw.write(JfrDeprecatedInvocationEvent);
cw.write(now);
cw.write(stacktrace ? edge->stacktrace_id() : 0);
cw.write(edge->deprecated_methodid());
cw.write(edge->invocation_time());
cw.write(edge->for_removal());
}
bool JfrDeprecatedEventWriter::process(const JfrDeprecatedEdge* edge) {
assert(edge != nullptr, "invariant");
if (_for_removal && !edge->for_removal()) {
return true;
}
write_event(edge, _cw,_now, _stacktrace);
if (!_did_write) {
_did_write = true;
}
return true;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2023, 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.
*
*/
#ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP
#define SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP
#include "memory/allocation.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTime.hpp"
class JfrCheckpointWriter;
class JfrChunkWriter;
class JfrDeprecatedEdge;
// This writer will collapse all individual stacktrace blobs into a single TYPE_STACKTRACE checkpoint.
class JfrDeprecatedStackTraceWriter : public StackObj{
private:
JfrChunkWriter& _cw;
int64_t _begin_offset;
int64_t _elements_offset;
size_t _processed;
uint32_t _elements;
bool _for_removal;
public:
JfrDeprecatedStackTraceWriter(JfrChunkWriter& cw);
~JfrDeprecatedStackTraceWriter();
size_t elements() const { return _elements; }
size_t processed() const { return _processed; }
bool process(const JfrDeprecatedEdge* edge);
static void install_stacktrace_blob(JfrDeprecatedEdge* edge, JfrCheckpointWriter& writer, JavaThread* jt);
};
class JfrDeprecatedEventWriter : public StackObj {
private:
JfrTicks _now;
JfrChunkWriter& _cw;
bool _for_removal;
bool _stacktrace;
bool _did_write;
public:
JfrDeprecatedEventWriter(JfrChunkWriter& cw, bool stacktrace);
bool did_write() const { return _did_write; }
bool process(const JfrDeprecatedEdge* edge);
};
class JfrDeprecatedEventWriterState : AllStatic {
public:
static void on_initialization();
static void on_level_setting_update(int64_t new_level);
};
#endif // SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP

View File

@ -0,0 +1,380 @@
/*
* Copyright (c) 2023, 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 "classfile/moduleEntry.hpp"
#include "jfrfiles/jfrEventIds.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/support/jfrDeprecationEventWriter.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrKlassUnloading.hpp"
#include "jfr/support/jfrMethodData.hpp"
#include "jfr/support/jfrMethodLookup.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrLinkedList.inline.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/method.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/thread.inline.hpp"
// for strstr
#include <string.h>
static bool _enqueue_klasses = false;
void JfrDeprecationManager::on_recorder_stop() {
_enqueue_klasses = false;
}
static inline traceid load_traceid(const Method* method) {
assert(method != nullptr, "invariant");
// If the Jfr system is not yet running we only tag the artifacts, not enqueuing klasses.
return _enqueue_klasses ? JfrTraceId::load(method) : JfrTraceId::load_no_enqueue(method);
}
JfrDeprecatedEdge::JfrDeprecatedEdge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt) :
_invocation_time(JfrTicks::now()),
_stacktrace(),
_next(nullptr),
_deprecated_ik(method->method_holder()),
_deprecated_methodid(load_traceid(method)),
_sender_ik(sender->method_holder()),
_sender_methodid(load_traceid(sender)),
// Our stacktrace will be hand-rolled into a blob.
// We don't need anything from the stacktrace
// subsystem except for a unique id.
_stack_trace_id(JfrStackTraceRepository::next_id()),
_bci(bci),
_linenumber(sender->line_number_from_bci(bci)),
_frame_type(frame_type),
_for_removal(method->deprecated_for_removal()) {}
bool JfrDeprecatedEdge::has_stacktrace() const {
return _stacktrace.valid();
}
void JfrDeprecatedEdge::set_stacktrace(const JfrBlobHandle& blob) {
assert(!has_stacktrace(), "invariant");
_stacktrace = blob;
}
const JfrBlobHandle& JfrDeprecatedEdge::stacktrace() const {
assert(has_stacktrace(), "invariant");
return _stacktrace;
}
typedef JfrLinkedList<JfrDeprecatedEdge> DeprecatedEdgeList;
static DeprecatedEdgeList _list; // Newly constructed edges are concurrently added to this list.
static DeprecatedEdgeList _pending_list; // During epoch rotation (safepoint) entries in _list are moved onto _pending_list
static DeprecatedEdgeList _resolved_list; // Fully resolved edges (event and stacktrace blobs).
static JfrDeprecatedEdge* allocate_edge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt);)
assert(method != nullptr, "invariant");
assert(method->deprecated(), "invariant");
assert(sender != nullptr, "invariant");
assert(jt != nullptr, "invariant");
return new JfrDeprecatedEdge(method, sender, bci, frame_type, jt);
}
static void create_edge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt) {
JfrDeprecatedEdge* edge;
// We need the JavaThread to be in _thread_in_vm when creating the edge.
// This is because the method artifacts needs to be tagged in the correct epoch.
if (jt->thread_state() != _thread_in_vm) {
assert(jt->is_Compiler_thread(), "invariant");
// Can safepoint here.
ThreadInVMfromNative transition(jt);
edge = allocate_edge(method, sender, bci, frame_type, jt);
} else {
edge = allocate_edge(method, sender, bci, frame_type, jt);
}
_list.add(edge);
}
static constexpr const size_t max_num_edges = 10000;
static void log_max_num_edges_reached() {
log_info(jfr)("The number of deprecated method invocations recorded has reached a maximum limit of %zu.", max_num_edges);
log_info(jfr)("Deprecated method invocations will not be recorded from now on.");
log_info(jfr)("Reduce the number of deprecated method invocations and try again.");
}
static bool max_limit_not_reached() {
static size_t num_edges = 0;
size_t compare_value;
do {
compare_value = Atomic::load(&num_edges);
if (compare_value == max_num_edges) {
return false;
}
} while (compare_value != Atomic::cmpxchg(&num_edges, compare_value, compare_value + 1));
if (compare_value + 1 == max_num_edges) {
log_max_num_edges_reached();
}
return true;
}
/*
* Two cases for JDK modules as outlined by JEP 200: The Modular JDK.
*
* The modular structure of the JDK implements the following principles:
* 1. Standard modules, whose specifications are governed by the JCP, have names starting with the string "java.".
* 2. All other modules are merely part of the JDK, and have names starting with the string "jdk.".
* */
static inline bool is_jdk_module(const char* module_name) {
assert(module_name != nullptr, "invariant");
return strstr(module_name, "java.") == module_name || strstr(module_name, "jdk.") == module_name;
}
static inline bool is_unnamed_module(const ModuleEntry* module) {
return module == nullptr || !module->is_named();
}
static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) {
assert(jt != nullptr, "invariant");
if (is_unnamed_module(module)) {
return false;
}
ResourceMark rm(jt);
const Symbol* const module_symbol = module->name();
assert(module_symbol != nullptr, "invariant");
const char* const module_name = module_symbol->as_C_string();
return is_jdk_module(module_name);
}
static inline bool is_not_jdk_module(const ModuleEntry* module, JavaThread* jt) {
return !is_jdk_module(module, jt);
}
static inline bool jfr_is_started_on_command_line() {
return JfrRecorder::is_started_on_commandline();
}
static bool should_record(const Method* method, const Method* sender, JavaThread* jt) {
assert(method != nullptr, "invariant");
assert(method->deprecated(), "invariant");
assert(sender != nullptr, "invariant");
assert(!sender->is_native(), "invariant");
assert(jt != nullptr, "invariant");
assert(jfr_is_started_on_command_line(), "invariant");
const ModuleEntry* const deprecated_module = method->method_holder()->module();
// Only record invoked deprecated methods in the JDK.
if (is_not_jdk_module(deprecated_module, jt)) {
return false;
}
const ModuleEntry* const sender_module = sender->method_holder()->module();
// Only record senders not in the JDK and if we are still within budget.
return is_not_jdk_module(sender_module, jt) && max_limit_not_reached();
}
// This is the entry point for newly discovered edges in JfrResolution.cpp.
void JfrDeprecationManager::on_link(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt) {
assert(method != nullptr, "invariant");
assert(method->deprecated(), "invariant");
assert(sender != nullptr, "invariant");
assert(!sender->is_native(), "invariant");
assert(jt != nullptr, "invariant");
assert(JfrRecorder::is_started_on_commandline(), "invariant");
if (JfrMethodData::mark_deprecated_call_site(sender, bci, jt)) {
if (should_record(method, sender, jt)) {
create_edge(method, sender, bci, frame_type, jt);
}
}
}
static void transfer_list() {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
assert(_pending_list.is_empty(), "invariant");
DeprecatedEdgeList::NodePtr head = _list.cut();
assert(_list.is_empty(), "invariant");
if (head != nullptr) {
_pending_list.add_list(head);
}
}
void JfrDeprecationManager::on_level_setting_update(int64_t new_level) {
JfrDeprecatedEventWriterState::on_level_setting_update(new_level);
}
void JfrDeprecationManager::on_safepoint_clear() {
assert(!_enqueue_klasses, "invariant");
// We are now starting JFR, so begin enqueuing tagged klasses.
_enqueue_klasses = true;
JfrDeprecatedEventWriterState::on_initialization();
transfer_list();
}
void JfrDeprecationManager::on_safepoint_write() {
assert(_enqueue_klasses, "invariant");
transfer_list();
}
static bool is_klass_unloaded(traceid klass_id) {
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
return JfrKlassUnloading::is_unloaded(klass_id, true);
}
static void add_to_leakp_set(const InstanceKlass* ik, traceid method_id) {
// The lock is needed to ensure the klass unloading lists do not grow in the middle of inspection.
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
assert(ik != nullptr, "invariant");
if (is_klass_unloaded(JfrMethodLookup::klass_id(method_id))) {
return;
}
const Method* const method = JfrMethodLookup::lookup(ik, method_id);
assert(method != nullptr, "invariant");
assert(method->method_holder() == ik, "invariant");
JfrTraceId::load_leakp_previous_epoch(ik, method); // now has the leakp marker
}
static void add_to_leakp_set(const JfrDeprecatedEdge* edge) {
assert(edge != nullptr, "invariant");
add_to_leakp_set(edge->deprecated_ik(), edge->deprecated_methodid());
add_to_leakp_set(edge->sender_ik(), edge->sender_methodid());
}
// Keeps track of nodes processed from the _pending_list.
static DeprecatedEdgeList::NodePtr _pending_head = nullptr;
static DeprecatedEdgeList::NodePtr _pending_tail = nullptr;
class PendingListProcessor {
private:
JfrCheckpointWriter& _writer;
JavaThread* _jt;
public:
PendingListProcessor(JfrCheckpointWriter& writer, JavaThread* jt) : _writer(writer), _jt(jt) {}
bool process(DeprecatedEdgeList::NodePtr edge) {
assert(edge != nullptr, "invariant");
JfrDeprecatedStackTraceWriter::install_stacktrace_blob(edge, _writer, _jt);
assert(edge->has_stacktrace(), "invariant");
add_to_leakp_set(edge);
if (_pending_head == nullptr) {
_pending_head = edge;
}
_pending_tail = edge;
return true;
}
};
void JfrDeprecationManager::prepare_type_set(JavaThread* jt) {
_pending_head = nullptr;
_pending_tail = nullptr;
if (_pending_list.is_nonempty()) {
JfrKlassUnloading::sort(true);
JfrCheckpointWriter writer(true /* prev epoch */, jt, false /* header */);
PendingListProcessor plp(writer, jt);
_pending_list.iterate(plp);
assert(_pending_head != nullptr, "invariant");
assert(_pending_tail != nullptr, "invariant");
assert(_pending_tail->next() == nullptr, "invariant");
// Excise already resolved edges to link them.
_pending_tail->set_next(_resolved_list.cut());
// Re-insertion.
_resolved_list.add_list(_pending_head);
_pending_list.clear();
}
assert(_pending_list.is_empty(), "invariant");
}
// A linked-list of blob handles.
static JfrBlobHandle type_set_blobs;
static inline void write_type_set_blobs(JfrCheckpointWriter& writer) {
type_set_blobs->write(writer);
}
static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) {
assert(writer.has_data(), "invariant");
const JfrBlobHandle blob = copy ? writer.copy() : writer.move();
if (type_set_blobs.valid()) {
type_set_blobs->set_next(blob);
} else {
type_set_blobs = blob;
}
}
void JfrDeprecationManager::on_type_set_unload(JfrCheckpointWriter& writer) {
if (writer.has_data()) {
save_type_set_blob(writer, true);
}
}
static inline bool has_stacktrace() {
return JfrEventSetting::has_stacktrace(JfrDeprecatedInvocationEvent);
}
static inline bool write_events(JfrChunkWriter& cw) {
assert(_resolved_list.is_nonempty(), "invariant");
JfrDeprecatedEventWriter ebw(cw, has_stacktrace());
_resolved_list.iterate(ebw);
return ebw.did_write();
}
static inline void write_stacktraces(JfrChunkWriter& cw) {
assert(has_stacktrace(), "invariant");
JfrDeprecatedStackTraceWriter scw(cw);
_resolved_list.iterate(scw);
}
static inline void write_type_sets(Thread* thread, bool on_error) {
JfrCheckpointWriter writer(!on_error, thread, false);
write_type_set_blobs(writer);
}
// First, we consolidate all stacktrace blobs into a single TYPE_STACKTRACE checkpoint and serialize it to the chunk.
// Secondly, we serialize all events to the chunk.
// Thirdly, the type set blobs are written into the JfrCheckpoint system, to be serialized to the chunk
// just after we return from here.
void JfrDeprecationManager::write_edges(JfrChunkWriter& cw, Thread* thread, bool on_error /* false */) {
if (_resolved_list.is_nonempty() && JfrEventSetting::is_enabled(JfrDeprecatedInvocationEvent)) {
if (has_stacktrace()) {
write_stacktraces(cw);
}
if (write_events(cw)) {
write_type_sets(thread, on_error);
}
}
}
void JfrDeprecationManager::on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread) {
assert(_pending_list.is_empty(), "invariant");
if (writer.has_data() && _pending_head != nullptr) {
save_type_set_blob(writer);
}
if (cw != nullptr) {
write_edges(*cw, thread);
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2023, 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.
*
*/
#ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP
#define SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP
#include "memory/allocation.hpp"
#include "jfr/utilities/jfrBlob.hpp"
#include "jfr/utilities/jfrTypes.hpp"
class JavaThread;
class JfrCheckpointWriter;
class JfrChunkWriter;
class Method;
class Thread;
class JfrDeprecatedEdge : public CHeapObj<mtTracing> {
template<typename, typename>
friend class JfrLinkedList;
friend class JfrDeprecatedStackTraceWriter;
private:
JfrTicks _invocation_time;
JfrBlobHandle _stacktrace;
JfrDeprecatedEdge* _next;
InstanceKlass* _deprecated_ik;
traceid _deprecated_methodid;
InstanceKlass* _sender_ik;
traceid _sender_methodid;
traceid _stack_trace_id;
int _bci;
int _linenumber;
u1 _frame_type;
bool _for_removal;
void set_stacktrace(const JfrBlobHandle& blob);
public:
JfrDeprecatedEdge(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* jt);
const JfrDeprecatedEdge* next() const { return _next; }
void set_next(JfrDeprecatedEdge* edge) { _next = edge; }
bool has_event() const;
const JfrBlobHandle& event() const;
const JfrBlobHandle& event_no_stacktrace() const;
bool has_stacktrace() const;
const JfrBlobHandle& stacktrace() const;
void install_stacktrace_blob(JavaThread* jt);
const InstanceKlass* deprecated_ik() const { return _deprecated_ik; }
traceid deprecated_methodid() const { return _deprecated_methodid; }
const InstanceKlass* sender_ik() const { return _sender_ik; }
traceid sender_methodid() const { return _sender_methodid; }
const JfrTicks& invocation_time() const { return _invocation_time; }
traceid stacktrace_id() const { return _stack_trace_id; }
int bci() const { return _bci; }
u1 frame_type() const { return _frame_type; }
bool for_removal() const { return _for_removal; }
int linenumber() const { return _linenumber; }
};
class JfrDeprecationManager : AllStatic {
public:
static void on_safepoint_clear();
static void on_safepoint_write();
static void on_recorder_stop();
static void prepare_type_set(JavaThread* jt);
static void on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread);
static void on_type_set_unload(JfrCheckpointWriter& writer);
static void write_edges(JfrChunkWriter& cw, Thread* thread, bool on_error = false);
static void on_link(const Method* method, Method* sender, int bci, u1 frame_type, JavaThread* thread);
static void on_level_setting_update(int64_t new_level);
};
#endif // SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2023, 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 "jfr/support/jfrMethodData.hpp"
#include "memory/resourceArea.hpp"
#include "oops/method.inline.hpp"
#include "oops/methodData.inline.hpp"
#include "runtime/handles.inline.hpp"
// Caller requires ResourceMark.
static inline BitData* get_bit_data(MethodData* mdo, int bci) {
assert(mdo != nullptr, "invariant");
BitData* const bit_data = static_cast<BitData*>(mdo->bci_to_data(bci));
assert(bit_data != nullptr, "invariant");
assert(bit_data->is_VirtualCallData() || bit_data->is_VirtualCallTypeData() ||
bit_data->is_CounterData() || bit_data->is_CallTypeData(), "invariant");
return bit_data;
}
static inline MethodData* build_mdo(Method* method, JavaThread* jt) {
methodHandle method_handle(jt, method);
Method::build_profiling_method_data(method_handle, jt);
return method->method_data();
}
static inline MethodData* get_mdo(Method* method, JavaThread* jt) {
MethodData* mdo = method->method_data();
return mdo != nullptr ? mdo : build_mdo(method, jt);
}
static bool mark_mdo(Method* method, int bci, JavaThread* jt) {
assert(method != nullptr, "invariant");
assert(!method->is_native(), "native methods have no MDO bit data");
assert(jt != nullptr, "invariant");
MethodData* const mdo = get_mdo(method, jt);
assert(mdo != nullptr, "invariant");
// Get the datalayout for the invocation bci.
BitData* const bit_data = get_bit_data(mdo, bci);
// Returns true if this callsite is not yet linked and
// our attempt to set the deprecated flag was succesful.
if (bit_data->set_deprecated_method_call_site()) {
assert(bit_data->deprecated_method_call_site(), "invariant");
return true;
}
assert(bit_data->deprecated_method_call_site(), "invariant");
return false;
}
bool JfrMethodData::mark_deprecated_call_site(Method* method, int bci, JavaThread* jt) {
assert(method != nullptr, "invariant");
assert(jt != nullptr, "invariant");
assert(method->validate_bci(bci) >= 0, "invariant");
ResourceMark rm(jt);
return mark_mdo(method, bci, jt);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2023, 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.
*
*/
#ifndef SHARE_JFR_SUPPORT_JFRMETHODDATA_HPP
#define SHARE_JFR_SUPPORT_JFRMETHODDATA_HPP
#include "memory/allocation.hpp"
class Method;
class JavaThread;
class JfrMethodData : AllStatic {
public:
static bool mark_deprecated_call_site(Method* method, int bci, JavaThread* jt);
};
#endif // SHARE_JFR_SUPPORT_JFRMETHODDATA_HPP

View File

@ -32,7 +32,9 @@
JfrNativeLibraryEventBase::JfrNativeLibraryEventBase(const char* name) : _name(name), _error_msg(nullptr), _start_time(nullptr) {} JfrNativeLibraryEventBase::JfrNativeLibraryEventBase(const char* name) : _name(name), _error_msg(nullptr), _start_time(nullptr) {}
JfrNativeLibraryEventBase::~JfrNativeLibraryEventBase() { JfrNativeLibraryEventBase::~JfrNativeLibraryEventBase() {
delete _start_time; if (_start_time != nullptr) {
delete _start_time;
}
} }
const char* JfrNativeLibraryEventBase::name() const { const char* JfrNativeLibraryEventBase::name() const {

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) 2022, 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 "ci/ciKlass.hpp"
#include "ci/ciMethod.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
#include "jfr/recorder/stacktrace/jfrStackTrace.hpp"
#include "jfr/support/jfrDeprecationManager.hpp"
#include "jfr/support/jfrResolution.hpp"
#include "memory/resourceArea.inline.hpp"
#include "oops/method.inline.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/vframe.inline.hpp"
#ifdef COMPILER1
#include "c1/c1_GraphBuilder.hpp"
#endif
#ifdef COMPILER2
#include "opto/parse.hpp"
#endif
// for strstr
#include <string.h>
// The following packages are internal implmentation details used by reflection.
// We exclude matching frames on the stack in a manner similar to StackWalker.
static constexpr const int NUM_EXCLUDED_PACKAGES = 4;
static constexpr const char* excluded_packages[NUM_EXCLUDED_PACKAGES] = { "java/lang/invoke/",
"jdk/internal/reflect/",
"java/lang/reflect/",
"sun/invoke/" };
static inline bool match(const char* str, const char* sub_str) {
assert(str != nullptr, "invariant");
assert(sub_str != nullptr, "invariant");
return strstr(str, sub_str) == str;
}
// Caller requires ResourceMark.
static inline bool exclude_frame(const Method* method) {
assert(method != nullptr, "invariant");
// exclude native methods.
if (method->is_native()) {
return true;
}
const Klass* const klass = method->method_holder();
assert(klass != nullptr, "invariant");
const Symbol* const klass_sym = klass->name();
assert(klass_sym != nullptr, "invariant");
const char* const klass_name = klass_sym->as_C_string();
assert(klass_name != nullptr, "invariant");
for (int i = 0; i < NUM_EXCLUDED_PACKAGES; ++i) {
if (match(klass_name,excluded_packages[i])) {
return true;
}
}
return false;
}
static Method* find_real_sender(vframeStream& stream, JavaThread* jt) {
assert(jt != nullptr, "invariant");
assert(stream.method()->is_native(), "invariant");
ResourceMark rm(jt);
while (!stream.at_end()) {
stream.next();
Method* method = stream.method();
if (!exclude_frame(method)) {
return method;
}
}
return nullptr;
}
static inline bool jfr_is_started_on_command_line() {
return JfrRecorder::is_started_on_commandline();
}
static inline Method* frame_context(vframeStream& stream, int& bci, u1& frame_type, JavaThread* jt) {
Method* method = stream.method();
assert(method != nullptr, "invariant");
if (method->is_native()) {
method = find_real_sender(stream, jt);
if (method == nullptr) {
return nullptr;
}
}
assert(method != nullptr, "invariant");
assert(!method->is_native(), "invariant");
bci = stream.bci();
frame_type = stream.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
if (frame_type == JfrStackFrame::FRAME_JIT && !stream.at_end()) {
const intptr_t* const id = stream.frame_id();
stream.next();
if (id == stream.frame_id()) {
frame_type = JfrStackFrame::FRAME_INLINE;
}
}
return method;
}
static inline Method* ljf_sender_method(int& bci, u1& frame_type, JavaThread* jt) {
assert(jt != nullptr, "invariant");
if (!jt->has_last_Java_frame()) {
return nullptr;
}
vframeStream stream(jt, true, false);
return frame_context(stream, bci, frame_type, jt);
}
static inline void on_runtime_deprecated(const Method* method, JavaThread* jt) {
assert(jt != nullptr, "invariant");
assert(method != nullptr, "invariant");
assert(method->deprecated(), "invariant");
if (jfr_is_started_on_command_line()) {
int bci;
u1 frame_type;
Method* const sender = ljf_sender_method(bci, frame_type, jt);
if (sender != nullptr) {
JfrDeprecationManager::on_link(method, sender, bci, frame_type, jt);
}
}
}
// We can circumvent the need to hook into backpatching if ciMethod is made aware
// of the deprecated annotation already as part of parsing bytecodes of the callee method.
static void on_backpatching_deprecated(const Method* deprecated_method, JavaThread* jt) {
assert(deprecated_method != nullptr, "invariant");
assert(deprecated_method->deprecated(), "invariant");
assert(jt->has_last_Java_frame(), "invariant");
assert(jt->last_frame().is_runtime_frame(), "invariant");
if (jfr_is_started_on_command_line()) {
vframeStream stream(jt, true, false);
assert(!stream.at_end(), "invariant");
stream.next(); // now at caller
int bci;
u1 frame_type;
Method* const sender = frame_context(stream, bci, frame_type, jt);
if (sender != nullptr) {
JfrDeprecationManager::on_link(deprecated_method, sender, bci, frame_type, jt);
}
}
}
void JfrResolution::on_backpatching(const Method* callee_method, JavaThread* jt) {
assert(callee_method != nullptr, "invariant");
assert(jt != nullptr, "invariant");
if (callee_method->deprecated()) {
on_backpatching_deprecated(callee_method, jt);
}
}
static inline const Method* ljf_sender_method(JavaThread* jt) {
assert(jt != nullptr, "invariant");
if (!jt->has_last_Java_frame()) {
return nullptr;
}
const vframeStream ljf(jt, true, false);
return ljf.method();
}
static const char* const link_error_msg = "illegal access linking method 'jdk.jfr.internal.event.EventWriterFactory.getEventWriter(long)'";
void JfrResolution::on_runtime_resolution(const CallInfo & info, TRAPS) {
assert(info.selected_method() != nullptr, "invariant");
assert(info.resolved_klass() != nullptr, "invariant");
static const Symbol* const event_writer_method_name = vmSymbols::getEventWriter_name();
assert(event_writer_method_name != nullptr, "invariant");
Method* const method = info.selected_method();
assert(method != nullptr, "invariant");
if (method->deprecated()) {
on_runtime_deprecated(method, THREAD);
return;
}
// Fast path
if (method->name() != event_writer_method_name) {
return;
}
static const Symbol* const event_writer_factory_klass_name = vmSymbols::jdk_jfr_internal_event_EventWriterFactory();
assert(event_writer_factory_klass_name != nullptr, "invariant");
if (info.resolved_klass()->name() != event_writer_factory_klass_name) {
return;
}
// Attempting to link against jdk.jfr.internal.event.EventWriterFactory.getEventWriter().
// The sender, i.e. the method attempting to link, is in the ljf (if one exists).
const Method* const sender = ljf_sender_method(THREAD);
if (sender == nullptr) {
// A compiler thread is doing linktime resolution but there is no information about the sender available.
// For the compiler threads, the sender is instead found as part of bytecode parsing.
return;
}
// Is the sender method blessed for linkage?
if (IS_METHOD_BLESSED(sender)) {
return;
}
#if INCLUDE_JVMCI
// JVMCI compiler is doing linktime resolution
if (sender->method_holder()->name() == vmSymbols::jdk_vm_ci_hotspot_CompilerToVM()) {
if (sender->name()->equals("lookupMethodInPool")) {
return;
}
}
#endif
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), link_error_msg);
}
static inline bool is_compiler_linking_event_writer(const Symbol* holder, const Symbol* name) {
static const Symbol* const event_writer_factory_klass_name = vmSymbols::jdk_jfr_internal_event_EventWriterFactory();
assert(event_writer_factory_klass_name != nullptr, "invariant");
if (holder != event_writer_factory_klass_name) {
return false;
}
static const Symbol* const event_writer_method_name = vmSymbols::getEventWriter_name();
assert(event_writer_method_name != nullptr, "invariant");
return name == event_writer_method_name;
}
static inline bool is_compiler_linking_event_writer(const ciKlass * holder, const ciMethod * target) {
assert(holder != nullptr, "invariant");
assert(target != nullptr, "invariant");
return is_compiler_linking_event_writer(holder->name()->get_symbol(), target->name()->get_symbol());
}
static inline void on_compiler_resolve_deprecated(const ciMethod* target, int bci, Method* sender) {
assert(target != nullptr, "invariant");
assert(sender != nullptr, "invariant");
if (jfr_is_started_on_command_line()) {
const Method* const method = target->get_Method();
assert(method != nullptr, "Invariant");
assert(method->deprecated(), "invariant");
JfrDeprecationManager::on_link(method, sender, bci, JfrStackFrame::FRAME_JIT, JavaThread::current());
}
}
#ifdef COMPILER1
// C1
void JfrResolution::on_c1_resolution(const GraphBuilder * builder, const ciKlass * holder, const ciMethod * target) {
Method* const sender = builder->method()->get_Method();
if (is_compiler_linking_event_writer(holder, target) && !IS_METHOD_BLESSED(sender)) {
builder->bailout(link_error_msg);
return;
}
if (target->deprecated()) {
on_compiler_resolve_deprecated(target, builder->bci(), sender);
}
}
#endif
#ifdef COMPILER2
// C2
void JfrResolution::on_c2_resolution(const Parse * parse, const ciKlass * holder, const ciMethod * target) {
Method* const sender = parse->method()->get_Method();
if (is_compiler_linking_event_writer(holder, target) && !IS_METHOD_BLESSED(sender)) {
parse->C->record_failure(link_error_msg);
return;
}
if (target->deprecated()) {
on_compiler_resolve_deprecated(target, parse->bci(), sender);
}
}
#endif
#if INCLUDE_JVMCI
// JVMCI
void JfrResolution::on_jvmci_resolution(const Method* caller, const Method* target, TRAPS) {
if (is_compiler_linking_event_writer(target->method_holder()->name(), target->name())) {
if (caller == nullptr || !IS_METHOD_BLESSED(caller)) {
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), link_error_msg);
}
}
}
#endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -22,8 +22,8 @@
* *
*/ */
#ifndef SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP #ifndef SHARE_SUPPORT_JFRRESOLUTION_HPP
#define SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP #define SHARE_SUPPORT_JFRRESOLUTION_HPP
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "utilities/exceptions.hpp" #include "utilities/exceptions.hpp"
@ -32,6 +32,7 @@ class CallInfo;
class ciKlass; class ciKlass;
class ciMethod; class ciMethod;
class GraphBuilder; class GraphBuilder;
class JavaThread;
class Parse; class Parse;
class JfrResolution : AllStatic { class JfrResolution : AllStatic {
@ -40,7 +41,7 @@ class JfrResolution : AllStatic {
static void on_c1_resolution(const GraphBuilder * builder, const ciKlass * holder, const ciMethod * target); static void on_c1_resolution(const GraphBuilder * builder, const ciKlass * holder, const ciMethod * target);
static void on_c2_resolution(const Parse * parse, const ciKlass * holder, const ciMethod * target); static void on_c2_resolution(const Parse * parse, const ciKlass * holder, const ciMethod * target);
static void on_jvmci_resolution(const Method* caller, const Method* target, TRAPS); static void on_jvmci_resolution(const Method* caller, const Method* target, TRAPS);
static void on_backpatching(const Method* callee_method, JavaThread* jt);
}; };
#endif // SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP #endif // SHARE_SUPPORT_JFRRESOLUTION_HPP

View File

@ -57,13 +57,13 @@ static JfrSymbolTable& instance() {
JfrSymbolTable* JfrSymbolTable::create() { JfrSymbolTable* JfrSymbolTable::create() {
assert(_instance == nullptr, "invariant"); assert(_instance == nullptr, "invariant");
assert_lock_strong(ClassLoaderDataGraph_lock); assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
_instance = new JfrSymbolTable(); _instance = new JfrSymbolTable();
return _instance; return _instance;
} }
void JfrSymbolTable::destroy() { void JfrSymbolTable::destroy() {
assert_lock_strong(ClassLoaderDataGraph_lock); assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
if (_instance != nullptr) { if (_instance != nullptr) {
delete _instance; delete _instance;
_instance = nullptr; _instance = nullptr;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -66,6 +66,9 @@ class JfrBlob : public JfrCHeapObj {
_next->exclusive_write(writer); _next->exclusive_write(writer);
} }
} }
size_t size() const {
return _size;
}
}; };
#endif // SHARE_JFR_UTILITIES_JFRBLOB_HPP #endif // SHARE_JFR_UTILITIES_JFRBLOB_HPP

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -43,12 +43,15 @@ class JfrLinkedList : public AllocPolicy {
bool is_empty() const; bool is_empty() const;
bool is_nonempty() const; bool is_nonempty() const;
void add(NodePtr node); void add(NodePtr node);
void add_list(NodePtr first);
NodePtr remove(); NodePtr remove();
template <typename Callback> template <typename Callback>
void iterate(Callback& cb); void iterate(Callback& cb);
NodePtr head() const; NodePtr head() const;
NodePtr excise(NodePtr prev, NodePtr node); NodePtr excise(NodePtr prev, NodePtr node);
bool in_list(const NodeType* node) const; bool in_list(const NodeType* node) const;
NodePtr cut();
void clear();
private: private:
NodePtr _head; NodePtr _head;
}; };

View File

@ -118,4 +118,25 @@ bool JfrLinkedList<NodeType, AllocPolicy>::in_list(const NodeType* node) const {
return false; return false;
} }
template <typename NodeType, typename AllocPolicy>
NodeType* JfrLinkedList<NodeType, AllocPolicy>::cut() {
NodePtr node;
do {
node = head();
} while (Atomic::cmpxchg(&_head, node, (NodeType*)nullptr) != node);
return node;
}
template <typename NodeType, typename AllocPolicy>
void JfrLinkedList<NodeType, AllocPolicy>::clear() {
cut();
}
template <typename NodeType, typename AllocPolicy>
inline void JfrLinkedList<NodeType, AllocPolicy>::add_list(NodeType* first) {
assert(head() == nullptr, "invariant");
Atomic::store(&_head, first);
}
#endif // SHARE_JFR_UTILITIES_JFRLINKEDLIST_INLINE_HPP #endif // SHARE_JFR_UTILITIES_JFRLINKEDLIST_INLINE_HPP

View File

@ -58,6 +58,8 @@ class ConstMethodFlags {
flag(is_scoped , 1 << 16) \ flag(is_scoped , 1 << 16) \
flag(changes_current_thread , 1 << 17) \ flag(changes_current_thread , 1 << 17) \
flag(jvmti_mount_transition , 1 << 18) \ flag(jvmti_mount_transition , 1 << 18) \
flag(deprecated , 1 << 19) \
flag(deprecated_for_removal , 1 << 20) \
/* end of list */ /* end of list */
#define CM_FLAGS_ENUM_NAME(name, value) _misc_##name = value, #define CM_FLAGS_ENUM_NAME(name, value) _misc_##name = value,

View File

@ -413,7 +413,7 @@ class ConstantPool : public Metadata {
unresolved_klass_at_put(cp_index, name_index, CPKlassSlot::_temp_resolved_klass_index); unresolved_klass_at_put(cp_index, name_index, CPKlassSlot::_temp_resolved_klass_index);
} }
jint int_at(int cp_index) { jint int_at(int cp_index) const {
assert(tag_at(cp_index).is_int(), "Corrupted constant pool"); assert(tag_at(cp_index).is_int(), "Corrupted constant pool");
return *int_at_addr(cp_index); return *int_at_addr(cp_index);
} }

View File

@ -249,6 +249,12 @@ class Method : public Metadata {
u2 max_locals() const { return constMethod()->max_locals(); } u2 max_locals() const { return constMethod()->max_locals(); }
void set_max_locals(int size) { constMethod()->set_max_locals(size); } void set_max_locals(int size) { constMethod()->set_max_locals(size); }
void set_deprecated() { constMethod()->set_deprecated(); }
bool deprecated() const { return constMethod()->deprecated(); }
void set_deprecated_for_removal() { constMethod()->set_deprecated_for_removal(); }
bool deprecated_for_removal() const { return constMethod()->deprecated_for_removal(); }
int highest_comp_level() const; int highest_comp_level() const;
void set_highest_comp_level(int level); void set_highest_comp_level(int level);
int highest_osr_comp_level() const; int highest_osr_comp_level() const;

View File

@ -663,9 +663,6 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, const methodHandl
} }
int MethodData::bytecode_cell_count(Bytecodes::Code code) { int MethodData::bytecode_cell_count(Bytecodes::Code code) {
if (CompilerConfig::is_c1_simple_only() && !ProfileInterpreter) {
return no_profile_data;
}
switch (code) { switch (code) {
case Bytecodes::_checkcast: case Bytecodes::_checkcast:
case Bytecodes::_instanceof: case Bytecodes::_instanceof:
@ -986,9 +983,6 @@ int MethodData::compute_allocation_size_in_words(const methodHandle& method) {
// the segment in bytes. // the segment in bytes.
int MethodData::initialize_data(BytecodeStream* stream, int MethodData::initialize_data(BytecodeStream* stream,
int data_index) { int data_index) {
if (CompilerConfig::is_c1_simple_only() && !ProfileInterpreter) {
return 0;
}
int cell_count = -1; int cell_count = -1;
u1 tag = DataLayout::no_tag; u1 tag = DataLayout::no_tag;
DataLayout* data_layout = data_layout_at(data_index); DataLayout* data_layout = data_layout_at(data_index);

View File

@ -183,7 +183,7 @@ public:
} }
u1 flags() const { u1 flags() const {
return _header._struct._flags; return Atomic::load_acquire(&_header._struct._flags);
} }
u2 bci() const { u2 bci() const {
@ -204,11 +204,36 @@ public:
return _cells[index]; return _cells[index];
} }
void set_flag_at(u1 flag_number) { bool set_flag_at(u1 flag_number) {
_header._struct._flags |= (u1)(0x1 << flag_number); const u1 bit = 1 << flag_number;
u1 compare_value;
do {
compare_value = _header._struct._flags;
if ((compare_value & bit) == bit) {
// already set.
return false;
}
} while (compare_value != Atomic::cmpxchg(&_header._struct._flags, compare_value, static_cast<u1>(compare_value | bit)));
return true;
} }
bool clear_flag_at(u1 flag_number) {
const u1 bit = 1 << flag_number;
u1 compare_value;
u1 exchange_value;
do {
compare_value = _header._struct._flags;
if ((compare_value & bit) == 0) {
// already cleaed.
return false;
}
exchange_value = compare_value & ~bit;
} while (compare_value != Atomic::cmpxchg(&_header._struct._flags, compare_value, exchange_value));
return true;
}
bool flag_at(u1 flag_number) const { bool flag_at(u1 flag_number) const {
return (_header._struct._flags & (0x1 << flag_number)) != 0; return (flags() & (1 << flag_number)) != 0;
} }
// Low-level support for code generation. // Low-level support for code generation.
@ -491,11 +516,12 @@ protected:
enum : u1 { enum : u1 {
// null_seen: // null_seen:
// saw a null operand (cast/aastore/instanceof) // saw a null operand (cast/aastore/instanceof)
null_seen_flag = DataLayout::first_flag + 0, null_seen_flag = DataLayout::first_flag + 0,
exception_handler_entered_flag = null_seen_flag + 1 exception_handler_entered_flag = null_seen_flag + 1,
deprecated_method_callsite_flag = exception_handler_entered_flag + 1
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
// bytecode threw any exception // bytecode threw any exception
, exception_seen_flag = exception_handler_entered_flag + 1 , exception_seen_flag = deprecated_method_callsite_flag + 1
#endif #endif
}; };
enum { bit_cell_count = 0 }; // no additional data fields needed. enum { bit_cell_count = 0 }; // no additional data fields needed.
@ -519,6 +545,9 @@ public:
// Consulting it allows the compiler to avoid setting up null_check traps. // Consulting it allows the compiler to avoid setting up null_check traps.
bool null_seen() { return flag_at(null_seen_flag); } bool null_seen() { return flag_at(null_seen_flag); }
void set_null_seen() { set_flag_at(null_seen_flag); } void set_null_seen() { set_flag_at(null_seen_flag); }
bool deprecated_method_call_site() const { return flag_at(deprecated_method_callsite_flag); }
bool set_deprecated_method_call_site() { return data()->set_flag_at(deprecated_method_callsite_flag); }
bool clear_deprecated_method_call_site() { return data()->clear_flag_at(deprecated_method_callsite_flag); }
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
// true if an exception was thrown at the specific BCI // true if an exception was thrown at the specific BCI

View File

@ -81,6 +81,9 @@
#ifdef COMPILER1 #ifdef COMPILER1
#include "c1/c1_Runtime1.hpp" #include "c1/c1_Runtime1.hpp"
#endif #endif
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
// Shared stub locations // Shared stub locations
RuntimeStub* SharedRuntime::_wrong_method_blob; RuntimeStub* SharedRuntime::_wrong_method_blob;
@ -1342,6 +1345,7 @@ bool SharedRuntime::resolve_sub_helper_internal(methodHandle callee_method, cons
CompiledStaticCall::compute_entry(callee_method, is_nmethod, static_call_info); CompiledStaticCall::compute_entry(callee_method, is_nmethod, static_call_info);
} }
JFR_ONLY(bool patched_caller = false;)
// grab lock, check for deoptimization and potentially patch caller // grab lock, check for deoptimization and potentially patch caller
{ {
CompiledICLocker ml(caller_nm); CompiledICLocker ml(caller_nm);
@ -1371,6 +1375,7 @@ bool SharedRuntime::resolve_sub_helper_internal(methodHandle callee_method, cons
if (!inline_cache->set_to_monomorphic(virtual_call_info)) { if (!inline_cache->set_to_monomorphic(virtual_call_info)) {
return false; return false;
} }
JFR_ONLY(patched_caller = true;)
} }
} else { } else {
if (VM_Version::supports_fast_class_init_checks() && if (VM_Version::supports_fast_class_init_checks() &&
@ -1383,10 +1388,14 @@ bool SharedRuntime::resolve_sub_helper_internal(methodHandle callee_method, cons
if (is_nmethod && caller_nm->method()->is_continuation_enter_intrinsic()) { if (is_nmethod && caller_nm->method()->is_continuation_enter_intrinsic()) {
ssc->compute_entry_for_continuation_entry(callee_method, static_call_info); ssc->compute_entry_for_continuation_entry(callee_method, static_call_info);
} }
if (ssc->is_clean()) ssc->set(static_call_info); if (ssc->is_clean()) {
ssc->set(static_call_info);
JFR_ONLY(patched_caller = true;)
}
} }
} }
} // unlock CompiledICLocker } // unlock CompiledICLocker
JFR_ONLY(if (patched_caller) Jfr::on_backpatching(callee_method(), THREAD);)
return true; return true;
} }

View File

@ -49,6 +49,7 @@ import jdk.jfr.events.StackFilter;
import jdk.jfr.internal.JVM; import jdk.jfr.internal.JVM;
import jdk.jfr.internal.settings.CutoffSetting; import jdk.jfr.internal.settings.CutoffSetting;
import jdk.jfr.internal.settings.EnabledSetting; import jdk.jfr.internal.settings.EnabledSetting;
import jdk.jfr.internal.settings.LevelSetting;
import jdk.jfr.internal.settings.PeriodSetting; import jdk.jfr.internal.settings.PeriodSetting;
import jdk.jfr.internal.settings.StackTraceSetting; import jdk.jfr.internal.settings.StackTraceSetting;
import jdk.jfr.internal.settings.ThresholdSetting; import jdk.jfr.internal.settings.ThresholdSetting;
@ -69,6 +70,7 @@ public final class EventControl {
private static final Type TYPE_CUTOFF = TypeLibrary.createType(CutoffSetting.class); private static final Type TYPE_CUTOFF = TypeLibrary.createType(CutoffSetting.class);
private static final Type TYPE_THROTTLE = TypeLibrary.createType(ThrottleSetting.class); private static final Type TYPE_THROTTLE = TypeLibrary.createType(ThrottleSetting.class);
private static final long STACK_FILTER_ID = Type.getTypeId(StackFilter.class); private static final long STACK_FILTER_ID = Type.getTypeId(StackFilter.class);
private static final Type TYPE_LEVEL = TypeLibrary.createType(LevelSetting.class);
private final ArrayList<SettingControl> settingControls = new ArrayList<>(); private final ArrayList<SettingControl> settingControls = new ArrayList<>();
private final ArrayList<NamedControl> namedControls = new ArrayList<>(5); private final ArrayList<NamedControl> namedControls = new ArrayList<>(5);
@ -91,6 +93,9 @@ public final class EventControl {
if (eventType.hasThrottle()) { if (eventType.hasThrottle()) {
addControl(Throttle.NAME, defineThrottle(eventType)); addControl(Throttle.NAME, defineThrottle(eventType));
} }
if (eventType.hasLevel()) {
addControl(Level.NAME, defineLevel(eventType));
}
addControl(Enabled.NAME, defineEnabled(eventType)); addControl(Enabled.NAME, defineEnabled(eventType));
addStackFilters(eventType); addStackFilters(eventType);
@ -337,6 +342,14 @@ public final class EventControl {
return new Control(new ThrottleSetting(type), def); return new Control(new ThrottleSetting(type), def);
} }
private static Control defineLevel(PlatformEventType type) {
Level level = type.getAnnotation(Level.class);
String[] values = level.value();
String def = values[0];
type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_LEVEL, Level.NAME, def, Collections.emptyList()));
return new Control(new LevelSetting(type, values), def);
}
private static Control definePeriod(PlatformEventType type) { private static Control definePeriod(PlatformEventType type) {
Period period = type.getAnnotation(Period.class); Period period = type.getAnnotation(Period.class);
String def = "everyChunk"; String def = "everyChunk";

View File

@ -659,4 +659,12 @@ public final class JVM {
* @param stackFilterId the stack filter ID to unregister * @param stackFilterId the stack filter ID to unregister
*/ */
public static native void unregisterStackFilter(long stackFilterId); public static native void unregisterStackFilter(long stackFilterId);
/**
* Sets bits used for event settings, like cutoff(ticks) and level
*
* @param eventTypeId the id of the event type
* @param value
*/
public static native void setMiscellaneous(long eventTypeId, long value);
} }

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2023, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.jfr.internal;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jdk.jfr.MetadataDefinition;
/**
* Event annotation, determines filtering level.
*
* This settings is only supported for JVM events.
*
* @since 22
*/
@MetadataDefinition
@Target({ ElementType.TYPE })
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Level {
/**
* Settings name {@code "level"} for configuring filtering level.
*/
public static final String NAME = "level";
/**
* Levels, for example {@code "forRemoval", "all"}.
*
* @return the levels, default { "forRemoval", "all" }, not {@code null}
*/
String[] value() default {};
}

View File

@ -81,6 +81,7 @@ public final class MetadataLoader {
private final boolean stackTrace; private final boolean stackTrace;
private final boolean cutoff; private final boolean cutoff;
private final boolean throttle; private final boolean throttle;
private final String level;
private final boolean isEvent; private final boolean isEvent;
private final boolean isRelation; private final boolean isRelation;
private final boolean experimental; private final boolean experimental;
@ -103,6 +104,7 @@ public final class MetadataLoader {
period = dis.readUTF(); period = dis.readUTF();
cutoff = dis.readBoolean(); cutoff = dis.readBoolean();
throttle = dis.readBoolean(); throttle = dis.readBoolean();
level = dis.readUTF();
experimental = dis.readBoolean(); experimental = dis.readBoolean();
internal = dis.readBoolean(); internal = dis.readBoolean();
id = dis.readLong(); id = dis.readLong();
@ -307,6 +309,13 @@ public final class MetadataLoader {
aes.add(STACK_TRACE); aes.add(STACK_TRACE);
} }
} }
if (!t.level.isEmpty()) {
String[] levels = t.level.split(",");
for (int i = 0; i < levels.length; i++) {
levels[i] = levels[i].strip();
}
aes.add(new AnnotationElement(Level.class, levels));
}
if (t.cutoff) { if (t.cutoff) {
aes.add(new AnnotationElement(Cutoff.class, Cutoff.INFINITY)); aes.add(new AnnotationElement(Cutoff.class, Cutoff.INFINITY));
} }

View File

@ -73,6 +73,7 @@ public final class MetadataRepository {
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType); EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
pEventType.setHasCutoff(eventType.getAnnotation(Cutoff.class) != null); pEventType.setHasCutoff(eventType.getAnnotation(Cutoff.class) != null);
pEventType.setHasThrottle(eventType.getAnnotation(Throttle.class) != null); pEventType.setHasThrottle(eventType.getAnnotation(Throttle.class) != null);
pEventType.setHasLevel(eventType.getAnnotation(Level.class) != null);
pEventType.setHasPeriod(eventType.getAnnotation(Period.class) != null); pEventType.setHasPeriod(eventType.getAnnotation(Period.class) != null);
// Must add hook before EventControl is created as it removes // Must add hook before EventControl is created as it removes
// annotations, such as Period and Threshold. // annotations, such as Period and Threshold.

View File

@ -65,6 +65,7 @@ public final class PlatformEventType extends Type {
private boolean markForInstrumentation; private boolean markForInstrumentation;
private boolean registered = true; private boolean registered = true;
private boolean committable = enabled && registered; private boolean committable = enabled && registered;
private boolean hasLevel = false;
// package private // package private
PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) { PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
@ -142,7 +143,17 @@ public final class PlatformEventType extends Type {
public void setCutoff(long cutoffNanos) { public void setCutoff(long cutoffNanos) {
if (isJVM) { if (isJVM) {
long cutoffTicks = JVMSupport.nanosToTicks(cutoffNanos); long cutoffTicks = JVMSupport.nanosToTicks(cutoffNanos);
JVM.setCutoff(getId(), cutoffTicks); JVM.setMiscellaneous(getId(), cutoffTicks);
}
}
public void setLevel(long level) {
setMiscellaneous(level);
}
private void setMiscellaneous(long value) {
if (isJVM) {
JVM.setMiscellaneous(getId(), value);
} }
} }
@ -156,6 +167,14 @@ public final class PlatformEventType extends Type {
this.hasPeriod = hasPeriod; this.hasPeriod = hasPeriod;
} }
public void setHasLevel(boolean hasLevel) {
this.hasLevel = hasLevel;
}
public boolean hasLevel() {
return this.hasLevel;
}
public boolean hasStackTrace() { public boolean hasStackTrace() {
return getField(ImplicitFields.STACK_TRACE) != null; return getField(ImplicitFields.STACK_TRACE) != null;
} }

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2023, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.jfr.internal.settings;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import jdk.jfr.Label;
import jdk.jfr.MetadataDefinition;
import jdk.jfr.Name;
import jdk.jfr.internal.PlatformEventType;
import jdk.jfr.internal.Type;
@MetadataDefinition
@Label("Level")
@Name(Type.SETTINGS_PREFIX + "Level")
public class LevelSetting extends JDKSettingControl {
private final PlatformEventType eventType;
private final List<String> levels;
private String value;
public LevelSetting(PlatformEventType eventType, String[] levels) {
this.eventType = Objects.requireNonNull(eventType);
this.levels = Arrays.asList(Objects.requireNonNull(levels));
}
@Override
public String combine(Set<String> values) {
int maxIndex = 0;
for (String value : values) {
maxIndex = Math.max(maxIndex, indexOf(value));
}
return levels.get(maxIndex);
}
@Override
public void setValue(String value) {
this.value = value;
this.eventType.setLevel(indexOf(value));
}
@Override
public String getValue() {
return value;
}
private int indexOf(String value) {
int index = levels.indexOf(value);
return index < 0 ? 0 : index;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2023, 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.
*/
package jdk.jfr.internal.test;
public class DeprecatedMethods {
public static int counter;
@Deprecated
public static void deprecated() {
counter++;
}
@Deprecated(since = "0")
public static void deprecatedSince() {
counter++;
}
@Deprecated(forRemoval = true)
public static void deprecatedForRemoval() {
counter++;
}
@Deprecated(since = "0", forRemoval = true)
public static void deprecatedSinceForRemoval() {
counter++;
}
@Deprecated
public static void reflectionDeprecated() {
counter++;
}
@Deprecated(since = "0")
public static void reflectionDeprecatedSince() {
counter++;
}
@Deprecated(forRemoval = true)
public static void reflectionDeprecatedForRemoval() {
counter++;
}
@Deprecated(since = "0", forRemoval = true)
public static void reflectionDeprecatedSinceForRemoval() {
counter++;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2023, 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.
*/
package jdk.jfr.internal.test;
@Deprecated(since = "0")
public class DeprecatedThing {
public int counter;
public void foo() {
bar();
}
public void zoo() {
System.out.println("Zoo invoked");
for (int i = 0; i < 1_000_000; i++) {
bar();
}
}
private void bar() {
baz();
}
public void baz() {
inc();
}
private void inc() {
counter++;
}
@Deprecated(forRemoval = true)
public void instanceDeprecatedForRemoval() {
for (int i = 0; i < 1_000_000; i++) {
inc();
}
}
@Deprecated(since = "0", forRemoval = true)
public void instanceDeprecatedSinceForRemoval() {
counter++;
}
}

View File

@ -915,6 +915,12 @@
<setting name="period">endChunk</setting> <setting name="period">endChunk</setting>
</event> </event>
<event name="jdk.DeprecatedInvocation">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="level">forRemoval</setting>
</event>

View File

@ -915,6 +915,11 @@
<setting name="period">endChunk</setting> <setting name="period">endChunk</setting>
</event> </event>
<event name="jdk.DeprecatedInvocation">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="level">forRemoval</setting>
</event>

View File

@ -0,0 +1,240 @@
/*
* Copyright (c) 2023, 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.
*/
package jdk.jfr.event.runtime;
import java.util.List;
import java.util.ArrayList;
import jdk.jfr.consumer.RecordedMethod;
import jdk.jfr.consumer.RecordedEvent;
import jdk.jfr.consumer.RecordedStackTrace;
import jdk.jfr.consumer.RecordedFrame;
import jdk.jfr.internal.test.DeprecatedMethods;
import jdk.jfr.internal.test.DeprecatedThing;
import jdk.jfr.Recording;
import jdk.test.lib.jfr.EventNames;
import jdk.test.lib.jfr.Events;
import static jdk.test.lib.Asserts.assertTrue;
import static jdk.test.lib.Asserts.assertNull;
import static jdk.test.lib.Asserts.assertNotNull;
/**
* @test
* @key jfr
* @requires vm.hasJFR
* @modules jdk.jfr/jdk.jfr.internal.test
* @library /test/lib
*
* @run main/othervm/timeout=300 -XX:StartFlightRecording:settings=none,+jdk.DeprecatedInvocation#enabled=true
* jdk.jfr.event.runtime.TestDeprecatedEvent Default
* @run main/othervm/timeout=300 -Xint -XX:+UseInterpreter -XX:StartFlightRecording:settings=none,+jdk.DeprecatedInvocation#enabled=true
* jdk.jfr.event.runtime.TestDeprecatedEvent Interpreter
*
* @run main/othervm/timeout=300 -Xcomp -XX:-UseInterpreter -XX:StartFlightRecording:settings=none,+jdk.DeprecatedInvocation#enabled=true
* jdk.jfr.event.runtime.TestDeprecatedEvent Compiler
*
* @run main/othervm/timeout=300 -Xcomp -XX:TieredStopAtLevel=1 -XX:-UseInterpreter -XX:StartFlightRecording:settings=none,+jdk.DeprecatedInvocation#enabled=true
* jdk.jfr.event.runtime.TestDeprecatedEvent C1
*
* @run main/othervm/timeout=300 -Xcomp -XX:TieredStopAtLevel=4 -XX:-TieredCompilation -XX:-UseInterpreter -XX:StartFlightRecording:settings=none,+jdk.DeprecatedInvocation#enabled=true
* jdk.jfr.event.runtime.TestDeprecatedEvent C2
*
*/
public class TestDeprecatedEvent {
/*
*
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
* jdk.jfr.event.runtime.TestDeprecatedEvent JVMCI
*
*/
public static String EVENT_NAME = EventNames.DeprecatedInvocation;
private static String mode;
public static int counter;
public static void main(String... args) throws Exception {
mode = args[0];
testDeprecatedLevelAll();
testDeprecatedLevelAllRetained();
testReflectionAll();
testDeprecatedLevelForRemovalRetained();
}
private static void testDeprecatedLevelAll() throws Exception {
try (Recording r = new Recording()) {
r.enable(EVENT_NAME).with("level", "all");
r.start();
testLevelAll();
r.stop();
validateLevelAll(r);
}
}
@Deprecated(forRemoval = true)
public static void userDeprecatedForRemoval() {
counter++;
}
private static void testLevelAll() throws Exception {
// Methods individually decorated.
DeprecatedMethods.deprecated();
DeprecatedMethods.deprecatedSince();
DeprecatedMethods.deprecatedForRemoval();
DeprecatedMethods.deprecatedSinceForRemoval();
// Class level @deprecated annotation
// @Deprecated(since = "0")
DeprecatedThing t = new DeprecatedThing();
t.instanceDeprecatedForRemoval();
t.instanceDeprecatedSinceForRemoval();
t.foo();
t.zoo();
// Invoke a deprecated method in the users code
// to verify the negative case, i.e. that this
// invocation is not reported.
userDeprecatedForRemoval();
}
private static void validateLevelAll(Recording r) throws Exception {
List<RecordedEvent> events = Events.fromRecording(r);
printInvocations(events, "all");
assertMethod(events, "testLevelAll", "deprecated");
assertMethod(events, "testLevelAll", "deprecatedSince");
assertMethod(events, "testLevelAll", "deprecatedForRemoval");
assertMethod(events, "testLevelAll", "deprecatedSinceForRemoval");
assertMethod(events, "testLevelAll", "instanceDeprecatedForRemoval");
assertMethod(events, "testLevelAll", "instanceDeprecatedSinceForRemoval");
assertMethod(events, "testLevelAll", "foo");
assertMethod(events, "testLevelAll", "zoo");
// Negative case
try {
assertMethod(events, "testLevelAll", "userDeprecatedForRemoval");
throw new RuntimeException("Invocation of a deprecated method in user code should not be reported");
} catch (Exception e) {
// Expected
}
}
// Does not invoke any deprecated methods. We only verify
// that all previously invoked methods are still retained
// when starting and stopping a subsequent recording.
private static void testDeprecatedLevelAllRetained() throws Exception {
try (Recording r = new Recording()) {
r.enable(EVENT_NAME).with("level", "all");
r.start();
r.stop();
validateLevelAll(r);
}
}
private static void testReflectionAll() throws Exception {
try (Recording r = new Recording()) {
r.enable(EVENT_NAME).with("level", "all");
r.start();
DeprecatedMethods.class.getMethod("reflectionDeprecated").invoke(null);
DeprecatedMethods.class.getMethod("reflectionDeprecatedSince").invoke(null);
DeprecatedMethods.class.getMethod("reflectionDeprecatedForRemoval").invoke(null);
DeprecatedMethods.class.getMethod("reflectionDeprecatedSinceForRemoval").invoke(null);
r.stop();
validateReflectionLevelAll(r);
}
}
private static void validateReflectionLevelAll(Recording r) throws Exception {
List<RecordedEvent> events = Events.fromRecording(r);
printInvocations(events, "reflectionAll");
assertMethod(events, "testReflectionAll", "reflectionDeprecated");
assertMethod(events, "testReflectionAll", "reflectionDeprecatedSince");
assertMethod(events, "testReflectionAll", "reflectionDeprecatedForRemoval");
assertMethod(events, "testReflectionAll", "reflectionDeprecatedSinceForRemoval");
}
// Does not invoke any deprecated methods. We only verify
// that all previously invoked methods are still retained
// when starting and stopping a subsequent recording.
private static void testDeprecatedLevelForRemovalRetained() throws Exception {
try (Recording r = new Recording()) {
r.enable(EVENT_NAME).with("level", "forRemoval");
r.start();
r.stop();
validateLevelForRemoval(r);
}
}
private static void validateLevelForRemoval(Recording r) throws Exception {
List<RecordedEvent> events = Events.fromRecording(r);
printInvocations(events, "forRemoval");
assertMethod(events, "testLevelAll", "deprecatedForRemoval");
assertMethod(events, "testLevelAll", "deprecatedSinceForRemoval");
assertMethod(events, "testLevelAll", "instanceDeprecatedForRemoval");
assertMethod(events, "testLevelAll", "instanceDeprecatedSinceForRemoval");
assertMethod(events, "testReflectionAll", "reflectionDeprecatedForRemoval");
assertMethod(events, "testReflectionAll", "reflectionDeprecatedSinceForRemoval");
}
private static void assertMethod(List<RecordedEvent> events, String caller, String method) throws Exception {
for (RecordedEvent e : events) {
RecordedMethod deprecatedMethod = e.getValue("method");
boolean forRemoval = e.getValue("forRemoval");
RecordedStackTrace stacktrace = e.getStackTrace();
assertNotNull(stacktrace, "should have a stacktrace");
assertTrue(stacktrace.isTruncated(), "invariant");
List<RecordedFrame> frames = stacktrace.getFrames();
assertTrue(frames.size() == 1, "invariant");
assertTrue(frames.getFirst().isJavaFrame(), "invariant");
RecordedFrame frame = frames.getFirst();
assertTrue(frame.isJavaFrame(), "invariant");
RecordedMethod callerMethod = frame.getMethod();
assertNull(e.getThread(), "should not have a thread");
if (forRemoval) {
assertTrue(deprecatedMethod.getName().endsWith("ForRemoval"), "wrong filtering?");
}
if (deprecatedMethod.getName().equals(method) && callerMethod.getName().equals(caller)){
return;
}
}
throw new Exception("Could not find invocation: " + caller + " -> " + method);
}
private static void printInvocations(List<RecordedEvent> events, String all) {
System.out.println("*** METHOD INVOCATION *** (" + mode + ") level = " + all + " count: " + events.size() + " ***\n");
for (RecordedEvent e : events) {
RecordedMethod deprecatedMethod = e.getValue("method");
boolean forRemoval = e.getValue("forRemoval");
RecordedStackTrace stacktrace = e.getStackTrace();
assertNotNull(stacktrace, "should have a stacktrace");
assertTrue(stacktrace.isTruncated(), "invariant");
List<RecordedFrame> frames = stacktrace.getFrames();
assertTrue(frames.size() == 1, "invariant");
RecordedFrame frame = frames.getFirst();
assertTrue(frame.isJavaFrame(), "invariant");
RecordedMethod callerMethod = frame.getMethod();
int bci = frame.getBytecodeIndex();
int lineNumber = frame.getLineNumber();
assertNull(e.getThread(), "should not have a thread");
System.out.println(callerMethod.getName() + " at bci: " + bci + " line: " + lineNumber + " -> " + deprecatedMethod.getName());
System.out.println(e);
}
System.out.println();
}
}

View File

@ -88,6 +88,7 @@ public class EventNames {
public static final String NativeMemoryUsageTotal = PREFIX + "NativeMemoryUsageTotal"; public static final String NativeMemoryUsageTotal = PREFIX + "NativeMemoryUsageTotal";
public static final String JavaAgent = PREFIX + "JavaAgent"; public static final String JavaAgent = PREFIX + "JavaAgent";
public static final String NativeAgent = PREFIX + "NativeAgent"; public static final String NativeAgent = PREFIX + "NativeAgent";
public static final String DeprecatedInvocation = PREFIX + "DeprecatedInvocation";
// This event is hard to test // This event is hard to test
public static final String ReservedStackActivation = PREFIX + "ReservedStackActivation"; public static final String ReservedStackActivation = PREFIX + "ReservedStackActivation";