diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java index 6b89d02ad2f..3497d03292d 100644 --- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java +++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -198,6 +198,7 @@ public class GenerateJfrFiles { String period = ""; boolean cutoff; boolean throttle; + String level = ""; boolean experimental; boolean internal; long id; @@ -222,6 +223,7 @@ public class GenerateJfrFiles { pos.writeUTF(period); pos.writeBoolean(cutoff); pos.writeBoolean(throttle); + pos.writeUTF(level); pos.writeBoolean(experimental); pos.writeBoolean(internal); pos.writeLong(id); @@ -520,6 +522,7 @@ public class GenerateJfrFiles { currentType.startTime = getBoolean(attributes, "startTime", true); currentType.period = getString(attributes, "period"); currentType.cutoff = getBoolean(attributes, "cutoff", false); + currentType.level = getString(attributes, "level"); currentType.throttle = getBoolean(attributes, "throttle", false); currentType.commitState = getString(attributes, "commitState"); currentType.isEvent = "Event".equals(qName); @@ -651,7 +654,7 @@ public class GenerateJfrFiles { out.write(""); out.write("struct jfrNativeEventSetting {"); out.write(" jlong threshold_ticks;"); - out.write(" jlong cutoff_ticks;"); + out.write(" jlong miscellaneous;"); out.write(" u1 stacktrace;"); out.write(" u1 enabled;"); out.write(" u1 large;"); diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index b8d7a21ef4c..0c171d0cf0b 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -200,6 +200,7 @@ class ciMethod : public ciMetadata { bool intrinsic_candidate() const { return get_Method()->intrinsic_candidate(); } bool is_static_initializer() const { return get_Method()->is_static_initializer(); } 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 { if (intrinsic_id() == vmIntrinsics::_blackhole) { diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index a7447211a1c..b7485b7db52 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -951,6 +951,8 @@ public: _field_Stable, _jdk_internal_vm_annotation_ReservedStackAccess, _jdk_internal_ValueBased, + _java_lang_Deprecated, + _java_lang_Deprecated_for_removal, _annotation_LIMIT }; const Location _location; @@ -1122,6 +1124,7 @@ static void parse_annotations(const ConstantPool* const cp, s_tag_val = 's', // payload is String s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;' s_size = 9, + b_tag_val = 'Z', // payload is boolean min_size = 6 // smallest possible size (zero members) }; // 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); if (AnnotationCollector::_unknown == id) continue; 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) { // @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 return _jdk_internal_ValueBased; } + case VM_SYMBOL_ENUM_NAME(java_lang_Deprecated): { + return _java_lang_Deprecated; + } default: { break; } @@ -2003,6 +2035,10 @@ void MethodAnnotationCollector::apply_to(const methodHandle& m) { m->set_intrinsic_candidate(); if (has_annotation(_jdk_internal_vm_annotation_ReservedStackAccess)) 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) { @@ -2016,6 +2052,22 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) { ik->set_is_value_based(); } } + if (has_annotation(_java_lang_Deprecated)) { + Array* 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* 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 diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index b450c125053..16ddc2602b1 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -162,7 +162,9 @@ class SerializeClosure; 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_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \ - \ + template(java_lang_Deprecated, "Ljava/lang/Deprecated;") \ + template(since, "since") \ + template(for_removal, "forRemoval") \ /* Java runtime version access */ \ template(java_lang_VersionProps, "java/lang/VersionProps") \ template(java_version_name, "java_version") \ diff --git a/src/hotspot/share/jfr/instrumentation/jfrResolution.cpp b/src/hotspot/share/jfr/instrumentation/jfrResolution.cpp deleted file mode 100644 index 63854335609..00000000000 --- a/src/hotspot/share/jfr/instrumentation/jfrResolution.cpp +++ /dev/null @@ -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 diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 99faa108bfd..45848fb0243 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "jfr/instrumentation/jfrResolution.hpp" #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.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/repository/jfrRepository.hpp" +#include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "runtime/java.hpp" @@ -67,9 +67,7 @@ void Jfr::on_create_vm_3() { } void Jfr::on_unloading_classes() { - if (JfrRecorder::is_created()) { - JfrCheckpointManager::on_unloading_classes(); - } + JfrCheckpointManager::on_unloading_classes(); } bool Jfr::is_excluded(Thread* t) { @@ -104,6 +102,10 @@ void Jfr::on_resolution(const CallInfo& info, TRAPS) { JfrResolution::on_runtime_resolution(info, THREAD); } +void Jfr::on_backpatching(const Method* callee_method, JavaThread* jt) { + JfrResolution::on_backpatching(callee_method, jt); +} + #ifdef COMPILER1 void Jfr::on_resolution(const GraphBuilder* builder, const ciKlass* holder, const ciMethod* target) { JfrResolution::on_c1_resolution(builder, holder, target); diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 89ecf5bc798..af492f85123 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -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. * * 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 bool on_flight_recorder_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 diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 82f26d7bdd0..db534b6df3c 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -45,6 +45,7 @@ #include "jfr/instrumentation/jfrEventClassTransformer.hpp" #include "jfr/instrumentation/jfrJvmtiAgent.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" +#include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/support/jfrJdkJfrEvent.hpp" #include "jfr/support/jfrKlassUnloading.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(); 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)) JfrEventThrottler::configure(static_cast(event_type_id), event_sample_size, period_ms); return JNI_TRUE; 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)) return JfrChunkRotation::should_rotate() ? JNI_TRUE : JNI_FALSE; NO_TRANSITION_END diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index b37841aeac2..c75a4c97219 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -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); -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); +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); jboolean JNICALL jfr_should_rotate_disk(JNIEnv* env, jclass jvm); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp index f8475881ff8..338f63fbc4f 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp @@ -82,7 +82,7 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (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*)"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*)"emitOldObjectSamples", (char*)"(JZZ)V", (void*)jfr_emit_old_object_samples, (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk, diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index ffd973696f1..9f6679c93eb 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -416,9 +416,9 @@ static void install_type_set_blobs() { 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"); - const JfrBlobHandle blob = copy ? writer.copy() : writer.move(); + const JfrBlobHandle blob = writer.copy(); if (saved_type_set_blobs.valid()) { saved_type_set_blobs->set_next(blob); } else { @@ -438,9 +438,8 @@ void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) { } void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); assert(LeakProfiler::is_running(), "invariant"); if (writer.has_data() && ObjectSampler::sampler()->last() != nullptr) { - save_type_set_blob(writer, true); + save_type_set_blob(writer); } } diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 7977b732eef..c1f626a8192 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1252,6 +1252,13 @@ + + + + + + diff --git a/src/hotspot/share/jfr/metadata/metadata.xsd b/src/hotspot/share/jfr/metadata/metadata.xsd index ffef3d932e3..9d6cdd3d744 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xsd +++ b/src/hotspot/share/jfr/metadata/metadata.xsd @@ -1,7 +1,7 @@