8282420: JFR: Remove event handlers

Reviewed-by: mgronlun
This commit is contained in:
Erik Gahlin 2022-05-10 16:14:07 +00:00
parent 04bba07d65
commit 0f3773635d
80 changed files with 2643 additions and 1273 deletions

View File

@ -46,6 +46,10 @@
#include "runtime/vm_version.hpp" #include "runtime/vm_version.hpp"
#include "utilities/bitMap.inline.hpp" #include "utilities/bitMap.inline.hpp"
#include "utilities/powerOfTwo.hpp" #include "utilities/powerOfTwo.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
class BlockListBuilder { class BlockListBuilder {
private: private:
@ -1911,7 +1915,6 @@ Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target,
return obj_args; return obj_args;
} }
void GraphBuilder::invoke(Bytecodes::Code code) { void GraphBuilder::invoke(Bytecodes::Code code) {
bool will_link; bool will_link;
ciSignature* declared_signature = NULL; ciSignature* declared_signature = NULL;
@ -1920,6 +1923,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
const Bytecodes::Code bc_raw = stream()->cur_bc_raw(); const Bytecodes::Code bc_raw = stream()->cur_bc_raw();
assert(declared_signature != NULL, "cannot be null"); assert(declared_signature != NULL, "cannot be null");
assert(will_link == target->is_loaded(), ""); assert(will_link == target->is_loaded(), "");
JFR_ONLY(Jfr::on_resolution(this, holder, target); CHECK_BAILOUT();)
ciInstanceKlass* klass = target->holder(); ciInstanceKlass* klass = target->holder();
assert(!target->is_loaded() || klass->is_loaded(), "loaded target must imply loaded klass"); assert(!target->is_loaded() || klass->is_loaded(), "loaded target must imply loaded klass");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2022, 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
@ -36,6 +36,7 @@
class MemoryBuffer; class MemoryBuffer;
class GraphBuilder { class GraphBuilder {
friend class JfrResolution;
private: private:
// Per-scope data. These are pushed and popped as we descend into // Per-scope data. These are pushed and popped as we descend into
// inlined methods. Currently in order to generate good code in the // inlined methods. Currently in order to generate good code in the

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2022, 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
@ -53,8 +53,6 @@ private:
DEBUG_ONLY(bool sid_ok();) DEBUG_ONLY(bool sid_ok();)
Symbol* get_symbol() const { return _symbol; }
const char* type_string() { return "ciSymbol"; } const char* type_string() { return "ciSymbol"; }
void print_impl(outputStream* st); void print_impl(outputStream* st);
@ -106,6 +104,9 @@ public:
bool equals(ciSymbol* obj) { return this->_symbol == obj->get_symbol(); } bool equals(ciSymbol* obj) { return this->_symbol == obj->get_symbol(); }
bool is_signature_polymorphic_name() const; bool is_signature_polymorphic_name() const;
Symbol* get_symbol() const { return _symbol; }
}; };
#endif // SHARE_CI_CISYMBOL_HPP #endif // SHARE_CI_CISYMBOL_HPP

View File

@ -60,6 +60,10 @@
#include "runtime/signature.hpp" #include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "runtime/vmThread.hpp" #include "runtime/vmThread.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
// Implementation of CallInfo // Implementation of CallInfo
@ -1092,6 +1096,7 @@ void LinkResolver::resolve_static_call(CallInfo& result,
// setup result // setup result
result.set_static(resolved_klass, methodHandle(THREAD, resolved_method), CHECK); result.set_static(resolved_klass, methodHandle(THREAD, resolved_method), CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
} }
// throws linktime exceptions // throws linktime exceptions
@ -1297,6 +1302,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
// setup result // setup result
result.set_static(resolved_klass, sel_method, CHECK); result.set_static(resolved_klass, sel_method, CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
} }
void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, Klass* receiver_klass, void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, Klass* receiver_klass,
@ -1417,6 +1423,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
} }
// setup result // setup result
result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
} }
void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* recv_klass, void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* recv_klass,
@ -1528,6 +1535,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result,
// This sets up the nonvirtual form of "virtual" call (as needed for final and private methods) // This sets up the nonvirtual form of "virtual" call (as needed for final and private methods)
result.set_virtual(resolved_klass, resolved_method, resolved_method, index, CHECK); result.set_virtual(resolved_klass, resolved_method, resolved_method, index, CHECK);
} }
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
} }
@ -1699,6 +1707,7 @@ bool LinkResolver::resolve_previously_linked_invokehandle(CallInfo& result, cons
methodHandle method(THREAD, cpce->f1_as_method()); methodHandle method(THREAD, cpce->f1_as_method());
Handle appendix(THREAD, cpce->appendix_if_resolved(pool)); Handle appendix(THREAD, cpce->appendix_if_resolved(pool));
result.set_handle(resolved_klass, method, appendix, CHECK_false); result.set_handle(resolved_klass, method, appendix, CHECK_false);
JFR_ONLY(Jfr::on_resolution(result, CHECK_false);)
return true; return true;
} else { } else {
return false; return false;
@ -1730,6 +1739,7 @@ void LinkResolver::resolve_handle_call(CallInfo& result,
Handle resolved_appendix; Handle resolved_appendix;
Method* resolved_method = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK); Method* resolved_method = lookup_polymorphic_method(link_info, &resolved_appendix, CHECK);
result.set_handle(resolved_klass, methodHandle(THREAD, resolved_method), resolved_appendix, CHECK); result.set_handle(resolved_klass, methodHandle(THREAD, resolved_method), resolved_appendix, CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
} }
void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) { void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) {
@ -1811,6 +1821,7 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
bootstrap_specifier.resolve_newly_linked_invokedynamic(result, CHECK); bootstrap_specifier.resolve_newly_linked_invokedynamic(result, CHECK);
// Exceptions::wrap_dynamic_exception not used because // Exceptions::wrap_dynamic_exception not used because
// set_handle doesn't throw linkage errors // set_handle doesn't throw linkage errors
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
} }
// Selected method is abstract. // Selected method is abstract.

View File

@ -32,13 +32,13 @@
#include "classfile/modules.hpp" #include "classfile/modules.hpp"
#include "classfile/stackMapTable.hpp" #include "classfile/stackMapTable.hpp"
#include "classfile/symbolTable.hpp" #include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verificationType.hpp" #include "classfile/verificationType.hpp"
#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodes.hpp"
#include "jfr/instrumentation/jfrEventClassTransformer.hpp" #include "jfr/instrumentation/jfrEventClassTransformer.hpp"
#include "jfr/jfr.hpp" #include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/jni/jfrUpcalls.hpp" #include "jfr/jni/jfrUpcalls.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/support/jfrJdkJfrEvent.hpp" #include "jfr/support/jfrJdkJfrEvent.hpp"
#include "jfr/utilities/jfrBigEndian.hpp" #include "jfr/utilities/jfrBigEndian.hpp"
@ -47,16 +47,19 @@
#include "memory/allocation.inline.hpp" #include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/array.hpp" #include "oops/array.hpp"
#include "oops/constMethod.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/klass.inline.hpp" #include "oops/klass.inline.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiRedefineClasses.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/jniHandles.hpp" #include "runtime/jniHandles.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "utilities/exceptions.hpp" #include "utilities/exceptions.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
static const u2 number_of_new_methods = 5; static const u2 number_of_new_methods = 5;
@ -68,7 +71,7 @@ static const char* utf8_constants[] = {
"Code", // 0 "Code", // 0
"J", // 1 "J", // 1
"commit", // 2 "commit", // 2
"eventHandler", // 3 "eventConfiguration", // 3
"duration", // 4 "duration", // 4
"begin", // 5 "begin", // 5
"()V", // 6 "()V", // 6
@ -77,7 +80,7 @@ static const char* utf8_constants[] = {
"end", // 9 "end", // 9
"shouldCommit", // 10 "shouldCommit", // 10
"startTime", // 11 // LAST_REQUIRED_UTF8 "startTime", // 11 // LAST_REQUIRED_UTF8
"Ljdk/jfr/internal/handlers/EventHandler;", // 12 "Ljdk/jfr/internal/event/EventConfiguration;", // 12
"Ljava/lang/Object;", // 13 "Ljava/lang/Object;", // 13
"<clinit>", // 14 "<clinit>", // 14
"jdk/jfr/FlightRecorder", // 15 "jdk/jfr/FlightRecorder", // 15
@ -95,7 +98,7 @@ enum utf8_req_symbols {
UTF8_REQ_Code, UTF8_REQ_Code,
UTF8_REQ_J_FIELD_DESC, UTF8_REQ_J_FIELD_DESC,
UTF8_REQ_commit, UTF8_REQ_commit,
UTF8_REQ_eventHandler, UTF8_REQ_eventConfiguration,
UTF8_REQ_duration, UTF8_REQ_duration,
UTF8_REQ_begin, UTF8_REQ_begin,
UTF8_REQ_EMPTY_VOID_METHOD_DESC, UTF8_REQ_EMPTY_VOID_METHOD_DESC,
@ -108,7 +111,7 @@ enum utf8_req_symbols {
}; };
enum utf8_opt_symbols { enum utf8_opt_symbols {
UTF8_OPT_eventHandler_FIELD_DESC = NOF_UTF8_REQ_SYMBOLS, UTF8_OPT_eventConfiguration_FIELD_DESC = NOF_UTF8_REQ_SYMBOLS,
UTF8_OPT_LjavaLangObject, UTF8_OPT_LjavaLangObject,
UTF8_OPT_clinit, UTF8_OPT_clinit,
UTF8_OPT_FlightRecorder, UTF8_OPT_FlightRecorder,
@ -565,11 +568,11 @@ static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_i
return writer.current_offset(); return writer.current_offset();
} }
static u2 add_field_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes, bool untypedEventHandler) { static u2 add_field_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes, bool untypedEventConfiguration) {
assert(utf8_indexes != NULL, "invariant"); assert(utf8_indexes != NULL, "invariant");
add_field_info(writer, add_field_info(writer,
utf8_indexes[UTF8_REQ_eventHandler], utf8_indexes[UTF8_REQ_eventConfiguration],
untypedEventHandler ? utf8_indexes[UTF8_OPT_LjavaLangObject] : utf8_indexes[UTF8_OPT_eventHandler_FIELD_DESC], untypedEventConfiguration ? utf8_indexes[UTF8_OPT_LjavaLangObject] : utf8_indexes[UTF8_OPT_eventConfiguration_FIELD_DESC],
true); // static true); // static
add_field_info(writer, add_field_info(writer,
@ -1111,11 +1114,40 @@ static jlong insert_clinit_method(const InstanceKlass* ik,
return writer.current_offset(); return writer.current_offset();
} }
static Symbol* begin = NULL;
static Symbol* end = NULL;
static Symbol* commit = NULL;
static Symbol* isEnabled = NULL;
static Symbol* shouldCommit = NULL;
static Symbol* void_method_sig = NULL;
static Symbol* boolean_method_sig = NULL;
static void initialize_symbols() {
if (begin == NULL) {
begin = SymbolTable::probe("begin", 5);
assert(begin != NULL, "invariant");
end = SymbolTable::probe("end", 3);
assert(end != NULL, "invariant");
commit = SymbolTable::probe("commit", 6);
assert(commit != NULL, "invariant");
isEnabled = SymbolTable::probe("isEnabled", 9);
assert(isEnabled != NULL, "invariant");
shouldCommit = SymbolTable::probe("shouldCommit", 12);
assert(shouldCommit != NULL, "invariant");
void_method_sig = SymbolTable::probe("()V", 3);
assert(void_method_sig != NULL, "invariant");
boolean_method_sig = SymbolTable::probe("()Z", 3);
assert(boolean_method_sig != NULL, "invariant");
}
}
// Caller needs ResourceMark // Caller needs ResourceMark
static ClassFileStream* create_new_bytes_for_event_klass(const InstanceKlass* ik, const ClassFileParser& parser, TRAPS) { static ClassFileStream* schema_extend_event_klass_bytes(const InstanceKlass* ik, const ClassFileParser& parser, TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
initialize_symbols();
static const u2 public_final_flag_mask = JVM_ACC_PUBLIC | JVM_ACC_FINAL; static const u2 public_final_flag_mask = JVM_ACC_PUBLIC | JVM_ACC_FINAL;
const ClassFileStream* const orig_stream = parser.clone_stream(); const ClassFileStream* const orig_stream = parser.clone_stream();
assert(orig_stream != NULL, "invariant");
const int orig_stream_length = orig_stream->length(); const int orig_stream_length = orig_stream->length();
// allocate an identically sized buffer // allocate an identically sized buffer
u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, orig_stream_length); u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, orig_stream_length);
@ -1202,7 +1234,7 @@ static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
u2 orig_cp_len, u2 orig_cp_len,
const Method* clinit_method, const Method* clinit_method,
bool register_klass, bool register_klass,
bool untypedEventHandler, bool untypedEventConfiguration,
TRAPS) { TRAPS) {
assert(utf8_indexes != NULL, "invariant"); assert(utf8_indexes != NULL, "invariant");
u2 added_cp_entries = 0; u2 added_cp_entries = 0;
@ -1212,10 +1244,10 @@ static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
} }
// resolve optional constants // resolve optional constants
utf8_indexes[UTF8_OPT_eventHandler_FIELD_DESC] = untypedEventHandler ? invalid_cp_index : utf8_indexes[UTF8_OPT_eventConfiguration_FIELD_DESC] = untypedEventConfiguration ? invalid_cp_index :
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_eventHandler_FIELD_DESC], orig_cp_len, added_cp_entries, THREAD); find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_eventConfiguration_FIELD_DESC], orig_cp_len, added_cp_entries, THREAD);
utf8_indexes[UTF8_OPT_LjavaLangObject] = untypedEventHandler ? utf8_indexes[UTF8_OPT_LjavaLangObject] = untypedEventConfiguration ?
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LjavaLangObject], orig_cp_len, added_cp_entries, THREAD) : invalid_cp_index; find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LjavaLangObject], orig_cp_len, added_cp_entries, THREAD) : invalid_cp_index;
if (register_klass) { if (register_klass) {
@ -1261,7 +1293,7 @@ static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
return added_cp_entries; return added_cp_entries;
} }
static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik, static u1* schema_extend_event_subklass_bytes(const InstanceKlass* ik,
const ClassFileParser& parser, const ClassFileParser& parser,
jint& size_of_new_bytes, jint& size_of_new_bytes,
TRAPS) { TRAPS) {
@ -1283,7 +1315,7 @@ static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, new_buffer_size); u1* const new_buffer = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, u1, new_buffer_size);
if (new_buffer == NULL) { if (new_buffer == NULL) {
log_error(jfr, system) ("Thread local allocation (native) for " SIZE_FORMAT log_error(jfr, system) ("Thread local allocation (native) for " SIZE_FORMAT
" bytes failed in JfrClassAdapter::on_klass_creation", (size_t)new_buffer_size); " bytes failed in JfrEventClassTransformer::on_klass_creation", static_cast<size_t>(new_buffer_size));
return NULL; return NULL;
} }
assert(new_buffer != NULL, "invariant"); assert(new_buffer != NULL, "invariant");
@ -1382,6 +1414,10 @@ static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
return new_buffer; return new_buffer;
} }
static bool should_force_instrumentation() {
return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation();
}
static void log_pending_exception(oop throwable) { static void log_pending_exception(oop throwable) {
assert(throwable != NULL, "invariant"); assert(throwable != NULL, "invariant");
oop msg = java_lang_Throwable::message(throwable); oop msg = java_lang_Throwable::message(throwable);
@ -1393,73 +1429,254 @@ static void log_pending_exception(oop throwable) {
} }
} }
static bool should_force_instrumentation() { static bool has_pending_exception(TRAPS) {
return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation(); assert(THREAD != NULL, "invariant");
if (HAS_PENDING_EXCEPTION) {
log_pending_exception(PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
return true;
}
return false;
} }
static ClassFileStream* create_new_bytes_for_subklass(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* t) { static bool has_local_method_implementation(const InstanceKlass* ik, const Symbol* name, const Symbol* signature) {
assert(ik != NULL, "invariant");
assert(name != NULL, "invariant");
assert(signature != NULL, "invariant");
return NULL != ik->find_local_method(name, signature, Klass::OverpassLookupMode::skip, Klass::StaticLookupMode::find,
Klass::PrivateLookupMode::find);
}
// If for a subklass, on initial class load, an implementation exist for any of the final methods declared in Event,
// then constraints are considered breached.
static bool invalid_preconditions_for_subklass_on_initial_load(const InstanceKlass* ik) {
assert(ik != NULL, "invariant");
return has_local_method_implementation(ik, begin, void_method_sig) ||
has_local_method_implementation(ik, end, void_method_sig) ||
has_local_method_implementation(ik, commit, void_method_sig) ||
has_local_method_implementation(ik, isEnabled, boolean_method_sig) ||
has_local_method_implementation(ik, shouldCommit, boolean_method_sig);
}
static ClassFileStream* schema_extend_event_subklass_bytes(const InstanceKlass* ik, const ClassFileParser& parser, bool& is_instrumented, TRAPS) {
assert(JdkJfrEvent::is_a(ik), "invariant"); assert(JdkJfrEvent::is_a(ik), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t)); assert(!is_instrumented, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
if (invalid_preconditions_for_subklass_on_initial_load(ik)) {
// Remove the tag denoting this as a jdk.jfr.Event subklass. No instrumentation, hence no events can be written.
// The class is allowed to load as-is, but it is classified as outside of the jfr system.
JdkJfrEvent::remove(ik);
return NULL;
}
jint size_of_new_bytes = 0; jint size_of_new_bytes = 0;
const u1* new_bytes = new_bytes_for_lazy_instrumentation(ik, parser, size_of_new_bytes, t); const u1* new_bytes = schema_extend_event_subklass_bytes(ik, parser, size_of_new_bytes, THREAD);
if (new_bytes == NULL) { if (new_bytes == NULL) {
return NULL; return NULL;
} }
assert(new_bytes != NULL, "invariant"); assert(new_bytes != NULL, "invariant");
assert(size_of_new_bytes > 0, "invariant"); assert(size_of_new_bytes > 0, "invariant");
const bool force_instrumentation = should_force_instrumentation();
bool force_instrumentation = should_force_instrumentation();
if (Jfr::is_recording() || force_instrumentation) { if (Jfr::is_recording() || force_instrumentation) {
jint size_instrumented_data = 0; jint size_of_instrumented_bytes = 0;
unsigned char* instrumented_data = NULL; unsigned char* instrumented_bytes = NULL;
const jclass super = (jclass)JNIHandles::make_local(ik->super()->java_mirror()); const jclass super = static_cast<jclass>(JfrJavaSupport::local_jni_handle(ik->super()->java_mirror(), THREAD));
const jboolean boot_class_loader = ik->class_loader_data()->is_boot_class_loader_data();
JfrUpcalls::new_bytes_eager_instrumentation(JfrTraceId::load_raw(ik), JfrUpcalls::new_bytes_eager_instrumentation(JfrTraceId::load_raw(ik),
force_instrumentation, force_instrumentation,
boot_class_loader,
super, super,
size_of_new_bytes, size_of_new_bytes,
new_bytes, new_bytes,
&size_instrumented_data, &size_of_instrumented_bytes,
&instrumented_data, &instrumented_bytes,
t); THREAD);
if (t->has_pending_exception()) { JfrJavaSupport::destroy_local_jni_handle(super);
log_pending_exception(t->pending_exception()); if (has_pending_exception(THREAD)) {
t->clear_pending_exception();
return NULL; return NULL;
} }
assert(instrumented_data != NULL, "invariant"); assert(instrumented_bytes != NULL, "invariant");
assert(size_instrumented_data > 0, "invariant"); assert(size_of_instrumented_bytes > 0, "invariant");
return new ClassFileStream(instrumented_data, size_instrumented_data, NULL, ClassFileStream::verify); new_bytes = instrumented_bytes;
size_of_new_bytes = size_of_instrumented_bytes;
is_instrumented = true;
} }
return new ClassFileStream(new_bytes, size_of_new_bytes, NULL, ClassFileStream::verify); return new ClassFileStream(new_bytes, size_of_new_bytes, NULL, ClassFileStream::verify);
} }
static bool cache_bytes(InstanceKlass* ik, ClassFileStream* new_stream, InstanceKlass* new_ik, TRAPS) { static bool _force_instrumentation = false;
assert(ik != NULL, "invariant");
void JfrEventClassTransformer::set_force_instrumentation(bool force_instrumentation) {
_force_instrumentation = force_instrumentation;
}
bool JfrEventClassTransformer::is_force_instrumentation() {
return _force_instrumentation;
}
static ClassFileStream* retransform_bytes(const Klass* existing_klass, const ClassFileParser& parser, bool& is_instrumented, TRAPS) {
assert(existing_klass != NULL, "invariant");
assert(!is_instrumented, "invariant");
assert(JdkJfrEvent::is_a(existing_klass) || JdkJfrEvent::is_host(existing_klass), "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
jint size_of_new_bytes = 0;
unsigned char* new_bytes = NULL;
{
ResourceMark rm(THREAD);
const ClassFileStream* const stream = parser.clone_stream();
assert(stream != NULL, "invariant");
const jclass clazz = static_cast<jclass>(JfrJavaSupport::local_jni_handle(existing_klass->java_mirror(), THREAD));
JfrUpcalls::on_retransform(JfrTraceId::load_raw(existing_klass),
clazz,
stream->length(),
stream->buffer(),
&size_of_new_bytes,
&new_bytes,
THREAD);
JfrJavaSupport::destroy_local_jni_handle(clazz);
if (has_pending_exception(THREAD)) {
return NULL;
}
}
assert(new_bytes != NULL, "invariant");
assert(size_of_new_bytes > 0, "invariant");
is_instrumented = true;
return new ClassFileStream(new_bytes, size_of_new_bytes, NULL, ClassFileStream::verify);
}
// On initial class load.
static void cache_class_file_data(InstanceKlass* new_ik, const ClassFileStream* new_stream, const JavaThread* thread) {
assert(new_ik != NULL, "invariant"); assert(new_ik != NULL, "invariant");
assert(new_ik->name() != NULL, "invariant");
assert(new_stream != NULL, "invariant"); assert(new_stream != NULL, "invariant");
assert(!HAS_PENDING_EXCEPTION, "invariant"); assert(thread != NULL, "invariant");
static const bool can_retransform = JfrOptionSet::allow_retransforms(); assert(!thread->has_pending_exception(), "invariant");
if (!can_retransform) { if (!JfrOptionSet::allow_retransforms()) {
return true; return;
} }
const jint stream_len = new_stream->length(); const jint stream_len = new_stream->length();
JvmtiCachedClassFileData* p = JvmtiCachedClassFileData* p =
(JvmtiCachedClassFileData*)NEW_C_HEAP_ARRAY_RETURN_NULL(u1, offset_of(JvmtiCachedClassFileData, data) + stream_len, mtInternal); (JvmtiCachedClassFileData*)NEW_C_HEAP_ARRAY_RETURN_NULL(u1, offset_of(JvmtiCachedClassFileData, data) + stream_len, mtInternal);
if (p == NULL) { if (p == NULL) {
log_error(jfr, system)("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT log_error(jfr, system)("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT " bytes failed in JfrEventClassTransformer::cache_class_file_data",
" bytes failed in JfrClassAdapter::on_klass_creation", (size_t)offset_of(JvmtiCachedClassFileData, data) + stream_len); static_cast<size_t>(offset_of(JvmtiCachedClassFileData, data) + stream_len));
return false; return;
} }
p->length = stream_len; p->length = stream_len;
memcpy(p->data, new_stream->buffer(), stream_len); memcpy(p->data, new_stream->buffer(), stream_len);
new_ik->set_cached_class_file(p); new_ik->set_cached_class_file(p);
JvmtiCachedClassFileData* const cached_class_data = ik->get_cached_class_file(); }
if (cached_class_data != NULL) {
os::free(cached_class_data); // On redefine / retransform, in case an agent modified the class, the original bytes are cached onto the scratch klass.
static void transfer_cached_class_file_data(InstanceKlass* ik, InstanceKlass* new_ik, const ClassFileParser& parser, JavaThread* thread) {
assert(ik != NULL, "invariant");
assert(new_ik != NULL, "invariant");
JvmtiCachedClassFileData* const p = ik->get_cached_class_file();
if (p != NULL) {
new_ik->set_cached_class_file(p);
ik->set_cached_class_file(NULL); ik->set_cached_class_file(NULL);
return;
} }
return true; // No cached classfile indicates that no agent modified the klass.
// This means that the parser is holding the original bytes. Hence, we cache it onto the scratch klass.
const ClassFileStream* const stream = parser.clone_stream();
cache_class_file_data(new_ik, stream, thread);
}
static void rewrite_klass_pointer(InstanceKlass*& ik, InstanceKlass* new_ik, ClassFileParser& parser, const JavaThread* thread) {
assert(ik != NULL, "invariant");
assert(new_ik != NULL, "invariant");
assert(thread != NULL, "invariant");
assert(IS_EVENT_OR_HOST_KLASS(new_ik), "invariant");
assert(TRACE_ID(ik) == TRACE_ID(new_ik), "invariant");
assert(!thread->has_pending_exception(), "invariant");
// Assign original InstanceKlass* back onto "its" parser object for proper destruction.
parser.set_klass_to_deallocate(ik);
// Finally rewrite the original pointer to the newly created InstanceKlass.
ik = new_ik;
}
// If code size is 1, it is 0xb1, i.e. the return instruction.
static inline bool is_commit_method_instrumented(const Method* m) {
assert(m != NULL, "invariant");
assert(m->name() == commit, "invariant");
assert(m->constMethod()->code_size() > 0, "invariant");
return m->constMethod()->code_size() > 1;
}
static bool bless_static_commit_method(const Array<Method*>* methods) {
assert(methods != NULL, "invariant");
for (int i = 0; i < methods->length(); ++i) {
const Method* const m = methods->at(i);
// Method is of the form "static void UserEvent::commit(...)" and instrumented
if (m->is_static() && m->name() == commit && is_commit_method_instrumented(m)) {
BLESS_METHOD(m);
return true;
}
}
return false;
}
static void bless_instance_commit_method(const Array<Method*>* methods) {
assert(methods != NULL, "invariant");
for (int i = 0; i < methods->length(); ++i) {
const Method* const m = methods->at(i);
// Method is of the form "void UserEvent:commit()" and instrumented
if (!m->is_static() &&
m->name() == commit &&
m->signature() == void_method_sig &&
is_commit_method_instrumented(m)) {
BLESS_METHOD(m);
}
}
}
// A blessed method is a method that is allowed to link to system sensitive code.
// It is primarily the class file schema extended instance 'commit()V' method.
// Jdk events can also define a static commit method with an arbitrary signature.
static void bless_commit_method(const InstanceKlass* new_ik) {
assert(new_ik != NULL, "invariant");
assert(JdkJfrEvent::is_subklass(new_ik), "invariant");
const Array<Method*>* const methods = new_ik->methods();
if (new_ik->class_loader() == NULL) {
// JDK events are allowed an additional commit method that is static.
// Search precedence must therefore inspect static methods first.
if (bless_static_commit_method(methods)) {
return;
}
}
bless_instance_commit_method(methods);
}
static void copy_traceid(const InstanceKlass* ik, const InstanceKlass* new_ik) {
assert(ik != NULL, "invariant");
assert(new_ik != NULL, "invariant");
new_ik->set_trace_id(ik->trace_id());
assert(TRACE_ID(ik) == TRACE_ID(new_ik), "invariant");
}
static const Klass* klass_being_redefined(const InstanceKlass* ik, JvmtiThreadState* state) {
assert(ik != NULL, "invariant");
assert(state != NULL, "invariant");
const GrowableArray<Klass*>* const redef_klasses = state->get_classes_being_redefined();
if (redef_klasses == NULL || redef_klasses->is_empty()) {
return NULL;
}
for (int i = 0; i < redef_klasses->length(); ++i) {
const Klass* const existing_klass = redef_klasses->at(i);
assert(existing_klass != NULL, "invariant");
if (ik->name() == existing_klass->name() && ik->class_loader_data() == existing_klass->class_loader_data()) {
// 'ik' is a scratch klass. Return the klass being redefined.
return existing_klass;
}
}
return NULL;
}
// Redefining / retransforming?
static const Klass* find_existing_klass(const InstanceKlass* ik, JavaThread* thread) {
assert(ik != NULL, "invariant");
assert(thread != NULL, "invariant");
JvmtiThreadState* const state = thread->jvmti_thread_state();
return state != NULL ? klass_being_redefined(ik, state) : NULL;
} }
static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStream* stream, TRAPS) { static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStream* stream, TRAPS) {
@ -1491,88 +1708,105 @@ static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStre
assert(new_ik != NULL, "invariant"); assert(new_ik != NULL, "invariant");
assert(new_ik->name() != NULL, "invariant"); assert(new_ik->name() != NULL, "invariant");
assert(strncmp(ik->name()->as_C_string(), new_ik->name()->as_C_string(), strlen(ik->name()->as_C_string())) == 0, "invariant"); assert(strncmp(ik->name()->as_C_string(), new_ik->name()->as_C_string(), strlen(ik->name()->as_C_string())) == 0, "invariant");
return cache_bytes(ik, stream, new_ik, THREAD) ? new_ik : NULL; return new_ik;
} }
static void rewrite_klass_pointer(InstanceKlass*& ik, InstanceKlass* new_ik, ClassFileParser& parser, TRAPS) { static InstanceKlass* create_instance_klass(InstanceKlass*& ik, ClassFileStream* stream, bool is_initial_load, JavaThread* thread) {
assert(ik != NULL, "invariant"); if (stream == NULL) {
assert(new_ik != NULL, "invariant"); if (is_initial_load) {
assert(new_ik->name() != NULL, "invariant"); log_error(jfr, system)("JfrEventClassTransformer: unable to create ClassFileStream for %s", ik->external_name());
assert(JdkJfrEvent::is(new_ik) || JdkJfrEvent::is_subklass(new_ik), "invariant");
assert(!HAS_PENDING_EXCEPTION, "invariant");
// assign original InstanceKlass* back onto "its" parser object for proper destruction
parser.set_klass_to_deallocate(ik);
// now rewrite original pointer to newly created InstanceKlass
ik = new_ik;
}
static bool is_retransforming(const InstanceKlass* ik, TRAPS) {
assert(ik != NULL, "invariant");
assert(JdkJfrEvent::is_a(ik), "invariant");
Symbol* const name = ik->name();
assert(name != NULL, "invariant");
Handle class_loader(THREAD, ik->class_loader());
Handle protection_domain(THREAD, ik->protection_domain());
return SystemDictionary::find_instance_klass(name, class_loader, protection_domain) != NULL;
}
// target for JFR_ON_KLASS_CREATION hook
void JfrEventClassTransformer::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) {
assert(ik != NULL, "invariant");
if (JdkJfrEvent::is(ik)) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
ClassFileStream* new_stream = create_new_bytes_for_event_klass(ik, parser, THREAD);
if (new_stream == NULL) {
log_error(jfr, system)("JfrClassAdapter: unable to create ClassFileStream");
return;
} }
assert(new_stream != NULL, "invariant"); return NULL;
InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD); }
if (new_ik == NULL) { InstanceKlass* const new_ik = create_new_instance_klass(ik, stream, thread);
log_error(jfr, system)("JfrClassAdapter: unable to create InstanceKlass"); if (new_ik == NULL) {
return; if (is_initial_load) {
log_error(jfr, system)("JfrEventClassTransformer: unable to create InstanceKlass for %s", ik->external_name());
} }
assert(new_ik != NULL, "invariant"); }
// We now need to explicitly tag the replaced klass as the jdk.jfr.Event klass return new_ik;
assert(!JdkJfrEvent::is(new_ik), "invariant"); }
JdkJfrEvent::tag_as(new_ik);
assert(JdkJfrEvent::is(new_ik), "invariant"); static void transform(InstanceKlass*& ik, ClassFileParser& parser, JavaThread* thread) {
rewrite_klass_pointer(ik, new_ik, parser, THREAD); assert(IS_EVENT_OR_HOST_KLASS(ik), "invariant");
bool is_instrumented = false;
ClassFileStream* stream = NULL;
const Klass* const existing_klass = find_existing_klass(ik, thread);
if (existing_klass != NULL) {
// There is already a klass defined, implying we are redefining / retransforming.
stream = retransform_bytes(existing_klass, parser, is_instrumented, thread);
} else {
// No existing klass, implying this is the initial load.
stream = JdkJfrEvent::is(ik) ? schema_extend_event_klass_bytes(ik, parser, thread) : schema_extend_event_subklass_bytes(ik, parser, is_instrumented, thread);
}
InstanceKlass* const new_ik = create_instance_klass(ik, stream, existing_klass == NULL, thread);
if (new_ik == NULL) {
return; return;
} }
assert(JdkJfrEvent::is_subklass(ik), "invariant"); if (existing_klass != NULL) {
if (ik->is_abstract() || is_retransforming(ik, THREAD)) { transfer_cached_class_file_data(ik, new_ik, parser, thread);
// abstract and scratch classes are not instrumented } else {
cache_class_file_data(new_ik, stream, thread);
}
if (is_instrumented && JdkJfrEvent::is_subklass(new_ik)) {
bless_commit_method(new_ik);
}
copy_traceid(ik, new_ik);
rewrite_klass_pointer(ik, new_ik, parser, thread);
}
// Target for the JFR_ON_KLASS_CREATION hook.
// Extends the class file schema on initial class load or reinstruments on redefine / retransform.
// The passed in parameter 'ik' acts as an in-out parameter: it is rewritten to point to a replaced
// instance of the passed in InstanceKlass. The original 'ik' will be set onto the passed parser,
// for destruction when the parser goes out of scope.
void JfrEventClassTransformer::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) {
assert(ik != NULL, "invariant");
assert(IS_EVENT_OR_HOST_KLASS(ik), "invariant");
if (ik->is_abstract() && !JdkJfrEvent::is(ik)) {
assert(JdkJfrEvent::is_subklass(ik), "invariant");
// Abstract subklasses are not instrumented.
return; return;
} }
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
HandleMark hm(THREAD); HandleMark hm(THREAD);
ClassFileStream* const new_stream = create_new_bytes_for_subklass(ik, parser, THREAD); transform(ik, parser, THREAD);
if (NULL == new_stream) {
log_error(jfr, system)("JfrClassAdapter: unable to create ClassFileStream");
return;
}
assert(new_stream != NULL, "invariant");
InstanceKlass* new_ik = create_new_instance_klass(ik, new_stream, THREAD);
if (new_ik == NULL) {
log_error(jfr, system)("JfrClassAdapter: unable to create InstanceKlass");
return;
}
assert(new_ik != NULL, "invariant");
// would have been tagged already as a subklass during the normal process of traceid assignment
assert(JdkJfrEvent::is_subklass(new_ik), "invariant");
traceid id = ik->trace_id();
ik->set_trace_id(0);
new_ik->set_trace_id(id);
rewrite_klass_pointer(ik, new_ik, parser, THREAD);
} }
static bool _force_instrumentation = false; static bool is_static_commit_method_blessed(const Array<Method*>* methods) {
void JfrEventClassTransformer::set_force_instrumentation(bool force_instrumentation) { assert(methods != NULL, "invariant");
_force_instrumentation = force_instrumentation; for (int i = 0; i < methods->length(); ++i) {
const Method* const m = methods->at(i);
// Must be of form: static void UserEvent::commit(...)
if (m->is_static() && m->name() == commit) {
return IS_METHOD_BLESSED(m);
}
}
return false;
} }
bool JfrEventClassTransformer::is_force_instrumentation() { static bool is_instance_commit_method_blessed(const Array<Method*>* methods) {
return _force_instrumentation; assert(methods != NULL, "invariant");
for (int i = 0; i < methods->length(); ++i) {
const Method* const m = methods->at(i);
// Must be of form: void UserEvent::commit()
if (!m->is_static() && m->name() == commit && m->signature() == void_method_sig) {
return IS_METHOD_BLESSED(m);
}
}
return false;
}
bool JfrEventClassTransformer::is_instrumented(const InstanceKlass* ik) {
assert(ik != NULL, "invariant");
assert(JdkJfrEvent::is_subklass(ik), "invariant");
const Array<Method*>* const methods = ik->methods();
if (ik->class_loader() == NULL) {
// JDK events are allowed an additional commit method that is static.
// Search precedence must therefore inspect static methods first.
if (is_static_commit_method_blessed(methods)) {
return true;
}
}
return is_instance_commit_method_blessed(methods);
} }

View File

@ -28,6 +28,7 @@
#include "memory/allStatic.hpp" #include "memory/allStatic.hpp"
#include "utilities/exceptions.hpp" #include "utilities/exceptions.hpp"
class CallInfo;
class ClassFileParser; class ClassFileParser;
class InstanceKlass; class InstanceKlass;
@ -38,6 +39,7 @@ class InstanceKlass;
class JfrEventClassTransformer : AllStatic { class JfrEventClassTransformer : AllStatic {
public: public:
static void on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS); static void on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS);
static bool is_instrumented(const InstanceKlass* ik);
static void set_force_instrumentation(bool force_instrumentation); static void set_force_instrumentation(bool force_instrumentation);
static bool is_force_instrumentation(); static bool is_force_instrumentation();
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -187,7 +187,6 @@ static bool register_callbacks(JavaThread* jt) {
jvmtiEventCallbacks callbacks; jvmtiEventCallbacks callbacks;
/* Set callbacks */ /* Set callbacks */
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;
const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
return jvmti_ret_code == JVMTI_ERROR_NONE; return jvmti_ret_code == JVMTI_ERROR_NONE;

View File

@ -0,0 +1,103 @@
/*
* 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 "c1/c1_GraphBuilder.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 "opto/parse.hpp"
#include "runtime/thread.hpp"
#include "runtime/vframe.inline.hpp"
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;
}
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), link_error_msg);
}
static inline bool is_compiler_linking_event_writer(const ciKlass * holder, const ciMethod * target) {
assert(holder != nullptr, "invariant");
assert(target != nullptr, "invariant");
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->name()->get_symbol() != 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 target->name()->get_symbol() == event_writer_method_name;
}
// 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);
}
}
// 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);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.
*
*/
#ifndef SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP
#define SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP
#include "memory/allocation.hpp"
#include "utilities/exceptions.hpp"
class CallInfo;
class ciKlass;
class ciMethod;
class GraphBuilder;
class Parse;
class JfrResolution : AllStatic {
public:
static void on_runtime_resolution(const CallInfo & info, TRAPS);
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);
};
#endif // SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP

View File

@ -23,6 +23,7 @@
*/ */
#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"
@ -30,6 +31,7 @@
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrEmergencyDump.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/jfrThreadLocal.hpp" #include "jfr/support/jfrThreadLocal.hpp"
#include "runtime/java.hpp" #include "runtime/java.hpp"
@ -98,6 +100,18 @@ void Jfr::on_set_current_thread(JavaThread* jt, oop thread) {
JfrThreadLocal::on_set_current_thread(jt, thread); JfrThreadLocal::on_set_current_thread(jt, thread);
} }
void Jfr::on_resolution(const CallInfo& info, TRAPS) {
JfrResolution::on_runtime_resolution(info, THREAD);
}
void Jfr::on_resolution(const GraphBuilder* builder, const ciKlass* holder, const ciMethod* target) {
JfrResolution::on_c1_resolution(builder, holder, target);
}
void Jfr::on_resolution(const Parse* parse, const ciKlass* holder, const ciMethod* target) {
JfrResolution::on_c2_resolution(parse, holder, target);
}
void Jfr::on_vm_shutdown(bool exception_handler) { void Jfr::on_vm_shutdown(bool exception_handler) {
if (JfrRecorder::is_recording()) { if (JfrRecorder::is_recording()) {
JfrEmergencyDump::on_vm_shutdown(exception_handler); JfrEmergencyDump::on_vm_shutdown(exception_handler);

View File

@ -27,11 +27,18 @@
#include "jni.h" #include "jni.h"
#include "memory/allStatic.hpp" #include "memory/allStatic.hpp"
#include "utilities/exceptions.hpp"
#include "oops/oopsHierarchy.hpp" #include "oops/oopsHierarchy.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
class CallInfo;
class ciKlass;
class ciMethod;
class GraphBuilder;
class JavaThread; class JavaThread;
class Klass;
class outputStream; class outputStream;
class Parse;
class Thread; class Thread;
extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass); extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass);
@ -53,6 +60,9 @@ class Jfr : AllStatic {
static void exclude_thread(Thread* thread); static void exclude_thread(Thread* thread);
static void on_thread_start(Thread* thread); static void on_thread_start(Thread* thread);
static void on_thread_exit(Thread* thread); static void on_thread_exit(Thread* thread);
static void on_resolution(const CallInfo& info, TRAPS);
static void on_resolution(const Parse* parse, const ciKlass* holder, const ciMethod* target);
static void on_resolution(const GraphBuilder* builder, const ciKlass* holder, const ciMethod* target);
static void on_java_thread_start(JavaThread* starter, JavaThread* startee); static void on_java_thread_start(JavaThread* starter, JavaThread* startee);
static void on_set_current_thread(JavaThread* jt, oop thread); static void on_set_current_thread(JavaThread* jt, oop thread);
static void on_vm_shutdown(bool exception_handler = false); static void on_vm_shutdown(bool exception_handler = false);

View File

@ -28,6 +28,7 @@
#include "classfile/symbolTable.hpp" #include "classfile/symbolTable.hpp"
#include "classfile/vmClasses.hpp" #include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
#include "jfr/jni/jfrJavaCall.hpp" #include "jfr/jni/jfrJavaCall.hpp"
#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
@ -762,7 +763,7 @@ bool JfrJavaSupport::is_excluded(Thread* thread) {
return JfrThreadLocal::is_jvm_thread_excluded(thread); return JfrThreadLocal::is_jvm_thread_excluded(thread);
} }
static const Klass* get_handler_field_descriptor(const Handle& h_mirror, fieldDescriptor* descriptor, TRAPS) { static const Klass* get_configuration_field_descriptor(const Handle& h_mirror, fieldDescriptor* descriptor, TRAPS) {
assert(h_mirror.not_null(), "invariant"); assert(h_mirror.not_null(), "invariant");
assert(descriptor != NULL, "invariant"); assert(descriptor != NULL, "invariant");
Klass* const k = java_lang_Class::as_Klass(h_mirror()); Klass* const k = java_lang_Class::as_Klass(h_mirror());
@ -772,50 +773,57 @@ static const Klass* get_handler_field_descriptor(const Handle& h_mirror, fieldDe
ik->initialize(CHECK_NULL); ik->initialize(CHECK_NULL);
} }
assert(ik->is_being_initialized() || ik->is_initialized(), "invariant"); assert(ik->is_being_initialized() || ik->is_initialized(), "invariant");
const Klass* const typed_field_holder = ik->find_field(vmSymbols::eventHandler_name(), const Klass* const typed_field_holder = ik->find_field(vmSymbols::eventConfiguration_name(),
vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(), vmSymbols::jdk_jfr_internal_event_EventConfiguration_signature(),
true, true,
descriptor); descriptor);
return typed_field_holder != NULL ? typed_field_holder : ik->find_field(vmSymbols::eventHandler_name(), return typed_field_holder != NULL ? typed_field_holder : ik->find_field(vmSymbols::eventConfiguration_name(),
vmSymbols::object_signature(), // untyped vmSymbols::object_signature(), // untyped
true, true,
descriptor); descriptor);
} }
jobject JfrJavaSupport::get_handler(jobject clazz, TRAPS) { jobject JfrJavaSupport::get_configuration(jobject clazz, TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
HandleMark hm(THREAD); HandleMark hm(THREAD);
const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz))); const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz)));
assert(h_mirror.not_null(), "invariant"); assert(h_mirror.not_null(), "invariant");
fieldDescriptor handler_field_descriptor; fieldDescriptor configuration_field_descriptor;
const Klass* const field_holder = get_handler_field_descriptor(h_mirror, &handler_field_descriptor, THREAD); const Klass* const field_holder = get_configuration_field_descriptor(h_mirror, &configuration_field_descriptor, THREAD);
if (field_holder == NULL) { if (field_holder == NULL) {
// The only reason should be that klass initialization failed. // The only reason should be that klass initialization failed.
return NULL; return NULL;
} }
assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant"); assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant");
oop handler_oop = h_mirror->obj_field(handler_field_descriptor.offset()); oop configuration_oop = h_mirror->obj_field(configuration_field_descriptor.offset());
return handler_oop != NULL ? JfrJavaSupport::local_jni_handle(handler_oop, THREAD) : NULL; return configuration_oop != NULL ? JfrJavaSupport::local_jni_handle(configuration_oop, THREAD) : NULL;
} }
bool JfrJavaSupport::set_handler(jobject clazz, jobject handler, TRAPS) { bool JfrJavaSupport::set_configuration(jobject clazz, jobject configuration, TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
HandleMark hm(THREAD); HandleMark hm(THREAD);
const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz))); const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz)));
assert(h_mirror.not_null(), "invariant"); assert(h_mirror.not_null(), "invariant");
fieldDescriptor handler_field_descriptor; fieldDescriptor configuration_field_descriptor;
const Klass* const field_holder = get_handler_field_descriptor(h_mirror, &handler_field_descriptor, THREAD); const Klass* const field_holder = get_configuration_field_descriptor(h_mirror, &configuration_field_descriptor, THREAD);
if (field_holder == NULL) { if (field_holder == NULL) {
// The only reason should be that klass initialization failed. // The only reason should be that klass initialization failed.
return false; return false;
} }
assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant"); assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant");
const oop handler_oop = JNIHandles::resolve(handler); const oop configuration_oop = JNIHandles::resolve(configuration);
assert(handler_oop != NULL, "invariant"); assert(configuration_oop != NULL, "invariant");
h_mirror->obj_field_put(handler_field_descriptor.offset(), handler_oop); h_mirror->obj_field_put(configuration_field_descriptor.offset(), configuration_oop);
return true; return true;
} }
bool JfrJavaSupport::is_instrumented(jobject clazz, TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
const Klass* const k = java_lang_Class::as_Klass(resolve_non_null(clazz));
assert(k->is_instance_klass(), "invariant");
return JfrEventClassTransformer::is_instrumented(InstanceKlass::cast(k));
}
bool JfrJavaSupport::on_thread_start(Thread* t) { bool JfrJavaSupport::on_thread_start(Thread* t) {
assert(t != NULL, "invariant"); assert(t != NULL, "invariant");
assert(Thread::current() == t, "invariant"); assert(Thread::current() == t, "invariant");

View File

@ -110,8 +110,10 @@ class JfrJavaSupport : public AllStatic {
static bool is_excluded(Thread* thread); static bool is_excluded(Thread* thread);
static bool on_thread_start(Thread* t); static bool on_thread_start(Thread* t);
static jobject get_handler(jobject clazz, TRAPS); static jobject get_configuration(jobject clazz, TRAPS);
static bool set_handler(jobject clazz, jobject handler, TRAPS); static bool set_configuration(jobject clazz, jobject configuration, TRAPS);
static bool is_instrumented(jobject clazz, TRAPS);
// critical // critical
static void abort(jstring errorMsg, TRAPS); static void abort(jstring errorMsg, TRAPS);

View File

@ -366,10 +366,18 @@ JVM_ENTRY_NO_ENV(jlong, jfr_chunk_start_nanos(JNIEnv* env, jobject jvm))
return JfrRepository::current_chunk_start_nanos(); return JfrRepository::current_chunk_start_nanos();
JVM_END JVM_END
JVM_ENTRY_NO_ENV(jobject, jfr_get_handler(JNIEnv * env, jobject jvm, jobject clazz)) JVM_ENTRY_NO_ENV(jobject, jfr_get_configuration(JNIEnv * env, jobject jvm, jobject clazz))
return JfrJavaSupport::get_handler(clazz, thread); return JfrJavaSupport::get_configuration(clazz, thread);
JVM_END JVM_END
JVM_ENTRY_NO_ENV(jboolean, jfr_set_handler(JNIEnv * env, jobject jvm, jobject clazz, jobject handler)) JVM_ENTRY_NO_ENV(jboolean, jfr_set_configuration(JNIEnv * env, jobject jvm, jobject clazz, jobject configuration))
return JfrJavaSupport::set_handler(clazz, handler, thread); return JfrJavaSupport::set_configuration(clazz, configuration, thread);
JVM_END
JVM_ENTRY_NO_ENV(jboolean, jfr_is_class_excluded(JNIEnv * env, jobject jvm, jclass clazz))
return JdkJfrEvent::is_excluded(clazz);
JVM_END
JVM_ENTRY_NO_ENV(jboolean, jfr_is_class_instrumented(JNIEnv* env, jobject jvm, jclass clazz))
return JfrJavaSupport::is_instrumented(clazz, thread);
JVM_END JVM_END

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2022, 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
@ -148,14 +148,19 @@ jboolean JNICALL jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t);
jlong JNICALL jfr_chunk_start_nanos(JNIEnv* env, jobject jvm); jlong JNICALL jfr_chunk_start_nanos(JNIEnv* env, jobject jvm);
jobject JNICALL jfr_get_handler(JNIEnv* env, jobject jvm, jobject clazz); jobject JNICALL jfr_get_configuration(JNIEnv* env, jobject jvm, jobject clazz);
jboolean JNICALL jfr_set_handler(JNIEnv* env, jobject jvm, jobject clazz, jobject handler); jboolean JNICALL jfr_set_configuration(JNIEnv* env, jobject jvm, jobject clazz, jobject configuration);
jlong JNICALL jfr_get_type_id_from_string(JNIEnv* env, jobject jvm, jstring type); jlong JNICALL jfr_get_type_id_from_string(JNIEnv* env, jobject jvm, jstring type);
jboolean JNICALL jfr_is_class_excluded(JNIEnv* env, jobject jvm, jclass clazz);
jboolean JNICALL jfr_is_class_instrumented(JNIEnv* env, jobject jvm, jclass clazz);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif // SHARE_JFR_JNI_JFRJNIMETHOD_HPP #endif // SHARE_JFR_JNI_JFRJNIMETHOD_HPP

View File

@ -69,9 +69,9 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"isAvailable", (char*)"()Z", (void*)jfr_is_available, (char*)"isAvailable", (char*)"()Z", (void*)jfr_is_available,
(char*)"getTimeConversionFactor", (char*)"()D", (void*)jfr_time_conv_factor, (char*)"getTimeConversionFactor", (char*)"()D", (void*)jfr_time_conv_factor,
(char*)"getTypeId", (char*)"(Ljava/lang/Class;)J", (void*)jfr_type_id, (char*)"getTypeId", (char*)"(Ljava/lang/Class;)J", (void*)jfr_type_id,
(char*)"getEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_get_event_writer, (char*)"getEventWriter", (char*)"()Ljdk/jfr/internal/event/EventWriter;", (void*)jfr_get_event_writer,
(char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer, (char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/event/EventWriter;", (void*)jfr_new_event_writer,
(char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush, (char*)"flush", (char*)"(Ljdk/jfr/internal/event/EventWriter;II)Z", (void*)jfr_event_writer_flush,
(char*)"flush", (char*)"()V", (void*)jfr_flush, (char*)"flush", (char*)"()V", (void*)jfr_flush,
(char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location, (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location,
(char*)"setDumpPath", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_dump_path, (char*)"setDumpPath", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_dump_path,
@ -89,9 +89,11 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"include", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_include_thread, (char*)"include", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_include_thread,
(char*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded, (char*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded,
(char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos, (char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos,
(char*)"getHandler", (char*)"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)jfr_get_handler, (char*)"getConfiguration", (char*)"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)jfr_get_configuration,
(char*)"setHandler", (char*)"(Ljava/lang/Class;Ljdk/jfr/internal/handlers/EventHandler;)Z", (void*)jfr_set_handler, (char*)"setConfiguration", (char*)"(Ljava/lang/Class;Ljdk/jfr/internal/event/EventConfiguration;)Z", (void*)jfr_set_configuration,
(char*)"getTypeId", (char*)"(Ljava/lang/String;)J", (void*)jfr_get_type_id_from_string (char*)"getTypeId", (char*)"(Ljava/lang/String;)J", (void*)jfr_get_type_id_from_string,
(char*)"isExcluded", (char*)"(Ljava/lang/Class;)Z", (void*)jfr_is_class_excluded,
(char*)"isInstrumented", (char*)"(Ljava/lang/Class;)Z", (void*) jfr_is_class_instrumented
}; };
const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod); const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);
@ -105,3 +107,4 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
env->DeleteLocalRef(jfr_clz); env->DeleteLocalRef(jfr_clz);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -55,9 +55,9 @@ static bool initialize(TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls"); jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls");
on_retransform_method_sym = SymbolTable::new_permanent_symbol("onRetransform"); on_retransform_method_sym = SymbolTable::new_permanent_symbol("onRetransform");
on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B"); on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZZLjava/lang/Class;[B)[B");
bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation"); bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation");
bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B"); bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZZLjava/lang/Class;[B)[B");
unhide_internal_types_sym = SymbolTable::new_permanent_symbol("unhideInternalTypes"); unhide_internal_types_sym = SymbolTable::new_permanent_symbol("unhideInternalTypes");
unhide_internal_types_sig_sym = SymbolTable::new_permanent_symbol("()V"); unhide_internal_types_sig_sym = SymbolTable::new_permanent_symbol("()V");
initialized = unhide_internal_types_sig_sym != NULL; initialized = unhide_internal_types_sig_sym != NULL;
@ -67,6 +67,7 @@ static bool initialize(TRAPS) {
static const typeArrayOop invoke(jlong trace_id, static const typeArrayOop invoke(jlong trace_id,
jboolean force_instrumentation, jboolean force_instrumentation,
jboolean boot_class_loader,
jclass class_being_redefined, jclass class_being_redefined,
jint class_data_len, jint class_data_len,
const unsigned char* class_data, const unsigned char* class_data,
@ -83,6 +84,7 @@ static const typeArrayOop invoke(jlong trace_id,
JfrJavaArguments args(&result, klass, method_sym, signature_sym); JfrJavaArguments args(&result, klass, method_sym, signature_sym);
args.push_long(trace_id); args.push_long(trace_id);
args.push_int(force_instrumentation); args.push_int(force_instrumentation);
args.push_int(boot_class_loader);
args.push_jobject(class_being_redefined); args.push_jobject(class_being_redefined);
args.push_oop(old_byte_array); args.push_oop(old_byte_array);
JfrJavaSupport::call_static(&args, THREAD); JfrJavaSupport::call_static(&args, THREAD);
@ -129,6 +131,7 @@ void JfrUpcalls::on_retransform(jlong trace_id,
initialize(THREAD); initialize(THREAD);
const typeArrayOop new_byte_array = invoke(trace_id, const typeArrayOop new_byte_array = invoke(trace_id,
false, false,
false, // not used
class_being_redefined, class_being_redefined,
class_data_len, class_data_len,
class_data, class_data,
@ -152,6 +155,7 @@ void JfrUpcalls::on_retransform(jlong trace_id,
void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id, void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id,
jboolean force_instrumentation, jboolean force_instrumentation,
jboolean boot_class_loader,
jclass super, jclass super,
jint class_data_len, jint class_data_len,
const unsigned char* class_data, const unsigned char* class_data,
@ -167,6 +171,7 @@ void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id,
initialize(THREAD); initialize(THREAD);
const typeArrayOop new_byte_array = invoke(trace_id, const typeArrayOop new_byte_array = invoke(trace_id,
force_instrumentation, force_instrumentation,
boot_class_loader,
super, super,
class_data_len, class_data_len,
class_data, class_data,

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -39,6 +39,7 @@ class JfrUpcalls : AllStatic {
public: public:
static void new_bytes_eager_instrumentation(jlong trace_id, static void new_bytes_eager_instrumentation(jlong trace_id,
jboolean force_instrumentation, jboolean force_instrumentation,
jboolean boot_class_loader,
jclass super, jclass super,
jint class_data_len, jint class_data_len,
const unsigned char* class_data, const unsigned char* class_data,

View File

@ -28,16 +28,15 @@
#include "classfile/symbolTable.hpp" #include "classfile/symbolTable.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/utilities/jfrTypes.hpp" #include "jfr/utilities/jfrTypes.hpp"
#include "oops/arrayKlass.inline.hpp"
#include "oops/klass.inline.hpp"
#include "oops/instanceKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/vm_version.hpp"
#include "runtime/jniHandles.inline.hpp" #include "runtime/jniHandles.inline.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "utilities/debug.hpp" #include "runtime/vm_version.hpp"
#include "utilities/growableArray.hpp"
// returns updated value // returns updated value
static traceid atomic_inc(traceid volatile* const dest, traceid stride = 1) { static traceid atomic_inc(traceid volatile* const dest, traceid stride = 1) {
@ -112,15 +111,36 @@ static void check_klass(const Klass* klass) {
} }
void JfrTraceId::assign(const Klass* klass) { void JfrTraceId::assign(const Klass* klass) {
assert(klass != NULL, "invariant"); assert(klass != nullptr, "invariant");
klass->set_trace_id(next_class_id()); klass->set_trace_id(next_class_id());
check_klass(klass); check_klass(klass);
const Klass* const super = klass->super(); const Klass* const super = klass->super();
if (super == NULL) { if (super == nullptr) {
return; return;
} }
if (IS_EVENT_KLASS(super)) { if (IS_EVENT_KLASS(super)) {
tag_as_jdk_jfr_event_sub(klass); tag_as_jdk_jfr_event_sub(klass);
return;
}
// Redefining / retransforming?
JavaThread* const jt = JavaThread::current();
assert(jt != nullptr, "invariant");
JvmtiThreadState* const state = jt->jvmti_thread_state();
if (state == nullptr) {
return;
}
const GrowableArray<Klass*>* const redef_klasses = state->get_classes_being_redefined();
if (redef_klasses == nullptr || redef_klasses->is_empty()) {
return;
}
for (int i = 0; i < redef_klasses->length(); ++i) {
if (klass->name() == redef_klasses->at(i)->name() && klass->class_loader_data() == redef_klasses->at(i)->class_loader_data()) {
// 'klass' is a scratch klass. If the klass being redefined is a host klass, then tag the scratch klass as well.
if (is_event_host(redef_klasses->at(i))) {
SET_EVENT_HOST_KLASS(klass);
assert(is_event_host(klass), "invariant");
}
}
} }
} }
@ -264,3 +284,12 @@ void JfrTraceId::tag_as_event_host(const jclass jc) {
tag_as_event_host(k); tag_as_event_host(k);
assert(IS_EVENT_HOST_KLASS(k), "invariant"); assert(IS_EVENT_HOST_KLASS(k), "invariant");
} }
void JfrTraceId::untag_jdk_jfr_event_sub(const Klass* k) {
assert(k != NULL, "invariant");
if (JfrTraceId::is_jdk_jfr_event_sub(k)) {
CLEAR_JDK_JFR_EVENT_SUBKLASS(k);
}
assert(IS_NOT_AN_EVENT_SUB_KLASS(k), "invariant");
}

View File

@ -120,6 +120,7 @@ class JfrTraceId : public AllStatic {
static bool is_jdk_jfr_event_sub(const jclass jc); static bool is_jdk_jfr_event_sub(const jclass jc);
static void tag_as_jdk_jfr_event_sub(const Klass* k); static void tag_as_jdk_jfr_event_sub(const Klass* k);
static void tag_as_jdk_jfr_event_sub(const jclass jc); static void tag_as_jdk_jfr_event_sub(const jclass jc);
static void untag_jdk_jfr_event_sub(const Klass* k);
static bool in_jdk_jfr_event_hierarchy(const Klass* k); static bool in_jdk_jfr_event_hierarchy(const Klass* k);
static bool in_jdk_jfr_event_hierarchy(const jclass jc); static bool in_jdk_jfr_event_hierarchy(const jclass jc);

View File

@ -54,6 +54,7 @@
#define TRANSIENT_BIT (TRANSIENT_META_BIT << META_SHIFT) #define TRANSIENT_BIT (TRANSIENT_META_BIT << META_SHIFT)
#define SERIALIZED_META_BIT (BIT << 4) #define SERIALIZED_META_BIT (BIT << 4)
#define SERIALIZED_BIT (SERIALIZED_META_BIT << META_SHIFT) #define SERIALIZED_BIT (SERIALIZED_META_BIT << META_SHIFT)
#define BLESSED_METHOD_BIT (JDK_JFR_EVENT_SUBKLASS)
#define TRACE_ID_SHIFT 16 #define TRACE_ID_SHIFT 16
#define METHOD_ID_NUM_MASK ((1 << TRACE_ID_SHIFT) - 1) #define METHOD_ID_NUM_MASK ((1 << TRACE_ID_SHIFT) - 1)
#define META_BITS (SERIALIZED_BIT | TRANSIENT_BIT | LEAKP_BIT | EPOCH_1_CLEARED_BIT | EPOCH_0_CLEARED_BIT) #define META_BITS (SERIALIZED_BIT | TRANSIENT_BIT | LEAKP_BIT | EPOCH_1_CLEARED_BIT | EPOCH_0_CLEARED_BIT)
@ -104,6 +105,7 @@
#define METHOD_FLAG_USED_THIS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (THIS_EPOCH_METHOD_FLAG_BIT))) #define METHOD_FLAG_USED_THIS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (THIS_EPOCH_METHOD_FLAG_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_METHOD_FLAG_BIT))) #define METHOD_FLAG_USED_PREVIOUS_EPOCH(method) (METHOD_FLAG_PREDICATE(method, (PREVIOUS_EPOCH_METHOD_FLAG_BIT)))
#define IS_METHOD_BLESSED(method) (METHOD_FLAG_PREDICATE(method, BLESSED_METHOD_BIT))
// setters // setters
#define SET_USED_THIS_EPOCH(ptr) (TRACE_ID_TAG(ptr, THIS_EPOCH_BIT)) #define SET_USED_THIS_EPOCH(ptr) (TRACE_ID_TAG(ptr, THIS_EPOCH_BIT))
@ -112,6 +114,7 @@
#define PREVIOUS_EPOCH_METHOD_AND_CLASS_BIT_MASK (~(PREVIOUS_EPOCH_METHOD_BIT | PREVIOUS_EPOCH_BIT)) #define PREVIOUS_EPOCH_METHOD_AND_CLASS_BIT_MASK (~(PREVIOUS_EPOCH_METHOD_BIT | PREVIOUS_EPOCH_BIT))
#define CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(kls) (TRACE_ID_MASK_CLEAR(kls, PREVIOUS_EPOCH_METHOD_AND_CLASS_BIT_MASK)) #define CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(kls) (TRACE_ID_MASK_CLEAR(kls, PREVIOUS_EPOCH_METHOD_AND_CLASS_BIT_MASK))
#define CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method) (METHOD_FLAG_CLEAR(method, PREVIOUS_EPOCH_METHOD_FLAG_BIT)) #define CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method) (METHOD_FLAG_CLEAR(method, PREVIOUS_EPOCH_METHOD_FLAG_BIT))
#define BLESS_METHOD(method) (METHOD_FLAG_TAG(method, BLESSED_METHOD_BIT))
// types // types
#define IS_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_KLASS)) #define IS_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_KLASS))
@ -120,6 +123,8 @@
#define IS_EVENT_HOST_KLASS(kls) (TRACE_ID_PREDICATE(kls, EVENT_HOST_KLASS)) #define IS_EVENT_HOST_KLASS(kls) (TRACE_ID_PREDICATE(kls, EVENT_HOST_KLASS))
#define SET_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_TAG(kls, JDK_JFR_EVENT_KLASS)) #define SET_JDK_JFR_EVENT_KLASS(kls) (TRACE_ID_TAG(kls, JDK_JFR_EVENT_KLASS))
#define SET_JDK_JFR_EVENT_SUBKLASS(kls) (TRACE_ID_TAG(kls, JDK_JFR_EVENT_SUBKLASS)) #define SET_JDK_JFR_EVENT_SUBKLASS(kls) (TRACE_ID_TAG(kls, JDK_JFR_EVENT_SUBKLASS))
#define JDK_JFR_EVENT_SUBKLASS_MASK (~(JDK_JFR_EVENT_SUBKLASS))
#define CLEAR_JDK_JFR_EVENT_SUBKLASS(kls) (TRACE_ID_MASK_CLEAR(kls, JDK_JFR_EVENT_SUBKLASS_MASK))
#define SET_EVENT_HOST_KLASS(kls) (TRACE_ID_TAG(kls, EVENT_HOST_KLASS)) #define SET_EVENT_HOST_KLASS(kls) (TRACE_ID_TAG(kls, EVENT_HOST_KLASS))
#define EVENT_KLASS_MASK(kls) (TRACE_ID_RAW(kls) & EVENT_BITS) #define EVENT_KLASS_MASK(kls) (TRACE_ID_RAW(kls) & EVENT_BITS)

View File

@ -45,19 +45,21 @@ class JfrIntrinsicSupport : AllStatic {
#define JFR_HAVE_INTRINSICS #define JFR_HAVE_INTRINSICS
#define JFR_TEMPLATES(template) \ #define JFR_TEMPLATES(template) \
template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \ template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \
template(jdk_jfr_internal_handlers_EventHandler_signature, "Ljdk/jfr/internal/handlers/EventHandler;") \ template(jdk_jfr_internal_event_EventWriterFactory, "jdk/jfr/internal/event/EventWriterFactory") \
template(eventHandler_name, "eventHandler") \ template(jdk_jfr_internal_event_EventConfiguration_signature, "Ljdk/jfr/internal/event/EventConfiguration;") \
template(void_eventWriter_signature, "()Ljdk/jfr/internal/EventWriter;") \ template(getEventWriter_signature, "()Ljdk/jfr/internal/event/EventWriter;") \
template(eventConfiguration_name, "eventConfiguration") \
template(commit_name, "commit") \
#define JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \ #define JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \
do_intrinsic(_counterTime, jdk_jfr_internal_JVM, counterTime_name, void_long_signature, F_SN) \ do_intrinsic(_counterTime, jdk_jfr_internal_JVM, counterTime_name, void_long_signature, F_SN) \
do_name( counterTime_name, "counterTime") \ do_name( counterTime_name, "counterTime") \
do_intrinsic(_getClassId, jdk_jfr_internal_JVM, getClassId_name, class_long_signature, F_SN) \ do_intrinsic(_getClassId, jdk_jfr_internal_JVM, getClassId_name, class_long_signature, F_SN) \
do_name( getClassId_name, "getClassId") \ do_name( getClassId_name, "getClassId") \
do_intrinsic(_getEventWriter, jdk_jfr_internal_JVM, getEventWriter_name, void_eventWriter_signature, F_SN) \ do_intrinsic(_getEventWriter, jdk_jfr_internal_JVM, getEventWriter_name, getEventWriter_signature, F_SN) \
do_name( getEventWriter_name, "getEventWriter") \ do_name( getEventWriter_name, "getEventWriter") \
#else // !INCLUDE_JFR #else // !INCLUDE_JFR

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022, 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
@ -73,6 +73,10 @@ static bool initialize(TRAPS) {
*/ */
static bool is_allowed(const Klass* k) { static bool is_allowed(const Klass* k) {
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
if (!JfrTraceId::is_jdk_jfr_event_sub(k)) {
// Was excluded during initial class load.
return false;
}
return !(k->is_abstract() || k->should_be_initialized()); return !(k->is_abstract() || k->should_be_initialized());
} }
@ -196,6 +200,10 @@ bool JdkJfrEvent::is_a(const jclass jc) {
return JfrTraceId::in_jdk_jfr_event_hierarchy(jc); return JfrTraceId::in_jdk_jfr_event_hierarchy(jc);
} }
void JdkJfrEvent::remove(const Klass* k) {
JfrTraceId::untag_jdk_jfr_event_sub(k);
}
bool JdkJfrEvent::is_host(const Klass* k) { bool JdkJfrEvent::is_host(const Klass* k) {
return JfrTraceId::is_event_host(k); return JfrTraceId::is_event_host(k);
} }
@ -219,3 +227,8 @@ bool JdkJfrEvent::is_visible(const Klass* k) {
bool JdkJfrEvent::is_visible(const jclass jc) { bool JdkJfrEvent::is_visible(const jclass jc) {
return JfrTraceId::in_visible_set(jc); return JfrTraceId::in_visible_set(jc);
} }
bool JdkJfrEvent::is_excluded(const jclass jc) {
return !JfrTraceId::in_visible_set(jc);
}

View File

@ -59,6 +59,7 @@ class JdkJfrEvent : AllStatic {
// jdk.jfr.Event hierarchy // jdk.jfr.Event hierarchy
static bool is_a(const Klass* k); static bool is_a(const Klass* k);
static bool is_a(const jclass jc); static bool is_a(const jclass jc);
static void remove(const Klass* k);
// klasses that host a jdk.jfr.Event // klasses that host a jdk.jfr.Event
static bool is_host(const Klass* k); static bool is_host(const Klass* k);
@ -69,6 +70,7 @@ class JdkJfrEvent : AllStatic {
// in the set of classes made visible to java // in the set of classes made visible to java
static bool is_visible(const Klass* k); static bool is_visible(const Klass* k);
static bool is_visible(const jclass jc); static bool is_visible(const jclass jc);
static bool is_excluded(const jclass jc);
// all klasses in the hierarchy // all klasses in the hierarchy
static jobject get_all_klasses(TRAPS); static jobject get_all_klasses(TRAPS);

View File

@ -38,6 +38,7 @@
#define EVENT_HOST_KLASS 64 #define EVENT_HOST_KLASS 64
#define EVENT_RESERVED 128 #define EVENT_RESERVED 128
#define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0) #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0)
#define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t) #define IS_EVENT_OR_HOST_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | EVENT_HOST_KLASS)) != 0)
#define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_OR_HOST_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t)
#endif // SHARE_JFR_SUPPORT_JFRKLASSEXTENSION_HPP #endif // SHARE_JFR_SUPPORT_JFRKLASSEXTENSION_HPP

View File

@ -50,7 +50,7 @@ static int thread_id_offset = invalid_offset;
static int valid_offset = invalid_offset; static int valid_offset = invalid_offset;
static bool setup_event_writer_offsets(TRAPS) { static bool setup_event_writer_offsets(TRAPS) {
const char class_name[] = "jdk/jfr/internal/EventWriter"; const char class_name[] = "jdk/jfr/internal/event/EventWriter";
Symbol* const k_sym = SymbolTable::new_symbol(class_name); Symbol* const k_sym = SymbolTable::new_symbol(class_name);
assert(k_sym != NULL, "invariant"); assert(k_sym != NULL, "invariant");
Klass* klass = SystemDictionary::resolve_or_fail(k_sym, true, CHECK_false); Klass* klass = SystemDictionary::resolve_or_fail(k_sym, true, CHECK_false);
@ -207,7 +207,7 @@ static jobject create_new_event_writer(JfrBuffer* buffer, JfrThreadLocal* tl, TR
assert(buffer != NULL, "invariant"); assert(buffer != NULL, "invariant");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
HandleMark hm(THREAD); HandleMark hm(THREAD);
static const char klass[] = "jdk/jfr/internal/EventWriter"; static const char klass[] = "jdk/jfr/internal/event/EventWriter";
static const char method[] = "<init>"; static const char method[] = "<init>";
static const char signature[] = "(JJJJZZ)V"; static const char signature[] = "(JJJJZZ)V";
JavaValue result(T_OBJECT); JavaValue result(T_OBJECT);

View File

@ -41,6 +41,10 @@
#include "opto/subnode.hpp" #include "opto/subnode.hpp"
#include "prims/methodHandles.hpp" #include "prims/methodHandles.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
void trace_type_profile(Compile* C, ciMethod *method, int depth, int bci, ciMethod *prof_method, ciKlass *prof_klass, int site_count, int receiver_count) { void trace_type_profile(Compile* C, ciMethod *method, int depth, int bci, ciMethod *prof_method, ciKlass *prof_klass, int site_count, int receiver_count) {
if (TraceTypeProfile || C->print_inlining()) { if (TraceTypeProfile || C->print_inlining()) {
@ -511,6 +515,7 @@ void Parse::do_call() {
ciKlass* holder = iter().get_declared_method_holder(); ciKlass* holder = iter().get_declared_method_holder();
ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder);
assert(declared_signature != NULL, "cannot be null"); assert(declared_signature != NULL, "cannot be null");
JFR_ONLY(Jfr::on_resolution(this, holder, orig_callee);)
// Bump max node limit for JSR292 users // Bump max node limit for JSR292 users
if (bc() == Bytecodes::_invokedynamic || orig_callee->is_method_handle_intrinsic()) { if (bc() == Bytecodes::_invokedynamic || orig_callee->is_method_handle_intrinsic()) {

View File

@ -3220,7 +3220,7 @@ bool LibraryCallKit::inline_native_getEventWriter() {
set_i_o(_gvn.transform(vthread_compare_io)); set_i_o(_gvn.transform(vthread_compare_io));
// Load the event writer oop by dereferencing the jobject handle. // Load the event writer oop by dereferencing the jobject handle.
ciKlass* klass_EventWriter = env()->find_system_klass(ciSymbol::make("jdk/jfr/internal/EventWriter")); ciKlass* klass_EventWriter = env()->find_system_klass(ciSymbol::make("jdk/jfr/internal/event/EventWriter"));
assert(klass_EventWriter->is_loaded(), "invariant"); assert(klass_EventWriter->is_loaded(), "invariant");
ciInstanceKlass* const instklass_EventWriter = klass_EventWriter->as_instance_klass(); ciInstanceKlass* const instklass_EventWriter = klass_EventWriter->as_instance_klass();
const TypeKlassPtr* const aklass = TypeKlassPtr::make(instklass_EventWriter); const TypeKlassPtr* const aklass = TypeKlassPtr::make(instklass_EventWriter);

View File

@ -150,9 +150,9 @@ public final class EventFactory {
try { try {
return new EventFactory(eventClass, sanitizedAnnotation, sanitizedFields); return new EventFactory(eventClass, sanitizedAnnotation, sanitizedFields);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new IllegalAccessError("Could not access constructor of generated event handler, " + e.getMessage()); throw new IllegalAccessError("Could not access constructor of generated event class, " + e.getMessage());
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
throw new InternalError("Could not find constructor in generated event handler, " + e.getMessage()); throw new InternalError("Could not find constructor in generated event class, " + e.getMessage());
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022, 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
@ -37,11 +37,15 @@ import jdk.jfr.internal.Type;
public final class ErrorThrownEvent extends AbstractJDKEvent { public final class ErrorThrownEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, Class) // commit(..., String, Class)
@Label("Message") @Label("Message")
public String message; public String message;
@Label("Class") @Label("Class")
public Class<?> thrownClass; public Class<?> thrownClass;
public static void commit(long start, long duration, String message, Class<? extends Error> thrownClass) {
// Generated
}
} }

View File

@ -24,15 +24,15 @@
*/ */
package jdk.jfr.events; package jdk.jfr.events;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.internal.Utils; import jdk.jfr.internal.Utils;
import jdk.jfr.internal.event.EventConfiguration;
public final class Handlers { public final class EventConfigurations {
public static final EventHandler SOCKET_READ = Utils.getHandler(SocketReadEvent.class); public static final EventConfiguration SOCKET_READ = Utils.getConfiguration(SocketReadEvent.class);
public static final EventHandler SOCKET_WRITE = Utils.getHandler(SocketWriteEvent.class); public static final EventConfiguration SOCKET_WRITE = Utils.getConfiguration(SocketWriteEvent.class);
public static final EventHandler FILE_READ = Utils.getHandler(FileReadEvent.class); public static final EventConfiguration FILE_READ = Utils.getConfiguration(FileReadEvent.class);
public static final EventHandler FILE_WRITE = Utils.getHandler(FileWriteEvent.class); public static final EventConfiguration FILE_WRITE = Utils.getConfiguration(FileWriteEvent.class);
public static final EventHandler FILE_FORCE = Utils.getHandler(FileForceEvent.class); public static final EventConfiguration FILE_FORCE = Utils.getConfiguration(FileForceEvent.class);
public static final EventHandler ERROR_THROWN = Utils.getHandler(ErrorThrownEvent.class); public static final EventConfiguration ERROR_THROWN = Utils.getConfiguration(ErrorThrownEvent.class);
public static final EventHandler EXCEPTION_THROWN = Utils.getHandler(ExceptionThrownEvent.class); public static final EventConfiguration EXCEPTION_THROWN = Utils.getConfiguration(ExceptionThrownEvent.class);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022, 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
@ -38,11 +38,15 @@ import jdk.jfr.internal.Type;
public final class ExceptionThrownEvent extends AbstractJDKEvent { public final class ExceptionThrownEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, Class) // commit(..., String, Class)
@Label("Message") @Label("Message")
public String message; public String message;
@Label("Class") @Label("Class")
public Class<?> thrownClass; public Class<?> thrownClass;
public static void commit(long start, long duration, String message, Class<? extends Throwable> thrownClass) {
// Generated
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, 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
@ -38,7 +38,7 @@ import jdk.jfr.internal.Type;
public final class FileForceEvent extends AbstractJDKEvent { public final class FileForceEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, boolean) // commit(..., String, boolean)
@Label("Path") @Label("Path")
@Description("Full path of the file") @Description("Full path of the file")
@ -47,4 +47,8 @@ public final class FileForceEvent extends AbstractJDKEvent {
@Label("Update Metadata") @Label("Update Metadata")
@Description("Whether the file metadata is updated") @Description("Whether the file metadata is updated")
public boolean metaData; public boolean metaData;
public static void commit(long start, long duration, String path, boolean metaData) {
// Generated
}
} }

View File

@ -39,7 +39,7 @@ import jdk.jfr.internal.Type;
public final class FileReadEvent extends AbstractJDKEvent { public final class FileReadEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, long, boolean) // commit(..., String, long, boolean)
@Label("Path") @Label("Path")
@Description("Full path of the file, or N/A if a file descriptor was used to create the stream, for example System.in") @Description("Full path of the file, or N/A if a file descriptor was used to create the stream, for example System.in")
@ -53,4 +53,8 @@ public final class FileReadEvent extends AbstractJDKEvent {
@Label("End of File") @Label("End of File")
@Description("If end of file was reached") @Description("If end of file was reached")
public boolean endOfFile; public boolean endOfFile;
public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) {
// Generated
}
} }

View File

@ -39,7 +39,7 @@ import jdk.jfr.internal.Type;
public final class FileWriteEvent extends AbstractJDKEvent { public final class FileWriteEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, long) // commit(..., String, long)
@Label("Path") @Label("Path")
@Description("Full path of the file, or N/A if a file descriptor was used to create the stream, for example System.out and System.err") @Description("Full path of the file, or N/A if a file descriptor was used to create the stream, for example System.out and System.err")
@ -49,4 +49,8 @@ public final class FileWriteEvent extends AbstractJDKEvent {
@Description("Number of bytes written to the file") @Description("Number of bytes written to the file")
@DataAmount @DataAmount
public long bytesWritten; public long bytesWritten;
public static void commit(long start, long duration, String path, long bytesWritten) {
// Generated
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022, 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
@ -40,7 +40,7 @@ import jdk.jfr.internal.Type;
public final class SocketReadEvent extends AbstractJDKEvent { public final class SocketReadEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, String, int, long, long, boolean) // commit(..., String, String, int, long, long, boolean)
@Label("Remote Host") @Label("Remote Host")
public String host; public String host;
@ -63,4 +63,8 @@ public final class SocketReadEvent extends AbstractJDKEvent {
@Label("End of Stream") @Label("End of Stream")
@Description("If end of stream was reached") @Description("If end of stream was reached")
public boolean endOfStream; public boolean endOfStream;
public static void commit(long start, long duration, String host, String address, int port, long timeout, long byteRead, boolean endOfStream) {
// Generated
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022, 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
@ -39,7 +39,7 @@ import jdk.jfr.internal.Type;
public final class SocketWriteEvent extends AbstractJDKEvent { public final class SocketWriteEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in // The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, String, int, long) // commit(..., String, String, int, long)
@Label("Remote Host") @Label("Remote Host")
public String host; public String host;
@ -54,4 +54,8 @@ public final class SocketWriteEvent extends AbstractJDKEvent {
@Description("Number of bytes written to the socket") @Description("Number of bytes written to the socket")
@DataAmount @DataAmount
public long bytesWritten; public long bytesWritten;
public static void commit(long start, long duration, String host, String address, int port, long bytes) {
// Generated
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -27,34 +27,16 @@ package jdk.jfr.internal;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.List;
import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.commons.Method;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
import jdk.jfr.ValueDescriptor; import jdk.jfr.ValueDescriptor;
import jdk.jfr.internal.EventInstrumentation.FieldInfo;
final class ASMToolkit {
private static Type TYPE_STRING = Type.getType(String.class);
private static Type Type_THREAD = Type.getType(Thread.class);
private static Type TYPE_CLASS = Type.getType(Class.class);
public static void invokeSpecial(MethodVisitor methodVisitor, String className, Method m) {
methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, m.getName(), m.getDescriptor(), false);
}
public static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) {
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false);
}
public static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) {
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false);
}
public final class ASMToolkit {
public static final Type TYPE_STRING = Type.getType(String.class);
private static final Type TYPE_THREAD = Type.getType(Thread.class);
private static final Type TYPE_CLASS = Type.getType(Class.class);
public static Type toType(ValueDescriptor v) { public static Type toType(ValueDescriptor v) {
String typeName = v.getTypeName(); String typeName = v.getTypeName();
@ -79,7 +61,7 @@ final class ASMToolkit {
case "java.lang.String": case "java.lang.String":
return TYPE_STRING; return TYPE_STRING;
case "java.lang.Thread": case "java.lang.Thread":
return Type_THREAD; return TYPE_THREAD;
case "java.lang.Class": case "java.lang.Class":
return TYPE_CLASS; return TYPE_CLASS;
} }
@ -135,18 +117,6 @@ final class ASMToolkit {
return className.replace(".", "/"); return className.replace(".", "/");
} }
public static Method makeWriteMethod(List<FieldInfo> fields) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (FieldInfo v : fields) {
if (!v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD) && !v.fieldName.equals(EventInstrumentation.FIELD_STACK_TRACE)) {
sb.append(v.fieldDescriptor);
}
}
sb.append(")V");
return new Method("write", sb.toString());
}
public static void logASM(String className, byte[] bytes) { public static void logASM(String className, byte[] bytes) {
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className); Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className);
if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE)) { if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE)) {
@ -158,5 +128,4 @@ final class ASMToolkit {
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, baos.toString()); Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, baos.toString());
}; };
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -27,7 +27,7 @@ package jdk.jfr.internal;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
final class Bits { // package-private public final class Bits {
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final boolean unalignedAccess = unsafe.unalignedAccess(); private static final boolean unalignedAccess = unsafe.unalignedAccess();
@ -158,12 +158,12 @@ final class Bits { // package-private
} }
// external api // external api
static int putByte(long a, byte x) { public static int putByte(long a, byte x) {
putByte_(a, x); putByte_(a, x);
return Byte.BYTES; return Byte.BYTES;
} }
static int putBoolean(long a, boolean x) { public static int putBoolean(long a, boolean x) {
putBoolean_(a, x); putBoolean_(a, x);
return Byte.BYTES; return Byte.BYTES;
} }
@ -186,7 +186,7 @@ final class Bits { // package-private
return Short.BYTES; return Short.BYTES;
} }
static int putInt(long a, int x) { public static int putInt(long a, int x) {
if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) { if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) {
putInt_(a, x); putInt_(a, x);
return Integer.BYTES; return Integer.BYTES;
@ -204,7 +204,7 @@ final class Bits { // package-private
return Long.BYTES; return Long.BYTES;
} }
static int putFloat(long a, float x) { public static int putFloat(long a, float x) {
if (unalignedAccess || isAddressAligned(a, Float.BYTES)) { if (unalignedAccess || isAddressAligned(a, Float.BYTES)) {
putFloat_(a, x); putFloat_(a, x);
return Float.BYTES; return Float.BYTES;
@ -213,7 +213,7 @@ final class Bits { // package-private
return Float.BYTES; return Float.BYTES;
} }
static int putDouble(long a, double x) { public static int putDouble(long a, double x) {
if (unalignedAccess || isAddressAligned(a, Double.BYTES)) { if (unalignedAccess || isAddressAligned(a, Double.BYTES)) {
putDouble_(a, x); putDouble_(a, x);
return Double.BYTES; return Double.BYTES;

View File

@ -172,4 +172,8 @@ public final class Control {
final String getLastValue() { final String getLastValue() {
return lastValue; return lastValue;
} }
final SettingControl getSettingControl() {
return delegate;
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -101,7 +101,7 @@ public final class EventClassBuilder {
private void buildConstructor() { private void buildConstructor() {
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null); MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null);
mv.visitIntInsn(Opcodes.ALOAD, 0); mv.visitIntInsn(Opcodes.ALOAD, 0);
ASMToolkit.invokeSpecial(mv, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), false);
mv.visitInsn(Opcodes.RETURN); mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
} }

View File

@ -170,9 +170,8 @@ public final class EventControl {
Module settingModule = settingsClass.getModule(); Module settingModule = settingsClass.getModule();
Modules.addReads(settingModule, EventControl.class.getModule()); Modules.addReads(settingModule, EventControl.class.getModule());
int index = settingInfos.size(); int index = settingInfos.size();
SettingInfo si = new SettingInfo(FIELD_SETTING_PREFIX + index, index); SettingControl settingControl = instantiateSettingControl(settingsClass);
si.settingControl = instantiateSettingControl(settingsClass); Control c = new Control(settingControl, null);
Control c = new Control(si.settingControl, null);
c.setDefault(); c.setDefault();
String defaultValue = c.getValue(); String defaultValue = c.getValue();
if (defaultValue != null) { if (defaultValue != null) {
@ -187,7 +186,7 @@ public final class EventControl {
aes.trimToSize(); aes.trimToSize();
addControl(settingName, c); addControl(settingName, c);
eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, settingName, defaultValue, aes)); eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, settingName, defaultValue, aes));
settingInfos.add(si); settingInfos.add(new SettingInfo(FIELD_SETTING_PREFIX + index, index, null, null, settingControl));
} }
} catch (InstantiationException e) { } catch (InstantiationException e) {
// Programming error by user, fail fast // Programming error by user, fail fast

View File

@ -1,337 +0,0 @@
/*
* Copyright (c) 2016, 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. 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.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.commons.Method;
import jdk.jfr.Event;
import jdk.jfr.EventType;
import jdk.jfr.SettingControl;
import jdk.jfr.ValueDescriptor;
import jdk.jfr.internal.EventInstrumentation.FieldInfo;
import jdk.jfr.internal.EventInstrumentation.SettingInfo;
import jdk.jfr.internal.handlers.EventHandler;
final class EventHandlerCreator {
// TODO:
// How can we find out class version without loading a
// class as resource in a privileged block and use ASM to inspect
// the contents. Using '52' even though we know later versions
// are available. The reason for this is compatibility aspects
// with for example WLS.
private static final int CLASS_VERSION = 52;
// This is needed so a new EventHandler is automatically generated in MetadataRepository
// if a user Event class is loaded using APPCDS/CDS.
private static final String SUFFIX = "_" + System.currentTimeMillis() + "-" + JVM.getJVM().getPid();
private static final String FIELD_EVENT_TYPE = "platformEventType";
private static final String FIELD_PREFIX_STRING_POOL = "stringPool";
private static final Type TYPE_STRING_POOL = Type.getType(StringPool.class);
private static final Type TYPE_EVENT_WRITER = Type.getType(EventWriter.class);
private static final Type TYPE_PLATFORM_EVENT_TYPE = Type.getType(PlatformEventType.class);
private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class);
private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
private static final Type TYPE_EVENT_TYPE = Type.getType(EventType.class);
private static final Type TYPE_EVENT_CONTROL = Type.getType(EventControl.class);
private static final String DESCRIPTOR_EVENT_HANDLER = "(" + Type.BOOLEAN_TYPE.getDescriptor() + TYPE_EVENT_TYPE.getDescriptor() + TYPE_EVENT_CONTROL.getDescriptor() + ")V";
private static final Method METHOD_GET_EVENT_WRITER = new Method("getEventWriter", "()" + TYPE_EVENT_WRITER.getDescriptor());
private static final Method METHOD_EVENT_HANDLER_CONSTRUCTOR = new Method("<init>", DESCRIPTOR_EVENT_HANDLER);
private static final Method METHOD_RESET = new Method("reset", "()V");
private final ClassWriter classWriter;
private final String className;
private final String internalClassName;
private final List<SettingInfo> settingInfos;
private final List<FieldInfo> fields;
public EventHandlerCreator(long id, List<SettingInfo> settingInfos, List<FieldInfo> fields) {
this.classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
this.className = makeEventHandlerName(id);
this.internalClassName = ASMToolkit.getInternalName(className);
this.settingInfos = settingInfos;
this.fields = fields;
}
public static String makeEventHandlerName(long id) {
return EventHandler.class.getName() + id + SUFFIX;
}
public EventHandlerCreator(long id, List<SettingInfo> settingInfos, EventType type, Class<? extends jdk.internal.event.Event> eventClass) {
this(id, settingInfos, createFieldInfos(eventClass, type));
}
private static List<FieldInfo> createFieldInfos(Class<? extends jdk.internal.event.Event> eventClass, EventType type) throws Error {
List<FieldInfo> fieldInfos = new ArrayList<>();
for (ValueDescriptor v : type.getFields()) {
// Only value descriptors that are not fields on the event class.
if (v != TypeLibrary.STACK_TRACE_FIELD && v != TypeLibrary.THREAD_FIELD) {
String fieldName = PrivateAccess.getInstance().getFieldName(v);
String fieldDescriptor = ASMToolkit.getDescriptor(v.getTypeName());
Class<?> c = eventClass;
String internalName = null;
while (c != Event.class) {
try {
Field field = c.getDeclaredField(fieldName);
if (c == eventClass || !Modifier.isPrivate(field.getModifiers())) {
internalName = ASMToolkit.getInternalName(c.getName());
break;
}
} catch (NoSuchFieldException | SecurityException e) {
// ignore
}
c = c.getSuperclass();
}
if (internalName != null) {
fieldInfos.add(new FieldInfo(fieldName, fieldDescriptor, internalName));
} else {
throw new InternalError("Could not locate field " + fieldName + " for event type " + type.getName());
}
}
}
return fieldInfos;
}
public Class<? extends EventHandler> makeEventHandlerClass() {
buildClassInfo();
buildConstructor();
buildWriteMethod();
byte[] bytes = classWriter.toByteArray();
ASMToolkit.logASM(className, bytes);
return SecuritySupport.defineClass(EventHandler.class, bytes).asSubclass(EventHandler.class);
}
public static EventHandler instantiateEventHandler(Class<? extends EventHandler> handlerClass, boolean registered, EventType eventType, EventControl eventControl) throws Error {
final Constructor<?> cc;
try {
cc = handlerClass.getDeclaredConstructors()[0];
} catch (Exception e) {
throw (Error) new InternalError("Could not get handler constructor for " + eventType.getName()).initCause(e);
}
// Users should not be allowed to create instances of the event handler
// so we need to unlock it here.
SecuritySupport.setAccessible(cc);
try {
List<SettingInfo> settingInfos = eventControl.getSettingInfos();
Object[] arguments = new Object[3 + settingInfos.size()];
arguments[0] = registered;
arguments[1] = eventType;
arguments[2] = eventControl;
for (SettingInfo si : settingInfos) {
arguments[si.index + 3] = si.settingControl;
}
return (EventHandler) cc.newInstance(arguments);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw (Error) new InternalError("Could not instantiate event handler for " + eventType.getName() + ". " + e.getMessage()).initCause(e);
}
}
private void buildConstructor() {
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PRIVATE, METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), makeConstructorDescriptor(settingInfos), null, null);
mv.visitVarInsn(Opcodes.ALOAD, 0); // this
mv.visitVarInsn(Opcodes.ILOAD, 1); // registered
mv.visitVarInsn(Opcodes.ALOAD, 2); // event type
mv.visitVarInsn(Opcodes.ALOAD, 3); // event control
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(EventHandler.class), METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), METHOD_EVENT_HANDLER_CONSTRUCTOR.getDescriptor(), false);
for (SettingInfo si : settingInfos) {
mv.visitVarInsn(Opcodes.ALOAD, 0); // this
mv.visitVarInsn(Opcodes.ALOAD, si.index + 4); // Setting Control
mv.visitFieldInsn(Opcodes.PUTFIELD, internalClassName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
}
// initialized string field writers
int fieldIndex = 0;
for (FieldInfo field : fields) {
if (field.isString()) {
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(EventHandler.class), "createStringFieldWriter", "()" + TYPE_STRING_POOL.getDescriptor(), false);
mv.visitFieldInsn(Opcodes.PUTFIELD, internalClassName, FIELD_PREFIX_STRING_POOL + fieldIndex, TYPE_STRING_POOL.getDescriptor());
}
fieldIndex++;
}
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void buildClassInfo() {
String internalSuperName = ASMToolkit.getInternalName(EventHandler.class.getName());
classWriter.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
for (SettingInfo si : settingInfos) {
classWriter.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor(), null, null);
}
int fieldIndex = 0;
for (FieldInfo field : fields) {
if (field.isString()) {
classWriter.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, FIELD_PREFIX_STRING_POOL+ fieldIndex, TYPE_STRING_POOL.getDescriptor(), null, null);
}
fieldIndex++;
}
}
private void visitMethod(final MethodVisitor mv, final int opcode, final Type type, final Method method) {
mv.visitMethodInsn(opcode, type.getInternalName(), method.getName(), method.getDescriptor(), false);
}
private void buildWriteMethod() {
int argIndex = 0; // // indexes the argument type array, the argument type array does not include 'this'
int slotIndex = 1; // indexes the proper slot in the local variable table, takes type size into account, therefore sometimes argIndex != slotIndex
int fieldIndex = 0;
Method desc = ASMToolkit.makeWriteMethod(fields);
Type[] argumentTypes = Type.getArgumentTypes(desc.getDescriptor());
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, desc.getName(), desc.getDescriptor(), null, null);
mv.visitCode();
Label start = new Label();
Label endTryBlock = new Label();
Label exceptionHandler = new Label();
mv.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable");
mv.visitLabel(start);
visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
// stack: [BW]
mv.visitInsn(Opcodes.DUP);
// stack: [BW], [BW]
// write begin event
mv.visitVarInsn(Opcodes.ALOAD, 0);
// stack: [BW], [BW], [this]
mv.visitFieldInsn(Opcodes.GETFIELD, TYPE_EVENT_HANDLER.getInternalName(), FIELD_EVENT_TYPE, TYPE_PLATFORM_EVENT_TYPE.getDescriptor());
// stack: [BW], [BW], [BS]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asASM());
// stack: [BW], [integer]
Label excluded = new Label();
mv.visitJumpInsn(Opcodes.IFEQ, excluded);
// stack: [BW]
// write startTime
mv.visitInsn(Opcodes.DUP);
// stack: [BW], [BW]
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
// stack: [BW], [BW], [long]
slotIndex += argumentTypes[argIndex++].getSize();
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
// stack: [BW]
fieldIndex++;
// write duration
mv.visitInsn(Opcodes.DUP);
// stack: [BW], [BW]
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
// stack: [BW], [BW], [long]
slotIndex += argumentTypes[argIndex++].getSize();
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
// stack: [BW]
fieldIndex++;
// write eventThread
mv.visitInsn(Opcodes.DUP);
// stack: [BW], [BW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM());
// stack: [BW]
// write stackTrace
mv.visitInsn(Opcodes.DUP);
// stack: [BW], [BW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM());
// stack: [BW]
// write custom fields
while (fieldIndex < fields.size()) {
mv.visitInsn(Opcodes.DUP);
// stack: [BW], [BW]
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
// stack:[BW], [BW], [field]
slotIndex += argumentTypes[argIndex++].getSize();
FieldInfo field = fields.get(fieldIndex);
if (field.isString()) {
mv.visitVarInsn(Opcodes.ALOAD, 0);
// stack:[BW], [BW], [field], [this]
mv.visitFieldInsn(Opcodes.GETFIELD, this.internalClassName, FIELD_PREFIX_STRING_POOL + fieldIndex, TYPE_STRING_POOL.getDescriptor());
// stack:[BW], [BW], [field], [string]
}
EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field);
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, eventMethod.asASM());
// stack: [BW]
fieldIndex++;
}
// stack: [BW]
// write end event (writer already on stack)
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM());
// stack [integer]
// notified -> restart event write attempt
mv.visitJumpInsn(Opcodes.IFEQ, start);
// stack:
mv.visitLabel(endTryBlock);
Label end = new Label();
mv.visitJumpInsn(Opcodes.GOTO, end);
mv.visitLabel(exceptionHandler);
// stack: [ex]
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"});
visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
// stack: [ex] [BW]
mv.visitInsn(Opcodes.DUP);
// stack: [ex] [BW] [BW]
Label rethrow = new Label();
mv.visitJumpInsn(Opcodes.IFNULL, rethrow);
// stack: [ex] [BW]
mv.visitInsn(Opcodes.DUP);
// stack: [ex] [BW] [BW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET);
mv.visitLabel(rethrow);
// stack:[ex] [BW]
mv.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] {"java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName()});
mv.visitInsn(Opcodes.POP);
// stack:[ex]
mv.visitInsn(Opcodes.ATHROW);
mv.visitLabel(excluded);
// stack: [BW]
mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName()} );
mv.visitInsn(Opcodes.POP);
mv.visitLabel(end);
// stack:
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private static String makeConstructorDescriptor(List<SettingInfo> settingsInfos) {
StringJoiner constructordescriptor = new StringJoiner("", "(", ")V");
constructordescriptor.add(Type.BOOLEAN_TYPE.getDescriptor());
constructordescriptor.add(Type.getType(EventType.class).getDescriptor());
constructordescriptor.add(Type.getType(EventControl.class).getDescriptor());
for (int i = 0; i < settingsInfos.size(); i++) {
constructordescriptor.add(TYPE_SETTING_CONTROL.getDescriptor());
}
return constructordescriptor.toString();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -51,104 +51,111 @@ import jdk.jfr.Name;
import jdk.jfr.Registered; import jdk.jfr.Registered;
import jdk.jfr.SettingControl; import jdk.jfr.SettingControl;
import jdk.jfr.SettingDefinition; import jdk.jfr.SettingDefinition;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.internal.event.EventWriter;
/** /**
* Class responsible for adding instrumentation to a subclass of {@link Event}. * Class responsible for adding instrumentation to a subclass of {@link Event}.
* *
*/ */
public final class EventInstrumentation { public final class EventInstrumentation {
static final class SettingInfo {
private String methodName;
private String internalSettingName;
private String settingDescriptor;
final String fieldName;
final int index;
// The settingControl is passed to EventHandler where it is record SettingInfo(String fieldName, int index, Type paramType, String methodName, SettingControl settingControl) {
// used to check enablement before calling commit /**
// Methods on settingControl must never be invoked * A malicious user must never be able to run a callback in the wrong
// directly by JFR, instead use jdk.jfr.internal.Control * context. Methods on SettingControl must therefore never be invoked directly
SettingControl settingControl; * by JFR, instead use jdk.jfr.internal.Control.
*/
public SettingInfo(String fieldName, int index) { public SettingControl settingControl() {
this.fieldName = fieldName; return this.settingControl;
this.index = index;
} }
} }
static final class FieldInfo { record FieldInfo(String fieldName, String fieldDescriptor, String internalClassName) {
private static final Type STRING = Type.getType(String.class);
final String fieldName;
final String fieldDescriptor;
final String internalClassName;
public FieldInfo(String fieldName, String fieldDescriptor, String internalClassName) {
this.fieldName = fieldName;
this.fieldDescriptor = fieldDescriptor;
this.internalClassName = internalClassName;
}
public boolean isString() {
return STRING.getDescriptor().equals(fieldDescriptor);
}
} }
public static final String FIELD_EVENT_THREAD = "eventThread"; public static final String FIELD_EVENT_THREAD = "eventThread";
public static final String FIELD_STACK_TRACE = "stackTrace"; public static final String FIELD_STACK_TRACE = "stackTrace";
public static final String FIELD_DURATION = "duration"; public static final String FIELD_DURATION = "duration";
static final String FIELD_EVENT_HANDLER = "eventHandler"; static final String FIELD_EVENT_CONFIGURATION = "eventConfiguration";
static final String FIELD_START_TIME = "startTime"; static final String FIELD_START_TIME = "startTime";
private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class); private static final String ANNOTATION_NAME_DESCRIPTOR = Type.getDescriptor(Name.class);
private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class); private static final String ANNOTATION_REGISTERED_DESCRIPTOR = Type.getDescriptor(Registered.class);
private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class); private static final String ANNOTATION_ENABLED_DESCRIPTOR = Type.getDescriptor(Enabled.class);
private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class); private static final Type TYPE_EVENT_CONFIGURATION = Type.getType(EventConfiguration.class);
private static final Type TYPE_EVENT_WRITER = Type.getType(EventWriter.class);
private static final Type TYPE_EVENT_WRITER_FACTORY = Type.getType("Ljdk/jfr/internal/event/EventWriterFactory;");
private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class); private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
private static final Type TYPE_OBJECT = Type.getType(Object.class); private static final String TYPE_OBJECT_DESCRIPTOR = Type.getDescriptor(Object.class);
private static final String TYPE_EVENT_CONFIGURATION_DESCRIPTOR = TYPE_EVENT_CONFIGURATION.getDescriptor();
private static final String TYPE_SETTING_DEFINITION_DESCRIPTOR = Type.getDescriptor(SettingDefinition.class);
private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]); private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]);
private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]); private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]);
private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]); private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]);
private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]); private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]);
private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]); private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]);
private static final Method METHOD_GET_EVENT_WRITER_KEY = new Method("getEventWriter", TYPE_EVENT_WRITER, new Type[] { Type.LONG_TYPE });
private static final Method METHOD_EVENT_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[0]); private static final Method METHOD_EVENT_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[0]);
private static final Method METHOD_EVENT_HANDLER_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE }); private static final Method METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE });
private static final Method METHOD_EVENT_CONFIGURATION_GET_SETTING = new Method("getSetting", TYPE_SETTING_CONTROL, new Type[] { Type.INT_TYPE });
private static final Method METHOD_DURATION = new Method("duration", Type.LONG_TYPE, new Type[] { Type.LONG_TYPE }); private static final Method METHOD_DURATION = new Method("duration", Type.LONG_TYPE, new Type[] { Type.LONG_TYPE });
private static final Method METHOD_RESET = new Method("reset", "()V");
private final ClassNode classNode; private final ClassNode classNode;
private final List<SettingInfo> settingInfos; private final List<SettingInfo> settingInfos;
private final List<FieldInfo> fieldInfos;; private final List<FieldInfo> fieldInfos;;
private final Method writeMethod;
private final String eventHandlerXInternalName;
private final String eventName; private final String eventName;
private final boolean untypedEventHandler; private final Class<?> superClass;
private boolean guardHandlerReference; private final boolean untypedEventConfiguration;
private Class<?> superClass; private final Method staticCommitMethod;
private final long eventTypeId;
private final boolean guardEventConfiguration;
EventInstrumentation(Class<?> superClass, byte[] bytes, long id) { EventInstrumentation(Class<?> superClass, byte[] bytes, long id, boolean bootClass, boolean guardEventConfiguration) {
this.eventTypeId = id;
this.superClass = superClass; this.superClass = superClass;
this.classNode = createClassNode(bytes); this.classNode = createClassNode(bytes);
this.settingInfos = buildSettingInfos(superClass, classNode); this.settingInfos = buildSettingInfos(superClass, classNode);
this.fieldInfos = buildFieldInfos(superClass, classNode); this.fieldInfos = buildFieldInfos(superClass, classNode);
this.untypedEventHandler = hasUntypedHandler(); String n = annotationValue(classNode, ANNOTATION_NAME_DESCRIPTOR, String.class);
this.writeMethod = makeWriteMethod(fieldInfos);
this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id));
String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class);
this.eventName = n == null ? classNode.name.replace("/", ".") : n; this.eventName = n == null ? classNode.name.replace("/", ".") : n;
this.staticCommitMethod = bootClass ? findStaticCommitMethod(classNode, fieldInfos) : null;
this.untypedEventConfiguration = hasUntypedConfiguration();
// Corner case when we are forced to generate bytecode (bytesForEagerInstrumentation)
// We can't reference EventConfiguration::isEnabled() before event class has been registered,
// so we add a guard against a null reference.
this.guardEventConfiguration = guardEventConfiguration;
} }
private boolean hasUntypedHandler() { public static Method findStaticCommitMethod(ClassNode classNode, List<FieldInfo> fields) {
for (FieldNode field : classNode.fields) { StringBuilder sb = new StringBuilder();
if (FIELD_EVENT_HANDLER.equals(field.name)) { sb.append("(");
return field.desc.equals(TYPE_OBJECT.getDescriptor()); for (FieldInfo v : fields) {
sb.append(v.fieldDescriptor);
}
sb.append(")V");
Method m = new Method("commit", sb.toString());
for (MethodNode method : classNode.methods) {
if ("commit".equals(method.name) && m.getDescriptor().equals(method.desc)) {
return m;
} }
} }
throw new InternalError("Class missing handler field"); return null;
}
private boolean hasUntypedConfiguration() {
for (FieldNode field : classNode.fields) {
if (FIELD_EVENT_CONFIGURATION.equals(field.name)) {
return field.desc.equals(TYPE_OBJECT_DESCRIPTOR);
}
}
throw new InternalError("Class missing configuration field");
} }
public String getClassName() { public String getClassName() {
return classNode.name.replace("/","."); return classNode.name.replace("/", ".");
} }
private ClassNode createClassNode(byte[] bytes) { private ClassNode createClassNode(byte[] bytes) {
@ -159,7 +166,7 @@ public final class EventInstrumentation {
} }
boolean isRegistered() { boolean isRegistered() {
Boolean result = annotationValue(classNode, ANNOTATION_TYPE_REGISTERED.getDescriptor(), Boolean.class); Boolean result = annotationValue(classNode, ANNOTATION_REGISTERED_DESCRIPTOR, Boolean.class);
if (result != null) { if (result != null) {
return result.booleanValue(); return result.booleanValue();
} }
@ -173,7 +180,7 @@ public final class EventInstrumentation {
} }
boolean isEnabled() { boolean isEnabled() {
Boolean result = annotationValue(classNode, ANNOTATION_TYPE_ENABLED.getDescriptor(), Boolean.class); Boolean result = annotationValue(classNode, ANNOTATION_ENABLED_DESCRIPTOR, Boolean.class);
if (result != null) { if (result != null) {
return result.booleanValue(); return result.booleanValue();
} }
@ -198,7 +205,7 @@ public final class EventInstrumentation {
if (key instanceof String keyName && value != null) { if (key instanceof String keyName && value != null) {
if (type == value.getClass()) { if (type == value.getClass()) {
if ("value".equals(keyName)) { if ("value".equals(keyName)) {
return (T) value; return (T) value;
} }
} }
} }
@ -212,20 +219,18 @@ public final class EventInstrumentation {
private static List<SettingInfo> buildSettingInfos(Class<?> superClass, ClassNode classNode) { private static List<SettingInfo> buildSettingInfos(Class<?> superClass, ClassNode classNode) {
Set<String> methodSet = new HashSet<>(); Set<String> methodSet = new HashSet<>();
List<SettingInfo> settingInfos = new ArrayList<>(); List<SettingInfo> settingInfos = new ArrayList<>();
String settingDescriptor = Type.getType(SettingDefinition.class).getDescriptor();
String nameDescriptor = Type.getType(Name.class).getDescriptor();
for (MethodNode m : classNode.methods) { for (MethodNode m : classNode.methods) {
if (m.visibleAnnotations != null) { if (m.visibleAnnotations != null) {
for (AnnotationNode an : m.visibleAnnotations) { for (AnnotationNode an : m.visibleAnnotations) {
// We can't really validate the method at this // We can't really validate the method at this
// stage. We would need to check that the parameter // stage. We would need to check that the parameter
// is an instance of SettingControl. // is an instance of SettingControl.
if (settingDescriptor.equals(an.desc)) { if (TYPE_SETTING_DEFINITION_DESCRIPTOR.equals(an.desc)) {
String name = m.name; String name = m.name;
for (AnnotationNode nameCandidate : m.visibleAnnotations) { for (AnnotationNode nameCandidate : m.visibleAnnotations) {
if (nameDescriptor.equals(nameCandidate.desc)) { if (ANNOTATION_NAME_DESCRIPTOR.equals(nameCandidate.desc)) {
List<Object> values = nameCandidate.values; List<Object> values = nameCandidate.values;
if (values.size() == 1 && values.get(0) instanceof String s) { if (values.size() == 1 && values.get(0)instanceof String s) {
name = Utils.validJavaIdentifier(s, name); name = Utils.validJavaIdentifier(s, name);
} }
} }
@ -237,12 +242,8 @@ public final class EventInstrumentation {
Type paramType = args[0]; Type paramType = args[0];
String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size(); String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size();
int index = settingInfos.size(); int index = settingInfos.size();
SettingInfo si = new SettingInfo(fieldName, index);
si.methodName = m.name;
si.settingDescriptor = paramType.getDescriptor();
si.internalSettingName = paramType.getInternalName();
methodSet.add(m.name); methodSet.add(m.name);
settingInfos.add(si); settingInfos.add(new SettingInfo(fieldName, index, paramType, m.name, null));
} }
} }
} }
@ -260,12 +261,8 @@ public final class EventInstrumentation {
Type paramType = Type.getType(param.getType()); Type paramType = Type.getType(param.getType());
String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size(); String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size();
int index = settingInfos.size(); int index = settingInfos.size();
SettingInfo si = new SettingInfo(fieldName, index);
si.methodName = method.getName();
si.settingDescriptor = paramType.getDescriptor();
si.internalSettingName = paramType.getInternalName();
methodSet.add(method.getName()); methodSet.add(method.getName());
settingInfos.add(si); settingInfos.add(new SettingInfo(fieldName, index, paramType, method.getName(), null));
} }
} }
} }
@ -278,7 +275,7 @@ public final class EventInstrumentation {
private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) { private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
Set<String> fieldSet = new HashSet<>(); Set<String> fieldSet = new HashSet<>();
List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size()); List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size());
// These two field are added by native as transient so they will be // These two fields are added by native as 'transient' so they will be
// ignored by the loop below. // ignored by the loop below.
// The benefit of adding them manually is that we can // The benefit of adding them manually is that we can
// control in which order they occur and we can add @Name, @Description // control in which order they occur and we can add @Name, @Description
@ -339,17 +336,16 @@ public final class EventInstrumentation {
} }
private void makeInstrumented() { private void makeInstrumented() {
// MyEvent#isEnabled()
updateMethod(METHOD_IS_ENABLED, methodVisitor -> { updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
Label nullLabel = new Label(); Label nullLabel = new Label();
if (guardHandlerReference) { if (guardEventConfiguration) {
getEventHandler(methodVisitor); getEventConfiguration(methodVisitor);
methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel); methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel);
} }
getEventHandler(methodVisitor); getEventConfiguration(methodVisitor);
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED); invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED);
methodVisitor.visitInsn(Opcodes.IRETURN); methodVisitor.visitInsn(Opcodes.IRETURN);
if (guardHandlerReference) { if (guardEventConfiguration) {
methodVisitor.visitLabel(nullLabel); methodVisitor.visitLabel(nullLabel);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitInsn(Opcodes.ICONST_0); methodVisitor.visitInsn(Opcodes.ICONST_0);
@ -360,7 +356,7 @@ public final class EventInstrumentation {
// MyEvent#begin() // MyEvent#begin()
updateMethod(METHOD_BEGIN, methodVisitor -> { updateMethod(METHOD_BEGIN, methodVisitor -> {
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP); invokeStatic(methodVisitor, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP);
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J"); methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J");
methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitInsn(Opcodes.RETURN);
}); });
@ -370,105 +366,301 @@ public final class EventInstrumentation {
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_DURATION); invokeStatic(methodVisitor, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_DURATION);
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J"); methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J");
methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(0, 0); methodVisitor.visitMaxs(0, 0);
}); });
updateMethod(METHOD_COMMIT, methodVisitor -> { // MyEvent#commit() or static MyEvent#commit(...)
// if (!isEnable()) { if (staticCommitMethod != null) {
// return; updateExistingWithEmptyVoidMethod(METHOD_COMMIT);
// } updateMethod(staticCommitMethod, mv -> {
methodVisitor.visitCode(); // indexes the argument type array, the argument type array does not include
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); // 'this'
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false); int argIndex = 0;
Label l0 = new Label(); // indexes the proper slot in the local variable table, takes type size into
methodVisitor.visitJumpInsn(Opcodes.IFNE, l0); // account, therefore sometimes argIndex != slotIndex
methodVisitor.visitInsn(Opcodes.RETURN); int slotIndex = 0;
methodVisitor.visitLabel(l0); int fieldIndex = 0;
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); Type[] argumentTypes = Type.getArgumentTypes(staticCommitMethod.getDescriptor());
// if (startTime == 0) { mv.visitCode();
// startTime = EventWriter.timestamp(); Label start = new Label();
// } else { Label endTryBlock = new Label();
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); Label exceptionHandler = new Label();
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); mv.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable");
methodVisitor.visitInsn(Opcodes.LCONST_0); mv.visitLabel(start);
methodVisitor.visitInsn(Opcodes.LCMP); getEventWriter(mv);
Label durationalEvent = new Label(); // stack: [EW]
methodVisitor.visitJumpInsn(Opcodes.IFNE, durationalEvent); mv.visitInsn(Opcodes.DUP);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); // stack: [EW], [EW]
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false); // write begin event
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J"); getEventConfiguration(mv);
Label commit = new Label(); // stack: [EW], [EW], [EventConfiguration]
methodVisitor.visitJumpInsn(Opcodes.GOTO, commit); mv.visitLdcInsn(eventTypeId);
// if (duration == 0) { // stack: [EW], [EW], [EventConfiguration] [long]
// duration = EventWriter.timestamp() - startTime; visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asASM());
// } // stack: [EW], [integer]
// } Label excluded = new Label();
methodVisitor.visitLabel(durationalEvent); mv.visitJumpInsn(Opcodes.IFEQ, excluded);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); // stack: [EW]
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); // write startTime
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); mv.visitInsn(Opcodes.DUP);
methodVisitor.visitInsn(Opcodes.LCONST_0); // stack: [EW], [EW]
methodVisitor.visitInsn(Opcodes.LCMP); mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
methodVisitor.visitJumpInsn(Opcodes.IFNE, commit); // stack: [EW], [EW], [long]
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); slotIndex += argumentTypes[argIndex++].getSize();
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false); visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); // stack: [EW]
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); fieldIndex++;
methodVisitor.visitInsn(Opcodes.LSUB); // write duration
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J"); mv.visitInsn(Opcodes.DUP);
methodVisitor.visitLabel(commit); // stack: [EW], [EW]
// if (shouldCommit()) { mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); // stack: [EW], [EW], [long]
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); slotIndex += argumentTypes[argIndex++].getSize();
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false); visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
Label end = new Label(); // stack: [EW]
// eventHandler.write(...); fieldIndex++;
// } // write eventThread
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end); mv.visitInsn(Opcodes.DUP);
getEventHandler(methodVisitor); // stack: [EW], [EW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM());
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); // stack: [EW]
for (FieldInfo fi : fieldInfos) { // write stackTrace
mv.visitInsn(Opcodes.DUP);
// stack: [EW], [EW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM());
// stack: [EW]
// write custom fields
while (fieldIndex < fieldInfos.size()) {
mv.visitInsn(Opcodes.DUP);
// stack: [EW], [EW]
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
// stack:[EW], [EW], [field]
slotIndex += argumentTypes[argIndex++].getSize();
FieldInfo field = fieldInfos.get(fieldIndex);
EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field);
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, eventMethod.asASM());
// stack: [EW]
fieldIndex++;
}
// stack: [EW]
// write end event (writer already on stack)
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM());
// stack [integer]
// notified -> restart event write attempt
mv.visitJumpInsn(Opcodes.IFEQ, start);
// stack:
mv.visitLabel(endTryBlock);
Label end = new Label();
mv.visitJumpInsn(Opcodes.GOTO, end);
mv.visitLabel(exceptionHandler);
// stack: [ex]
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" });
getEventWriter(mv);
// stack: [ex] [EW]
mv.visitInsn(Opcodes.DUP);
// stack: [ex] [EW] [EW]
Label rethrow = new Label();
mv.visitJumpInsn(Opcodes.IFNULL, rethrow);
// stack: [ex] [EW]
mv.visitInsn(Opcodes.DUP);
// stack: [ex] [EW] [EW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET);
mv.visitLabel(rethrow);
// stack:[ex] [EW]
mv.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] { "java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName() });
mv.visitInsn(Opcodes.POP);
// stack:[ex]
mv.visitInsn(Opcodes.ATHROW);
mv.visitLabel(excluded);
// stack: [EW]
mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName() });
mv.visitInsn(Opcodes.POP);
mv.visitLabel(end);
// stack:
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
});
} else {
updateMethod(METHOD_COMMIT, methodVisitor -> {
// if (!isEnable()) {
// return;
// }
methodVisitor.visitCode();
Label start = new Label();
Label endTryBlock = new Label();
Label exceptionHandler = new Label();
methodVisitor.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable");
methodVisitor.visitLabel(start);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false);
} Label l0 = new Label();
methodVisitor.visitJumpInsn(Opcodes.IFNE, l0);
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, eventHandlerXInternalName, writeMethod.getName(), writeMethod.getDescriptor(), false); methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitLabel(end); methodVisitor.visitLabel(l0);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitInsn(Opcodes.RETURN); // if (startTime == 0) {
methodVisitor.visitEnd(); // startTime = EventWriter.timestamp();
}); // } else {
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
methodVisitor.visitInsn(Opcodes.LCONST_0);
methodVisitor.visitInsn(Opcodes.LCMP);
Label durationalEvent = new Label();
methodVisitor.visitJumpInsn(Opcodes.IFNE, durationalEvent);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false);
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J");
Label commit = new Label();
methodVisitor.visitJumpInsn(Opcodes.GOTO, commit);
// if (duration == 0) {
// duration = EventWriter.timestamp() - startTime;
// }
// }
methodVisitor.visitLabel(durationalEvent);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
methodVisitor.visitInsn(Opcodes.LCONST_0);
methodVisitor.visitInsn(Opcodes.LCMP);
methodVisitor.visitJumpInsn(Opcodes.IFNE, commit);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
methodVisitor.visitInsn(Opcodes.LSUB);
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J");
methodVisitor.visitLabel(commit);
// if (shouldCommit()) {
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
invokeVirtual(methodVisitor, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT);
Label end = new Label();
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
getEventWriter(methodVisitor);
// stack: [EW]
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [EW] [EW]
getEventConfiguration(methodVisitor);
// stack: [EW] [EW] [EC]
methodVisitor.visitLdcInsn(eventTypeId);
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asmMethod);
Label excluded = new Label();
// stack: [EW] [int]
methodVisitor.visitJumpInsn(Opcodes.IFEQ, excluded);
// stack: [EW]
int fieldIndex = 0;
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [EW] [EW]
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
// stack: [EW] [EW] [this]
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
// stack: [EW] [EW] [long]
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asmMethod);
// stack: [EW]
fieldIndex++;
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [EW] [EW]
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
// stack: [EW] [EW] [this]
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
// stack: [EW] [EW] [long]
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asmMethod);
// stack: [EW]
fieldIndex++;
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [EW] [EW]
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM());
// stack: [EW]
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [EW] [EW]
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM());
// stack: [EW]
while (fieldIndex < fieldInfos.size()) {
FieldInfo field = fieldInfos.get(fieldIndex);
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [EW] [EW]
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
// stack: [EW] [EW] [this]
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), field.fieldName, field.fieldDescriptor);
// stack: [EW] [EW] <T>
EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field);
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, eventMethod.asmMethod);
// stack: [EW]
fieldIndex++;
}
// stack:[EW]
invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM());
// stack [int]
// notified -> restart event write attempt
methodVisitor.visitJumpInsn(Opcodes.IFEQ, start);
methodVisitor.visitLabel(endTryBlock);
methodVisitor.visitJumpInsn(Opcodes.GOTO, end);
methodVisitor.visitLabel(exceptionHandler);
// stack: [ex]
methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" });
getEventWriter(methodVisitor);
// stack: [ex] [EW]
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [ex] [EW] [EW]
Label rethrow = new Label();
methodVisitor.visitJumpInsn(Opcodes.IFNULL, rethrow);
// stack: [ex] [EW]
methodVisitor.visitInsn(Opcodes.DUP);
// stack: [ex] [EW] [EW]
visitMethod(methodVisitor, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET);
methodVisitor.visitLabel(rethrow);
// stack:[ex] [EW]
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] { "java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName() });
methodVisitor.visitInsn(Opcodes.POP);
// stack:[ex]
methodVisitor.visitInsn(Opcodes.ATHROW);
methodVisitor.visitLabel(excluded);
// stack: [EW]
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName() });
methodVisitor.visitInsn(Opcodes.POP);
methodVisitor.visitLabel(end);
// stack:
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(0, 0);
methodVisitor.visitEnd();
});
}
// MyEvent#shouldCommit() // MyEvent#shouldCommit()
updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> { updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
Label fail = new Label(); Label fail = new Label();
if (guardHandlerReference) { if (guardEventConfiguration) {
getEventHandler(methodVisitor); getEventConfiguration(methodVisitor);
methodVisitor.visitJumpInsn(Opcodes.IFNULL, fail); methodVisitor.visitJumpInsn(Opcodes.IFNULL, fail);
} }
// if (!eventHandler.shouldCommit(duration) goto fail; // if (!eventConfiguration.shouldCommit(duration) goto fail;
getEventHandler(methodVisitor); getEventConfiguration(methodVisitor);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT); invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT);
methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
int index = 0;
for (SettingInfo si : settingInfos) { for (SettingInfo si : settingInfos) {
// if (!settingsMethod(eventHandler.settingX)) goto fail; // if (!settingsMethod(eventConfiguration.settingX)) goto fail;
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
if (untypedEventHandler) { if (untypedEventConfiguration) {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor()); methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_OBJECT_DESCRIPTOR);
} else { } else {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_EVENT_CONFIGURATION_DESCRIPTOR);
} }
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName); methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, TYPE_EVENT_CONFIGURATION.getInternalName());
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor()); methodVisitor.visitLdcInsn(index);
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName); invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING);
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false); methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.paramType().getInternalName());
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.paramType().getDescriptor() + ")Z", false);
methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
index++;
} }
// return true // return true
methodVisitor.visitInsn(Opcodes.ICONST_1); methodVisitor.visitInsn(Opcodes.ICONST_1);
@ -480,13 +672,32 @@ public final class EventInstrumentation {
}); });
} }
private void getEventWriter(MethodVisitor mv) {
mv.visitLdcInsn(EventWriterKey.getKey());
visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER_FACTORY, METHOD_GET_EVENT_WRITER_KEY);
}
private void getEventHandler(MethodVisitor methodVisitor) { private void visitMethod(final MethodVisitor mv, final int opcode, final Type type, final Method method) {
if (untypedEventHandler) { mv.visitMethodInsn(opcode, type.getInternalName(), method.getName(), method.getDescriptor(), false);
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor()); }
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, TYPE_EVENT_HANDLER.getInternalName());
private static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) {
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false);
}
private static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) {
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false);
}
private void invokeVirtual(MethodVisitor methodVisitor, Type type, Method method) {
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, type.getInternalName(), method.getName(), method.getDescriptor(), false);
}
private void getEventConfiguration(MethodVisitor methodVisitor) {
if (untypedEventConfiguration) {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_OBJECT_DESCRIPTOR);
} else { } else {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class)); methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_EVENT_CONFIGURATION_DESCRIPTOR);
} }
} }
@ -494,6 +705,9 @@ public final class EventInstrumentation {
updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT); updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT);
updateExistingWithReturnFalse(METHOD_IS_ENABLED); updateExistingWithReturnFalse(METHOD_IS_ENABLED);
updateExistingWithEmptyVoidMethod(METHOD_COMMIT); updateExistingWithEmptyVoidMethod(METHOD_COMMIT);
if (staticCommitMethod != null) {
updateExistingWithEmptyVoidMethod(staticCommitMethod);
}
updateExistingWithEmptyVoidMethod(METHOD_BEGIN); updateExistingWithEmptyVoidMethod(METHOD_BEGIN);
updateExistingWithEmptyVoidMethod(METHOD_END); updateExistingWithEmptyVoidMethod(METHOD_END);
} }
@ -533,33 +747,11 @@ public final class EventInstrumentation {
classNode.methods.add(index, newMethod); classNode.methods.add(index, newMethod);
} }
public static Method makeWriteMethod(List<FieldInfo> fields) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (FieldInfo v : fields) {
sb.append(v.fieldDescriptor);
}
sb.append(")V");
return new Method("write", sb.toString());
}
private String getInternalClassName() { private String getInternalClassName() {
return classNode.name; return classNode.name;
} }
public List<SettingInfo> getSettingInfos() {
return settingInfos;
}
public List<FieldInfo> getFieldInfos() {
return fieldInfos;
}
public String getEventName() { public String getEventName() {
return eventName; return eventName;
} }
public void setGuardHandler(boolean guardHandlerReference) {
this.guardHandlerReference = guardHandlerReference;
}
} }

View File

@ -0,0 +1,44 @@
/*
* 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. 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 jdk.jfr.internal.event.EventWriter;
// This class is not directly used but renamed to
// jdk.jfr.internal.event.EventWriterFactory and loaded dynamically
// when the first event class is bytecode instrumented.
// See JVMUpcalls and EventWriterKey::ensureEventWriterFactory()
public final class EventWriterFactoryRecipe {
private static final long KEY = EventWriterKey.getKey();
public static EventWriter getEventWriter(long key) {
if (key == KEY) {
EventWriter ew = JVM.getEventWriter();
return ew != null ? ew : JVM.newEventWriter();
}
EventWriterKey.block();
return null; // Can't reach here.
}
}

View File

@ -0,0 +1,123 @@
/*
* 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. 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.io.InputStream;
// Purpose of this class is NOT to create a cryptographically
// strong random number. but to quickly generate a value hard to guess
// without the need to load classes or have an impact on security
// related events, like SecureRandom::getAlgorithm("NativePRNGNonBlocking") does
public final class EventWriterKey {
private final static long KEY = createKey();
private static boolean loaded;
private static boolean logged;
public static long getKey() {
return KEY;
}
private static long createKey() {
JVM jvm = JVM.getJVM();
long r = mixMurmur64(System.identityHashCode(new Object()));
r = 31 * r + mixMurmur64(jvm.getPid().hashCode());
r = 31 * r + mixMurmur64(System.nanoTime());
r = 31 * r + mixMurmur64(Thread.currentThread().threadId());
r = 31 * r + mixMurmur64(System.currentTimeMillis());
r = 31 * r + mixMurmur64(jvm.getTypeId(JVM.class));
r = 31 * r + mixMurmur64(JVM.counterTime());
return mixMurmur64(r);
}
// Copied from jdk.internal.util.random.RandomSupport.mixMurmur64(long)
private static long mixMurmur64(long z) {
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
return z ^ (z >>> 33);
}
public static void ensureEventWriterFactory() {
if (loaded) {
return;
}
String name = "/jdk/jfr/internal/EventWriterFactoryRecipe.class";
try (InputStream is = EventWriterKey.class.getResourceAsStream(name)) {
byte[] bytes = is.readAllBytes();
bytes = replace(bytes,
"jdk/jfr/internal/EventWriterFactoryRecipe",
"jdk/jfr/internal/event/EventWriterFactory");
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
SecuritySupport.defineClass(c, bytes);
loaded = true;
} catch (Throwable e) {
throw new InternalError("Could not read bytecode for " + name, e);
}
Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "EventWriterFactory created");
}
// Starve the system of resources to prevent further attempts.
// Note, code that have the capability to invoke this method
// could spin in a loop anyway. Alternatives, such as System.exit(1),
// may provide caller with additional capabilities.
public static void block() {
// Making this field variable a local variable leads to CTW failure
logged = false;
while (true) {
try {
if (!logged) {
// Only log once to prevent flooding of log.
logged = true;
// Purposely don't call Thread::getName() since it can be overridden
Logger.log(LogTag.JFR, LogLevel.ERROR, "Malicious attempt to access JFR buffers. Stopping thread from further execution.");
}
} catch (Throwable t) {
// Ensure code can't break out and retry
}
}
}
private static byte[] replace(byte[] bytes, String match, String replacement) {
if (match.length() != replacement.length()) {
throw new IllegalArgumentException("Match must be same size as replacement");
}
for (int i = 0; i < bytes.length - match.length(); i++) {
if (match(bytes, i, match)) {
for (int j = 0; j < replacement.length(); j++) {
bytes[i + j] = (byte) replacement.charAt(j);
}
}
}
return bytes;
}
private static boolean match(byte[] bytes, int offset, String text) {
for (int i = 0; i < text.length(); i++) {
if (bytes[offset + i] != text.charAt(i)) {
return false;
}
}
return true;
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -27,10 +27,11 @@ package jdk.jfr.internal;
import jdk.internal.org.objectweb.asm.commons.Method; import jdk.internal.org.objectweb.asm.commons.Method;
import jdk.jfr.internal.EventInstrumentation.FieldInfo; import jdk.jfr.internal.EventInstrumentation.FieldInfo;
import jdk.jfr.internal.event.EventConfiguration;
public enum EventWriterMethod { public enum EventWriterMethod {
BEGIN_EVENT("(" + jdk.internal.org.objectweb.asm.Type.getType(PlatformEventType.class).getDescriptor() + ")Z", "???", "beginEvent"), BEGIN_EVENT("(" + jdk.internal.org.objectweb.asm.Type.getType(EventConfiguration.class).getDescriptor() + "J)Z", "???", "beginEvent"),
END_EVENT("()Z", "???", "endEvent"), END_EVENT("()Z", "???", "endEvent"),
PUT_BYTE("(B)V", "byte", "putByte"), PUT_BYTE("(B)V", "byte", "putByte"),
PUT_SHORT("(S)V", "short", "putShort"), PUT_SHORT("(S)V", "short", "putShort"),
@ -42,12 +43,12 @@ public enum EventWriterMethod {
PUT_BOOLEAN("(Z)V", "boolean", "putBoolean"), PUT_BOOLEAN("(Z)V", "boolean", "putBoolean"),
PUT_THREAD("(Ljava/lang/Thread;)V", Type.THREAD.getName(), "putThread"), PUT_THREAD("(Ljava/lang/Thread;)V", Type.THREAD.getName(), "putThread"),
PUT_CLASS("(Ljava/lang/Class;)V", Type.CLASS.getName(), "putClass"), PUT_CLASS("(Ljava/lang/Class;)V", Type.CLASS.getName(), "putClass"),
PUT_STRING("(Ljava/lang/String;Ljdk/jfr/internal/StringPool;)V", Type.STRING.getName(), "putString"), PUT_STRING("(Ljava/lang/String;)V", Type.STRING.getName(), "putString"),
PUT_EVENT_THREAD("()V", Type.THREAD.getName(), "putEventThread"), PUT_EVENT_THREAD("()V", Type.THREAD.getName(), "putEventThread"),
PUT_STACK_TRACE("()V", Type.TYPES_PREFIX + "StackTrace", "putStackTrace"); PUT_STACK_TRACE("()V", Type.TYPES_PREFIX + "StackTrace", "putStackTrace");
private final Method asmMethod; final Method asmMethod;
private final String typeDescriptor; final String typeDescriptor;
EventWriterMethod(String paramSignature, String typeName, String methodName) { EventWriterMethod(String paramSignature, String typeName, String methodName) {
this.typeDescriptor = ASMToolkit.getDescriptor(typeName); this.typeDescriptor = ASMToolkit.getDescriptor(typeName);
@ -68,14 +69,14 @@ public enum EventWriterMethod {
*/ */
public static EventWriterMethod lookupMethod(FieldInfo v) { public static EventWriterMethod lookupMethod(FieldInfo v) {
// event thread // event thread
if (v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD)) { if (v.fieldName().equals(EventInstrumentation.FIELD_EVENT_THREAD)) {
return EventWriterMethod.PUT_EVENT_THREAD; return EventWriterMethod.PUT_EVENT_THREAD;
} }
for (EventWriterMethod m : EventWriterMethod.values()) { for (EventWriterMethod m : EventWriterMethod.values()) {
if (v.fieldDescriptor.equals(m.typeDescriptor)) { if (v.fieldDescriptor().equals(m.typeDescriptor)) {
return m; return m;
} }
} }
throw new Error("Unknown type " + v.fieldDescriptor); throw new Error("Unknown type " + v.fieldDescriptor());
} }
} }

View File

@ -29,8 +29,8 @@ import java.util.List;
import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.jfr.Event; import jdk.jfr.Event;
import jdk.jfr.internal.EventWriter; import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventWriter;
/** /**
* Interface against the JVM. * Interface against the JVM.
@ -212,7 +212,7 @@ public final class JVM {
* *
* @throws IllegalStateException if wrong JVMTI phase. * @throws IllegalStateException if wrong JVMTI phase.
*/ */
public synchronized native void retransformClasses(Class<?>[] classes); public synchronized native void retransformClasses(Class<?>[] classes);
/** /**
* Enable event * Enable event
@ -561,12 +561,30 @@ public final class JVM {
public native void include(Thread thread); public native void include(Thread thread);
/** /**
* Test if a thread ius currently excluded from the jfr system. * Test if a thread is currently excluded from the jfr system.
* *
* @return is thread currently excluded * @return is thread currently excluded
*/ */
public native boolean isExcluded(Thread thread); public native boolean isExcluded(Thread thread);
/**
* Test if a class is excluded from the jfr system.
*
* @param eventClass the class, not {@code null}
*
* @return is class excluded
*/
public native boolean isExcluded(Class<? extends jdk.internal.event.Event> eventClass);
/**
* Test if a class is instrumented.
*
* @param eventClass the class, not {@code null}
*
* @return is class instrumented
*/
public native boolean isInstrumented(Class<? extends jdk.internal.event.Event> eventClass);
/** /**
* Get the start time in nanos from the header of the current chunk * Get the start time in nanos from the header of the current chunk
* *
@ -575,24 +593,24 @@ public final class JVM {
public native long getChunkStartNanos(); public native long getChunkStartNanos();
/** /**
* Stores an EventHandler to the eventHandler field of an event class. * Stores an EventConfiguration to the configuration field of an event class.
* *
* @param eventClass the class, not {@code null} * @param eventClass the class, not {@code null}
* *
* @param handler the handler, may be {@code null} * @param configuration the configuration, may be {@code null}
* *
* @return if the field could be set * @return if the field could be set
*/ */
public native boolean setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler); public native boolean setConfiguration(Class<? extends jdk.internal.event.Event> eventClass, EventConfiguration configuration);
/** /**
* Retrieves the EventHandler for an event class. * Retrieves the EventConfiguration for an event class.
* *
* @param eventClass the class, not {@code null} * @param eventClass the class, not {@code null}
* *
* @return the handler, may be {@code null} * @return the configuration, may be {@code null}
*/ */
public native Object getHandler(Class<? extends jdk.internal.event.Event> eventClass); public native Object getConfiguration(Class<? extends jdk.internal.event.Event> eventClass);
/** /**
* Returns the id for the Java types defined in metadata.xml. * Returns the id for the Java types defined in metadata.xml.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -26,9 +26,8 @@ package jdk.jfr.internal;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.internal.instrument.JDKEvents; import jdk.jfr.internal.instrument.JDKEvents;
/** /**
* All upcalls from the JVM should go through this class. * All upcalls from the JVM should go through this class.
* *
@ -40,9 +39,16 @@ final class JVMUpcalls {
* *
* @param traceId * @param traceId
* Id of the class * Id of the class
* @param dummy * @param dummy1
* (not used but needed since invoke infrastructure in native * not used, but act as padding so bytesForEagerInstrumentation and
* uses same signature bytesForEagerInstrumentation) * onRetransform can have identical method signatures, which simplifies the
* invoke machinery in native
*
* @param dummy2
* not used, but act as padding so bytesForEagerInstrumentation and
* onRetransform can have identical method signatures, which simplifies the
* invoke machinery in native
*
* @param clazz * @param clazz
* class being retransformed * class being retransformed
* @param oldBytes * @param oldBytes
@ -50,17 +56,19 @@ final class JVMUpcalls {
* @return byte code to use * @return byte code to use
* @throws Throwable * @throws Throwable
*/ */
static byte[] onRetransform(long traceId, boolean dummy, Class<?> clazz, byte[] oldBytes) throws Throwable { static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class<?> clazz, byte[] oldBytes) throws Throwable {
try { try {
if (jdk.internal.event.Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) { if (jdk.internal.event.Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
EventHandler handler = Utils.getHandler(clazz.asSubclass(jdk.internal.event.Event.class)); EventWriterKey.ensureEventWriterFactory();
if (handler == null) { EventConfiguration configuration = Utils.getConfiguration(clazz.asSubclass(jdk.internal.event.Event.class));
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request."); if (configuration == null) {
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event configuration found for " + clazz.getName() + ". Ignoring instrumentation request.");
// Probably triggered by some other agent // Probably triggered by some other agent
return oldBytes; return oldBytes;
} }
boolean bootClassLoader = clazz.getClassLoader() == null;
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform"); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform");
EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId); EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId, bootClassLoader, false);
byte[] bytes = ei.buildInstrumented(); byte[] bytes = ei.buildInstrumented();
ASMToolkit.logASM(clazz.getName(), bytes); ASMToolkit.logASM(clazz.getName(), bytes);
return bytes; return bytes;
@ -70,7 +78,6 @@ final class JVMUpcalls {
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName()); Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName());
} }
return oldBytes; return oldBytes;
} }
/** /**
@ -88,13 +95,13 @@ final class JVMUpcalls {
* @return byte code to use * @return byte code to use
* @throws Throwable * @throws Throwable
*/ */
static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrumentation, Class<?> superClass, byte[] oldBytes) throws Throwable { static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrumentation, boolean bootClassLoader, Class<?> superClass, byte[] oldBytes) throws Throwable {
if (JVMSupport.isNotAvailable()) { if (JVMSupport.isNotAvailable()) {
return oldBytes; return oldBytes;
} }
String eventName = "<Unknown>"; String eventName = "<Unknown>";
try { try {
EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId); EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId, bootClassLoader, true);
eventName = ei.getEventName(); eventName = ei.getEventName();
if (!forceInstrumentation) { if (!forceInstrumentation) {
// Assume we are recording // Assume we are recording
@ -107,15 +114,8 @@ final class JVMUpcalls {
return oldBytes; return oldBytes;
} }
} }
// Corner case when we are forced to generate bytecode. We can't reference the event EventWriterKey.ensureEventWriterFactory();
// handler in #isEnabled() before event class has been registered, so we add a
// guard against a null reference.
ei.setGuardHandler(true);
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load");
EventHandlerCreator eh = new EventHandlerCreator(traceId, ei.getSettingInfos(), ei.getFieldInfos());
// Handler class must be loaded before instrumented event class can
// be used
eh.makeEventHandlerClass();
byte[] bytes = ei.buildInstrumented(); byte[] bytes = ei.buildInstrumented();
ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes); ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes);
return bytes; return bytes;

View File

@ -25,12 +25,11 @@
package jdk.jfr.internal; package jdk.jfr.internal;
import static jdk.jfr.internal.LogLevel.DEBUG;
import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -39,6 +38,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import jdk.jfr.AnnotationElement; import jdk.jfr.AnnotationElement;
import jdk.jfr.Event; import jdk.jfr.Event;
@ -47,9 +47,11 @@ import jdk.jfr.Period;
import jdk.jfr.StackTrace; import jdk.jfr.StackTrace;
import jdk.jfr.Threshold; import jdk.jfr.Threshold;
import jdk.jfr.ValueDescriptor; import jdk.jfr.ValueDescriptor;
import jdk.jfr.SettingControl;
import jdk.jfr.internal.EventInstrumentation.SettingInfo;
import jdk.jfr.internal.RequestEngine.RequestHook; import jdk.jfr.internal.RequestEngine.RequestHook;
import jdk.jfr.internal.consumer.RepositoryFiles; import jdk.jfr.internal.consumer.RepositoryFiles;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventConfiguration;
public final class MetadataRepository { public final class MetadataRepository {
@ -61,10 +63,10 @@ public final class MetadataRepository {
private final TypeLibrary typeLibrary = TypeLibrary.getInstance(); private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
private final SettingsManager settingsManager = new SettingsManager(); private final SettingsManager settingsManager = new SettingsManager();
private final Map<String, Class<? extends Event>> mirrors = new HashMap<>(); private final Map<String, Class<? extends Event>> mirrors = new HashMap<>();
private Constructor<EventConfiguration> cachedEventConfigurationConstructor;
private boolean staleMetadata = true; private boolean staleMetadata = true;
private boolean unregistered; private boolean unregistered;
private long lastUnloaded = -1; private long lastUnloaded = -1;
private Instant outputChange;
public MetadataRepository() { public MetadataRepository() {
initializeJVMEventTypes(); initializeJVMEventTypes();
@ -100,11 +102,11 @@ public final class MetadataRepository {
} }
public synchronized List<EventType> getRegisteredEventTypes() { public synchronized List<EventType> getRegisteredEventTypes() {
List<EventHandler> handlers = getEventHandlers(); List<EventConfiguration> configurations = getEventConfigurations();
List<EventType> eventTypes = new ArrayList<>(handlers.size() + nativeEventTypes.size()); List<EventType> eventTypes = new ArrayList<>(configurations.size() + nativeEventTypes.size());
for (EventHandler h : handlers) { for (EventConfiguration ec : configurations) {
if (h.isRegistered()) { if (ec.isRegistered()) {
eventTypes.add(h.getEventType()); eventTypes.add(ec.getEventType());
} }
} }
for (EventType t : nativeEventTypes) { for (EventType t : nativeEventTypes) {
@ -116,18 +118,18 @@ public final class MetadataRepository {
} }
public synchronized EventType getEventType(Class<? extends jdk.internal.event.Event> eventClass) { public synchronized EventType getEventType(Class<? extends jdk.internal.event.Event> eventClass) {
EventHandler h = getHandler(eventClass, false); EventConfiguration ec = getConfiguration(eventClass, false);
if (h != null && h.isRegistered()) { if (ec != null && ec.isRegistered()) {
return h.getEventType(); return ec.getEventType();
} }
throw new IllegalStateException("Event class " + eventClass.getName() + " is not registered"); throw new IllegalStateException("Event class " + eventClass.getName() + " is not registered");
} }
public synchronized void unregister(Class<? extends Event> eventClass) { public synchronized void unregister(Class<? extends Event> eventClass) {
Utils.checkRegisterPermission(); Utils.checkRegisterPermission();
EventHandler handler = getHandler(eventClass, false); EventConfiguration configuration = getConfiguration(eventClass, false);
if (handler != null) { if (configuration != null) {
handler.setRegistered(false); configuration.getPlatformEventType().setRegistered(false);
} }
// never registered, ignore call // never registered, ignore call
} }
@ -137,23 +139,31 @@ public final class MetadataRepository {
public synchronized EventType register(Class<? extends jdk.internal.event.Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) { public synchronized EventType register(Class<? extends jdk.internal.event.Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
Utils.checkRegisterPermission(); Utils.checkRegisterPermission();
EventHandler handler = getHandler(eventClass, true); if (jvm.isExcluded(eventClass)) {
if (handler == null) { // Event classes are marked as excluded during class load
// if they override methods in the jdk.jfr.Event class, i.e. commit().
// An excluded class lacks a configuration field and can't be used by JFR.
// The Event::commit() is marked as final, so javac won't
// compile an override, but it can be constructed by other means.
throw new IllegalArgumentException("Must not override methods declared in jdk.jfr.Event");
}
EventConfiguration configuration = getConfiguration(eventClass, true);
if (configuration == null) {
if (eventClass.getAnnotation(MirrorEvent.class) != null) { if (eventClass.getAnnotation(MirrorEvent.class) != null) {
// don't register mirrors // Don't register mirror classes.
return null; return null;
} }
PlatformEventType pe = findMirrorType(eventClass); PlatformEventType pe = findMirrorType(eventClass);
handler = makeHandler(eventClass, pe, dynamicAnnotations, dynamicFields); configuration = makeConfiguration(eventClass, pe, dynamicAnnotations, dynamicFields);
} }
handler.setRegistered(true); configuration.getPlatformEventType().setRegistered(true);
typeLibrary.addType(handler.getPlatformEventType()); typeLibrary.addType(configuration.getPlatformEventType());
if (jvm.isRecording()) { if (jvm.isRecording()) {
settingsManager.setEventControl(handler.getEventControl()); settingsManager.setEventControl(configuration.getEventControl());
settingsManager.updateRetransform(Collections.singletonList((eventClass))); settingsManager.updateRetransform(Collections.singletonList((eventClass)));
} }
setStaleMetadata(); setStaleMetadata();
return handler.getEventType(); return configuration.getEventType();
} }
private PlatformEventType findMirrorType(Class<? extends jdk.internal.event.Event> eventClass) throws InternalError { private PlatformEventType findMirrorType(Class<? extends jdk.internal.event.Event> eventClass) throws InternalError {
@ -170,40 +180,52 @@ public final class MetadataRepository {
return et; return et;
} }
private EventHandler getHandler(Class<? extends jdk.internal.event.Event> eventClass, boolean ensureInitialized) { private EventConfiguration getConfiguration(Class<? extends jdk.internal.event.Event> eventClass, boolean ensureInitialized) {
Utils.ensureValidEventSubclass(eventClass); Utils.ensureValidEventSubclass(eventClass);
SecuritySupport.makeVisibleToJFR(eventClass); SecuritySupport.makeVisibleToJFR(eventClass);
if (ensureInitialized) { if (ensureInitialized) {
Utils.ensureInitialized(eventClass); Utils.ensureInitialized(eventClass);
} }
return Utils.getHandler(eventClass); return Utils.getConfiguration(eventClass);
} }
private EventHandler makeHandler(Class<? extends jdk.internal.event.Event> eventClass, PlatformEventType pEventType, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) throws InternalError { private EventConfiguration newEventConfiguration(EventType eventType, EventControl ec, SettingControl[] settings) {
SecuritySupport.addHandlerExport(eventClass); try {
if (cachedEventConfigurationConstructor == null) {
var argClasses = new Class<?>[] { EventType.class, EventControl.class, SettingControl[].class };
Constructor<EventConfiguration> c = EventConfiguration.class.getDeclaredConstructor(argClasses);
SecuritySupport.setAccessible(c);
cachedEventConfigurationConstructor = c;
}
return cachedEventConfigurationConstructor.newInstance(eventType, ec, settings);
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new InternalError(e);
}
}
private EventConfiguration makeConfiguration(Class<? extends jdk.internal.event.Event> eventClass, PlatformEventType pEventType, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) throws InternalError {
SecuritySupport.addInternalEventExport(eventClass);
if (pEventType == null) { if (pEventType == null) {
pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields); pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields);
} }
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType); EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
EventControl ec = new EventControl(pEventType, eventClass); EventControl ec = new EventControl(pEventType, eventClass);
Class<? extends EventHandler> handlerClass = null; List<SettingInfo> settingInfos = ec.getSettingInfos();
try { SettingControl[] settings = new SettingControl[settingInfos.size()];
String eventHandlerName = EventHandlerCreator.makeEventHandlerName(eventType.getId()); int index = 0;
handlerClass = Class.forName(eventHandlerName, false, Event.class.getClassLoader()).asSubclass(EventHandler.class); for (var settingInfo : settingInfos) {
// Created eagerly on class load, tag as instrumented settings[index++] = settingInfo.settingControl();
pEventType.setInstrumented(); }
Logger.log(JFR_SYSTEM, DEBUG, "Found existing event handler for " + eventType.getName()); EventConfiguration configuration = newEventConfiguration(eventType, ec, settings);
} catch (ClassNotFoundException cne) { PlatformEventType pe = configuration.getPlatformEventType();
EventHandlerCreator ehc = new EventHandlerCreator(eventType.getId(), ec.getSettingInfos(), eventType, eventClass); pe.setRegistered(true);
handlerClass = ehc.makeEventHandlerClass(); if (jvm.isInstrumented(eventClass)) {
Logger.log(LogTag.JFR_SYSTEM, DEBUG, "Created event handler for " + eventType.getName()); pe.setInstrumented();
} }
EventHandler handler = EventHandlerCreator.instantiateEventHandler(handlerClass, true, eventType, ec); Utils.setConfiguration(eventClass, configuration);
Utils.setHandler(eventClass, handler); return configuration;
return handler;
} }
public synchronized void setSettings(List<Map<String, String>> list) { public synchronized void setSettings(List<Map<String, String>> list) {
settingsManager.setSettings(list); settingsManager.setSettings(list);
} }
@ -219,7 +241,7 @@ public final class MetadataRepository {
ArrayList<EventControl> controls = new ArrayList<>(eventClasses.size() + nativeControls.size()); ArrayList<EventControl> controls = new ArrayList<>(eventClasses.size() + nativeControls.size());
controls.addAll(nativeControls); controls.addAll(nativeControls);
for (Class<? extends jdk.internal.event.Event> clazz : eventClasses) { for (Class<? extends jdk.internal.event.Event> clazz : eventClasses) {
EventHandler eh = Utils.getHandler(clazz); EventConfiguration eh = Utils.getConfiguration(clazz);
if (eh != null) { if (eh != null) {
controls.add(eh.getEventControl()); controls.add(eh.getEventControl());
} }
@ -232,16 +254,16 @@ public final class MetadataRepository {
staleMetadata = false; staleMetadata = false;
} }
private static List<EventHandler> getEventHandlers() { private static List<EventConfiguration> getEventConfigurations() {
List<Class<? extends jdk.internal.event.Event>> allEventClasses = jvm.getAllEventClasses(); List<Class<? extends jdk.internal.event.Event>> allEventClasses = jvm.getAllEventClasses();
List<EventHandler> eventHandlers = new ArrayList<>(allEventClasses.size()); List<EventConfiguration> eventConfigurations = new ArrayList<>(allEventClasses.size());
for (Class<? extends jdk.internal.event.Event> clazz : allEventClasses) { for (Class<? extends jdk.internal.event.Event> clazz : allEventClasses) {
EventHandler eh = Utils.getHandler(clazz); EventConfiguration ec = Utils.getConfiguration(clazz);
if (eh != null) { if (ec != null) {
eventHandlers.add(eh); eventConfigurations.add(ec);
} }
} }
return eventHandlers; return eventConfigurations;
} }
private byte[] getBinaryRepresentation() { private byte[] getBinaryRepresentation() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, 2022, 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
@ -85,7 +85,7 @@ public final class PlatformEventType extends Type {
return false; return false;
} }
private static boolean isUsingHandler(String name) { private static boolean isUsingConfiguration(String name) {
switch (name) { switch (name) {
case Type.EVENT_NAME_PREFIX + "SocketRead" : case Type.EVENT_NAME_PREFIX + "SocketRead" :
case Type.EVENT_NAME_PREFIX + "SocketWrite" : case Type.EVENT_NAME_PREFIX + "SocketWrite" :
@ -102,11 +102,11 @@ public final class PlatformEventType extends Type {
if (isExceptionEvent(name)) { if (isExceptionEvent(name)) {
return 4; return 4;
} }
if (isUsingHandler(name)) { if (isUsingConfiguration(name)) {
return 3; return 3;
} }
} }
return 4; return 3;
} }
public void add(SettingDescriptor settingDescriptor) { public void add(SettingDescriptor settingDescriptor) {

View File

@ -49,10 +49,12 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime; import java.nio.file.attribute.FileTime;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.NoSuchAlgorithmException;
import java.security.Permission; import java.security.Permission;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -82,7 +84,7 @@ public final class SecuritySupport {
static { static {
// ensure module java.base can read module jdk.jfr as early as possible // ensure module java.base can read module jdk.jfr as early as possible
addReadEdge(Object.class); addReadEdge(Object.class);
addHandlerExport(Object.class); addInternalEventExport(Object.class);
addEventsExport(Object.class); addEventsExport(Object.class);
addInstrumentExport(Object.class); addInstrumentExport(Object.class);
} }
@ -290,11 +292,11 @@ public final class SecuritySupport {
} }
/** /**
* Adds a qualified export of the internal.jdk.jfr.internal.handlers package * Adds a qualified export of the internal.jdk.jfr.internal.event package
* (for EventHandler) * (for EventConfiguration and EventWriter)
*/ */
static void addHandlerExport(Class<?> clazz) { static void addInternalEventExport(Class<?> clazz) {
Modules.addExports(JFR_MODULE, Utils.HANDLERS_PACKAGE_NAME, clazz.getModule()); Modules.addExports(JFR_MODULE, Utils.EVENT_PACKAGE_NAME, clazz.getModule());
} }
static void addEventsExport(Class<?> clazz) { static void addEventsExport(Class<?> clazz) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -37,7 +37,7 @@ import java.util.Set;
import java.util.StringJoiner; import java.util.StringJoiner;
import jdk.jfr.internal.EventControl.NamedControl; import jdk.jfr.internal.EventControl.NamedControl;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventConfiguration;
final class SettingsManager { final class SettingsManager {
@ -154,9 +154,9 @@ final class SettingsManager {
public void updateRetransform(List<Class<? extends jdk.internal.event.Event>> eventClasses) { public void updateRetransform(List<Class<? extends jdk.internal.event.Event>> eventClasses) {
List<Class<?>> classes = new ArrayList<>(); List<Class<?>> classes = new ArrayList<>();
for(Class<? extends jdk.internal.event.Event> eventClass: eventClasses) { for(Class<? extends jdk.internal.event.Event> eventClass: eventClasses) {
EventHandler eh = Utils.getHandler(eventClass); EventConfiguration ec = Utils.getConfiguration(eventClass);
if (eh != null ) { if (ec != null ) {
PlatformEventType eventType = eh.getPlatformEventType(); PlatformEventType eventType = ec.getPlatformEventType();
if (eventType.isMarkedForInstrumentation()) { if (eventType.isMarkedForInstrumentation()) {
classes.add(eventClass); classes.add(eventClass);
eventType.markForInstrumentation(false); eventType.markForInstrumentation(false);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2022, 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
@ -28,16 +28,16 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
public final class StringPool { public final class StringPool {
static final int MIN_LIMIT = 16; public static final int MIN_LIMIT = 16;
static final int MAX_LIMIT = 128; /* 0 MAX means disabled */ public static final int MAX_LIMIT = 128; /* 0 MAX means disabled */
private static final long DO_NOT_POOL = -1; private static final long DO_NOT_POOL = -1;
private static final SimpleStringIdPool sp = new SimpleStringIdPool(); private static final SimpleStringIdPool sp = new SimpleStringIdPool();
static long addString(String s) { public static long addString(String s) {
return sp.addString(s); return sp.addString(s);
} }
static void reset() { public static void reset() {
sp.reset(); sp.reset();
} }

View File

@ -62,7 +62,7 @@ import jdk.jfr.Event;
import jdk.jfr.FlightRecorderPermission; import jdk.jfr.FlightRecorderPermission;
import jdk.jfr.Recording; import jdk.jfr.Recording;
import jdk.jfr.RecordingState; import jdk.jfr.RecordingState;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventConfiguration;
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;
@ -74,7 +74,7 @@ public final class Utils {
private static final String OFF = "off"; private static final String OFF = "off";
public static final String EVENTS_PACKAGE_NAME = "jdk.jfr.events"; public static final String EVENTS_PACKAGE_NAME = "jdk.jfr.events";
public static final String INSTRUMENT_PACKAGE_NAME = "jdk.jfr.internal.instrument"; public static final String INSTRUMENT_PACKAGE_NAME = "jdk.jfr.internal.instrument";
public static final String HANDLERS_PACKAGE_NAME = "jdk.jfr.internal.handlers"; public static final String EVENT_PACKAGE_NAME = "jdk.jfr.internal.event";
public static final String REGISTER_EVENT = "registerEvent"; public static final String REGISTER_EVENT = "registerEvent";
public static final String ACCESS_FLIGHT_RECORDER = "accessFlightRecorder"; public static final String ACCESS_FLIGHT_RECORDER = "accessFlightRecorder";
private static final String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk."; private static final String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk.";
@ -445,19 +445,19 @@ public final class Utils {
return (long) (nanos * JVM.getJVM().getTimeConversionFactor()); return (long) (nanos * JVM.getJVM().getTimeConversionFactor());
} }
public static synchronized EventHandler getHandler(Class<? extends jdk.internal.event.Event> eventClass) { public static synchronized EventConfiguration getConfiguration(Class<? extends jdk.internal.event.Event> eventClass) {
Utils.ensureValidEventSubclass(eventClass); Utils.ensureValidEventSubclass(eventClass);
Object handler = JVM.getJVM().getHandler(eventClass); Object configuration = JVM.getJVM().getConfiguration(eventClass);
if (handler == null || handler instanceof EventHandler) { if (configuration == null || configuration instanceof EventConfiguration) {
return (EventHandler) handler; return (EventConfiguration) configuration;
} }
throw new InternalError("Could not access event handler"); throw new InternalError("Could not get configuration object on event class " + eventClass.getName());
} }
static synchronized void setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler) { static synchronized void setConfiguration(Class<? extends jdk.internal.event.Event> eventClass, EventConfiguration configuration) {
Utils.ensureValidEventSubclass(eventClass); Utils.ensureValidEventSubclass(eventClass);
if (!JVM.getJVM().setHandler(eventClass, handler)) { if (!JVM.getJVM().setConfiguration(eventClass, configuration)) {
throw new InternalError("Could not set event handler"); throw new InternalError("Could not set configuration object on event class " + eventClass.getName());
} }
} }
@ -522,6 +522,7 @@ public final class Utils {
SAVE_GENERATED = SecuritySupport.getBooleanProperty("jfr.save.generated.asm"); SAVE_GENERATED = SecuritySupport.getBooleanProperty("jfr.save.generated.asm");
} }
if (SAVE_GENERATED) { if (SAVE_GENERATED) {
className = className.substring(className.lastIndexOf("/") + 1, className.length());
try { try {
try (FileOutputStream fos = new FileOutputStream(className + ".class")) { try (FileOutputStream fos = new FileOutputStream(className + ".class")) {
fos.write(bytes); fos.write(bytes);

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2016, 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. 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.event;
import jdk.jfr.EventType;
import jdk.jfr.internal.EventControl;
import jdk.jfr.internal.JVM;
import jdk.jfr.internal.PlatformEventType;
import jdk.jfr.internal.PrivateAccess;
import jdk.jfr.SettingControl;
// Users should not be able to subclass or instantiate for security reasons.
public final class EventConfiguration {
private final PlatformEventType platformEventType;
private final EventType eventType;
private final EventControl eventControl;
private final SettingControl[] settings;
// Private constructor so user code can't instantiate
private EventConfiguration(EventType eventType, EventControl eventControl, SettingControl[] settings) {
this.eventType = eventType;
this.platformEventType = PrivateAccess.getInstance().getPlatformEventType(eventType);
this.eventControl = eventControl;
this.settings = settings;
}
// Class jdk.jfr.internal.PlatformEventType is not
// accessible from event class by design
public PlatformEventType getPlatformEventType() {
return platformEventType;
}
// Class jdk.jfr.internal.EventControl is not
// accessible from event class by design
public EventControl getEventControl() {
return eventControl;
}
// Accessed by generated code in event class
public boolean shouldCommit(long duration) {
return isEnabled() && duration >= platformEventType.getThresholdTicks();
}
// Accessed by generated code in event class
public SettingControl getSetting(int index) {
return settings[index];
}
// Accessed by generated code in event class
public boolean isEnabled() {
return platformEventType.isCommittable();
}
// Accessed by generated code in event class
public EventType getEventType() {
return eventType;
}
// Not really part of the configuration, but the method
// needs to be somewhere the event class can access,
// but not part of the public API.
public static long timestamp() {
return JVM.counterTime();
}
// Accessed by generated code in event class
public static long duration(long startTime) {
if (startTime == 0) {
// User forgot to invoke begin, or instrumentation was
// added after the user invoked begin.
// Returning 0 will make it an instant event
return 0;
}
return timestamp() - startTime;
}
public boolean isRegistered() {
return platformEventType.isRegistered();
}
public long getId() {
return eventType.getId();
}
}

View File

@ -23,17 +23,36 @@
* questions. * questions.
*/ */
package jdk.jfr.internal; package jdk.jfr.internal.event;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
import jdk.jfr.internal.Bits;
import jdk.jfr.internal.EventWriterKey;
import jdk.jfr.internal.StringPool;
import jdk.jfr.internal.JVM;
import jdk.jfr.internal.PlatformEventType;
import jdk.jfr.internal.consumer.StringParser; import jdk.jfr.internal.consumer.StringParser;
/** // User code should not be able to get access to an EventWriter instance as it
* Class must reside in a package with package restriction. // would allow it to write arbitrary data into buffers, potentially from
* // different threads.
* Users should not have direct access to underlying memory. //
* // This is prevented in three ways:
*/ //
// 1. For code to access the jdk.jfr.internal.event package
// at least one event class (for a particular module) must be
// registered having FlightRecorderPermission("registerEvent").
//
// 2. The EventWriter EventWriterFactory::getEventWriter(long) method can only be linked from
// the UserEvent::commit() method instrumented by JFR. This is ensured by the JVM.
// (The EventWriterFactory class is dynamically generated before the first event
// is instrumented. See EventWriterFactoryRecipe)
//
// 3. Steps 1 and 2 are sufficient to make it fully secure, with or without a Security
// Manager, but as an additional measure, the method EventWriterFactory::getEventWriter(long)
// requires the caller to provide a key that is hard to guess. The key is generated
// into the bytecode of the method invoking getEventWriter(long).
//
public final class EventWriter { public final class EventWriter {
// Event may not exceed size for a padded integer // Event may not exceed size for a padded integer
@ -55,9 +74,9 @@ public final class EventWriter {
private boolean flushOnEnd; private boolean flushOnEnd;
private boolean largeSize = false; private boolean largeSize = false;
public static EventWriter getEventWriter() { // User code must not be able to instantiate
EventWriter ew = JVM.getEventWriter(); private EventWriter() {
return ew != null ? ew : JVM.newEventWriter(); threadID = 0;
} }
public void putBoolean(boolean i) { public void putBoolean(boolean i) {
@ -117,7 +136,7 @@ public final class EventWriter {
} }
} }
public void putString(String s, StringPool pool) { public void putString(String s) {
if (s == null) { if (s == null) {
putByte(StringParser.Encoding.NULL.byteValue()); putByte(StringParser.Encoding.NULL.byteValue());
return; return;
@ -237,12 +256,19 @@ public final class EventWriter {
return JVM.flush(this, usedSize, requestedSize); return JVM.flush(this, usedSize, requestedSize);
} }
public boolean beginEvent(PlatformEventType eventType) {
public boolean beginEvent(EventConfiguration configuration, long typeId) {
// Malicious code could take the EventConfiguration object from one
// event class field and assign it to another. This check makes sure
// the event type matches what was added by instrumentation.
if (configuration.getId() != typeId) {
EventWriterKey.block();
}
if (excluded) { if (excluded) {
// thread is excluded from writing events // thread is excluded from writing events
return false; return false;
} }
this.eventType = eventType; this.eventType = configuration.getPlatformEventType();
reserveEventSizeField(); reserveEventSizeField();
putLong(eventType.getId()); putLong(eventType.getId());
return true; return true;

View File

@ -1,145 +0,0 @@
/*
* Copyright (c) 2016, 2020, 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.handlers;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import jdk.jfr.EventType;
import jdk.jfr.internal.EventControl;
import jdk.jfr.internal.JVM;
import jdk.jfr.internal.PlatformEventType;
import jdk.jfr.internal.PrivateAccess;
import jdk.jfr.internal.StringPool;
// Users should not be subclass for security reasons.
public abstract class EventHandler {
// Accessed by generated sub class
protected final PlatformEventType platformEventType;
private final EventType eventType;
private final EventControl eventControl;
// Accessed by generated sub class
EventHandler(boolean registered, EventType eventType, EventControl eventControl) {
this.eventType = eventType;
this.platformEventType = PrivateAccess.getInstance().getPlatformEventType(eventType);
this.eventControl = eventControl;
platformEventType.setRegistered(registered);
}
protected final StringPool createStringFieldWriter() {
return new StringPool();
}
// Accessed by generated code in event class
public final boolean shouldCommit(long duration) {
return isEnabled() && duration >= platformEventType.getThresholdTicks();
}
// Accessed by generated code in event class
// Accessed by generated sub class
public final boolean isEnabled() {
return platformEventType.isCommittable();
}
public final EventType getEventType() {
return eventType;
}
public final PlatformEventType getPlatformEventType() {
return platformEventType;
}
public final EventControl getEventControl() {
return eventControl;
}
public static long timestamp() {
return JVM.counterTime();
}
public static long duration(long startTime) {
if (startTime == 0) {
// User forgot to invoke begin, or instrumentation was
// added after the user invoked begin.
// Returning 0 will make it an instant event
return 0;
}
return timestamp() - startTime;
}
// Prevent a malicious user from instantiating a generated event handlers.
@Override
public final Object clone() throws java.lang.CloneNotSupportedException {
throw new CloneNotSupportedException();
}
private final void writeObject(ObjectOutputStream out) throws IOException {
throw new IOException("Object cannot be serialized");
}
private final void readObject(ObjectInputStream in) throws IOException {
throw new IOException("Class cannot be deserialized");
}
public boolean isRegistered() {
return platformEventType.isRegistered();
}
public boolean setRegistered(boolean registered) {
return platformEventType.setRegistered(registered);
}
public void write(long start, long duration, String host, String address, int port, long timeout, long bytesRead, boolean endOfSTream) {
throwError("SocketReadEvent");
}
public void write(long start, long duration, String host, String address, int port, long bytesWritten) {
throwError("SocketWriteEvent");
}
public void write(long start, long duration, String path, boolean metadata) {
throwError("FileForceEvent");
}
public void write(long start, long duration, String path, long bytesRead, boolean endOfFile) {
throwError("FileReadEvent");
}
public void write(long start, long duration, String path, long bytesWritten) {
throwError("FileWriteEvent");
}
public void write(long start, long duration, String path, Class<?> exceptionClass) {
throwError("ExceptionThrownEvent or ErrorThrownEvent");
}
private void throwError(String classes) {
throw new InternalError("Method parameters don't match fields in class " + classes);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -28,8 +28,11 @@ package jdk.jfr.internal.instrument;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import jdk.jfr.events.Handlers; import jdk.jfr.events.FileForceEvent;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.FileReadEvent;
import jdk.jfr.events.FileWriteEvent;
import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.events.EventConfigurations;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -45,19 +48,19 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void force(boolean metaData) throws IOException { public void force(boolean metaData) throws IOException {
EventHandler handler = Handlers.FILE_FORCE; EventConfiguration eventConfiguration = EventConfigurations.FILE_FORCE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
force(metaData); force(metaData);
return; return;
} }
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
force(metaData); force(metaData);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, metaData); FileForceEvent.commit(start, duration, path, metaData);
} }
} }
} }
@ -65,22 +68,22 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(ByteBuffer dst) throws IOException { public int read(ByteBuffer dst) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(dst); return read(dst);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(dst); bytesRead = read(dst);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }
@ -90,22 +93,22 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(ByteBuffer dst, long position) throws IOException { public int read(ByteBuffer dst, long position) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(dst, position); return read(dst, position);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(dst, position); bytesRead = read(dst, position);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }
@ -115,22 +118,22 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(dsts, offset, length); return read(dsts, offset, length);
} }
long bytesRead = 0; long bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(dsts, offset, length); bytesRead = read(dsts, offset, length);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }
@ -140,20 +143,20 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int write(ByteBuffer src) throws IOException { public int write(ByteBuffer src) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return write(src); return write(src);
} }
int bytesWritten = 0; int bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesWritten = write(src); bytesWritten = write(src);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten > 0 ? bytesWritten : 0; long bytes = bytesWritten > 0 ? bytesWritten : 0;
handler.write(start, duration, path, bytes); FileWriteEvent.commit(start, duration, path, bytes);
} }
} }
return bytesWritten; return bytesWritten;
@ -162,21 +165,21 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int write(ByteBuffer src, long position) throws IOException { public int write(ByteBuffer src, long position) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return write(src, position); return write(src, position);
} }
int bytesWritten = 0; int bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesWritten = write(src, position); bytesWritten = write(src, position);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten > 0 ? bytesWritten : 0; long bytes = bytesWritten > 0 ? bytesWritten : 0;
handler.write(start, duration, path, bytes); FileWriteEvent.commit(start, duration, path, bytes);
} }
} }
return bytesWritten; return bytesWritten;
@ -185,20 +188,20 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return write(srcs, offset, length); return write(srcs, offset, length);
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesWritten = write(srcs, offset, length); bytesWritten = write(srcs, offset, length);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten > 0 ? bytesWritten : 0; long bytes = bytesWritten > 0 ? bytesWritten : 0;
handler.write(start, duration, path, bytes); FileWriteEvent.commit(start, duration, path, bytes);
} }
} }
return bytesWritten; return bytesWritten;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -27,8 +27,9 @@ package jdk.jfr.internal.instrument;
import java.io.IOException; import java.io.IOException;
import jdk.jfr.events.Handlers; import jdk.jfr.events.EventConfigurations;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.FileReadEvent;
import jdk.jfr.internal.event.EventConfiguration;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -44,8 +45,8 @@ final class FileInputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read() throws IOException { public int read() throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(); return read();
} }
int result = 0; int result = 0;
@ -53,7 +54,7 @@ final class FileInputStreamInstrumentor {
long bytesRead = 0; long bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
result = read(); result = read();
if (result < 0) { if (result < 0) {
endOfFile = true; endOfFile = true;
@ -61,9 +62,9 @@ final class FileInputStreamInstrumentor {
bytesRead = 1; bytesRead = 1;
} }
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesRead, endOfFile); FileReadEvent.commit(start, duration, path, bytesRead, endOfFile);
} }
} }
return result; return result;
@ -72,22 +73,22 @@ final class FileInputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(byte b[]) throws IOException { public int read(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(b); return read(b);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(b); bytesRead = read(b);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }
@ -97,22 +98,22 @@ final class FileInputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(byte b[], int off, int len) throws IOException { public int read(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(b, off, len); return read(b, off, len);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(b, off, len); bytesRead = read(b, off, len);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -27,8 +27,9 @@ package jdk.jfr.internal.instrument;
import java.io.IOException; import java.io.IOException;
import jdk.jfr.events.Handlers; import jdk.jfr.events.FileWriteEvent;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.events.EventConfigurations;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -44,21 +45,21 @@ final class FileOutputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(int b) throws IOException { public void write(int b) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b); write(b);
return; return;
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b); write(b);
bytesWritten = 1; bytesWritten = 1;
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten); FileWriteEvent.commit(start, duration, path, bytesWritten);
} }
} }
} }
@ -66,21 +67,21 @@ final class FileOutputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(byte b[]) throws IOException { public void write(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b); write(b);
return; return;
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b); write(b);
bytesWritten = b.length; bytesWritten = b.length;
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten); FileWriteEvent.commit(start, duration, path, bytesWritten);
} }
} }
} }
@ -88,21 +89,21 @@ final class FileOutputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(byte b[], int off, int len) throws IOException { public void write(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b, off, len); write(b, off, len);
return; return;
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b, off, len); write(b, off, len);
bytesWritten = len; bytesWritten = len;
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten); FileWriteEvent.commit(start, duration, path, bytesWritten);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -27,8 +27,10 @@ package jdk.jfr.internal.instrument;
import java.io.IOException; import java.io.IOException;
import jdk.jfr.events.Handlers; import jdk.jfr.events.FileReadEvent;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.FileWriteEvent;
import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.events.EventConfigurations;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -44,8 +46,8 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read() throws IOException { public int read() throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(); return read();
} }
int result = 0; int result = 0;
@ -53,7 +55,7 @@ final class RandomAccessFileInstrumentor {
boolean endOfFile = false; boolean endOfFile = false;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
result = read(); result = read();
if (result < 0) { if (result < 0) {
endOfFile = true; endOfFile = true;
@ -61,9 +63,9 @@ final class RandomAccessFileInstrumentor {
bytesRead = 1; bytesRead = 1;
} }
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesRead, endOfFile); FileReadEvent.commit(start, duration, path, bytesRead, endOfFile);
} }
} }
return result; return result;
@ -72,22 +74,22 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(byte b[]) throws IOException { public int read(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(b); return read(b);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(b); bytesRead = read(b);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }
@ -97,22 +99,22 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(byte b[], int off, int len) throws IOException { public int read(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_READ; EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(b, off, len); return read(b, off, len);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(b, off, len); bytesRead = read(b, off, len);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true); FileReadEvent.commit(start, duration, path, 0L, true);
} else { } else {
handler.write(start, duration, path, bytesRead, false); FileReadEvent.commit(start, duration, path, bytesRead, false);
} }
} }
} }
@ -122,21 +124,21 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(int b) throws IOException { public void write(int b) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b); write(b);
return; return;
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b); write(b);
bytesWritten = 1; bytesWritten = 1;
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten); FileWriteEvent.commit(start, duration, path, bytesWritten);
} }
} }
} }
@ -144,21 +146,21 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(byte b[]) throws IOException { public void write(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b); write(b);
return; return;
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b); write(b);
bytesWritten = b.length; bytesWritten = b.length;
} finally { } finally {
long duration = EventHandler.timestamp(); long duration = EventConfiguration.timestamp();
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten); FileWriteEvent.commit(start, duration, path, bytesWritten);
} }
} }
} }
@ -166,21 +168,21 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(byte b[], int off, int len) throws IOException { public void write(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_WRITE; EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b, off, len); write(b, off, len);
return; return;
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b, off, len); write(b, off, len);
bytesWritten = len; bytesWritten = len;
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten); FileWriteEvent.commit(start, duration, path, bytesWritten);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -30,8 +30,10 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.UnixDomainSocketAddress; import java.net.UnixDomainSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import jdk.jfr.events.Handlers; import jdk.jfr.events.EventConfigurations;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.SocketReadEvent;
import jdk.jfr.events.SocketWriteEvent;
import jdk.jfr.internal.event.EventConfiguration;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -45,18 +47,18 @@ final class SocketChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(ByteBuffer dst) throws IOException { public int read(ByteBuffer dst) throws IOException {
EventHandler handler = Handlers.SOCKET_READ; EventConfiguration eventConfiguration = EventConfigurations.SOCKET_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(dst); return read(dst);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();;
bytesRead = read(dst); bytesRead = read(dst);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
SocketAddress remoteAddress = getRemoteAddress(); SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) { if (remoteAddress instanceof InetSocketAddress isa) {
String hostString = isa.getAddress().toString(); String hostString = isa.getAddress().toString();
@ -66,17 +68,17 @@ final class SocketChannelImplInstrumentor {
String address = hostString.substring(delimiterIndex + 1); String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort(); int port = isa.getPort();
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, host, address, port, 0, 0L, true); SocketReadEvent.commit(start, duration, host, address, port, 0, 0L, true);
} else { } else {
handler.write(start, duration, host, address, port, 0, bytesRead, false); SocketReadEvent.commit(start, duration, host, address, port, 0, bytesRead, false);
} }
} else { } else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
String path = "[" + udsa.getPath().toString() + "]"; String path = "[" + udsa.getPath().toString() + "]";
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, "Unix domain socket", path, 0, 0, 0L, true); SocketReadEvent.commit(start, duration, "Unix domain socket", path, 0, 0, 0L, true);
} else { } else {
handler.write(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false); SocketReadEvent.commit(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false);
} }
} }
} }
@ -87,18 +89,18 @@ final class SocketChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
EventHandler handler = Handlers.SOCKET_READ; EventConfiguration eventConfiguration = EventConfigurations.SOCKET_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(dsts, offset, length); return read(dsts, offset, length);
} }
long bytesRead = 0; long bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(dsts, offset, length); bytesRead = read(dsts, offset, length);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
SocketAddress remoteAddress = getRemoteAddress(); SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) { if (remoteAddress instanceof InetSocketAddress isa) {
String hostString = isa.getAddress().toString(); String hostString = isa.getAddress().toString();
@ -108,17 +110,17 @@ final class SocketChannelImplInstrumentor {
String address = hostString.substring(delimiterIndex + 1); String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort(); int port = isa.getPort();
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, host, address, port, 0, 0L, true); SocketReadEvent.commit(start, duration, host, address, port, 0, 0L, true);
} else { } else {
handler.write(start, duration, host, address, port, 0, bytesRead, false); SocketReadEvent.commit(start, duration, host, address, port, 0, bytesRead, false);
} }
} else { } else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
String path = "[" + udsa.getPath().toString() + "]"; String path = "[" + udsa.getPath().toString() + "]";
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, "Unix domain socket", path, 0, 0, 0L, true); SocketReadEvent.commit(start, duration, "Unix domain socket", path, 0, 0, 0L, true);
} else { } else {
handler.write(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false); SocketReadEvent.commit(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false);
} }
} }
} }
@ -129,18 +131,18 @@ final class SocketChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int write(ByteBuffer buf) throws IOException { public int write(ByteBuffer buf) throws IOException {
EventHandler handler = Handlers.SOCKET_WRITE; EventConfiguration eventConfiguration = EventConfigurations.SOCKET_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return write(buf); return write(buf);
} }
int bytesWritten = 0; int bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesWritten = write(buf); bytesWritten = write(buf);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten < 0 ? 0 : bytesWritten; long bytes = bytesWritten < 0 ? 0 : bytesWritten;
SocketAddress remoteAddress = getRemoteAddress(); SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) { if (remoteAddress instanceof InetSocketAddress isa) {
@ -150,11 +152,11 @@ final class SocketChannelImplInstrumentor {
String host = hostString.substring(0, delimiterIndex); String host = hostString.substring(0, delimiterIndex);
String address = hostString.substring(delimiterIndex + 1); String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort(); int port = isa.getPort();
handler.write(start, duration, host, address, port, bytes); SocketWriteEvent.commit(start, duration, host, address, port, bytes);
} else { } else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
String path = "[" + udsa.getPath().toString() + "]"; String path = "[" + udsa.getPath().toString() + "]";
handler.write(start, duration, "Unix domain socket", path, 0, bytes); SocketWriteEvent.commit(start, duration, "Unix domain socket", path, 0, bytes);
} }
} }
} }
@ -169,18 +171,18 @@ final class SocketChannelImplInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
EventHandler handler = Handlers.SOCKET_WRITE; EventConfiguration eventConfiguration = EventConfigurations.SOCKET_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return write(srcs, offset, length); return write(srcs, offset, length);
} }
long bytesWritten = 0; long bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesWritten = write(srcs, offset, length); bytesWritten = write(srcs, offset, length);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten < 0 ? 0 : bytesWritten; long bytes = bytesWritten < 0 ? 0 : bytesWritten;
SocketAddress remoteAddress = getRemoteAddress(); SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) { if (remoteAddress instanceof InetSocketAddress isa) {
@ -190,11 +192,11 @@ final class SocketChannelImplInstrumentor {
String host = hostString.substring(0, delimiterIndex); String host = hostString.substring(0, delimiterIndex);
String address = hostString.substring(delimiterIndex + 1); String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort(); int port = isa.getPort();
handler.write(start, duration, host, address, port, bytes); SocketWriteEvent.commit(start, duration, host, address, port, bytes);
} else { } else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
String path = "[" + udsa.getPath().toString() + "]"; String path = "[" + udsa.getPath().toString() + "]";
handler.write(start, duration, "Unix domain socket", path, 0, bytes); SocketWriteEvent.commit(start, duration, "Unix domain socket", path, 0, bytes);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -29,8 +29,9 @@ import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import jdk.jfr.events.Handlers; import jdk.jfr.events.EventConfigurations;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.SocketReadEvent;
import jdk.jfr.internal.event.EventConfiguration;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -44,27 +45,27 @@ final class SocketInputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public int read(byte b[], int off, int length) throws IOException { public int read(byte b[], int off, int length) throws IOException {
EventHandler handler = Handlers.SOCKET_READ; EventConfiguration eventConfiguration = EventConfigurations.SOCKET_READ;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
return read(b, off, length); return read(b, off, length);
} }
int bytesRead = 0; int bytesRead = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
bytesRead = read(b, off, length); bytesRead = read(b, off, length);
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
InetAddress remote = parent.getInetAddress(); InetAddress remote = parent.getInetAddress();
String host = remote.getHostName(); String host = remote.getHostName();
String address = remote.getHostAddress(); String address = remote.getHostAddress();
int port = parent.getPort(); int port = parent.getPort();
int timeout = parent.getSoTimeout(); int timeout = parent.getSoTimeout();
if (bytesRead < 0) { if (bytesRead < 0) {
handler.write(start, duration, host, address, port, timeout, 0L, true); SocketReadEvent.commit(start, duration, host, address, port, timeout, 0L, true);
} else { } else {
handler.write(start, duration, host, address, port, timeout, bytesRead, false); SocketReadEvent.commit(start, duration, host, address, port, timeout, bytesRead, false);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2022, 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
@ -29,8 +29,9 @@ import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import jdk.jfr.events.Handlers; import jdk.jfr.events.EventConfigurations;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.SocketWriteEvent;
import jdk.jfr.internal.event.EventConfiguration;
/** /**
* See {@link JITracer} for an explanation of this code. * See {@link JITracer} for an explanation of this code.
@ -44,22 +45,22 @@ final class SocketOutputStreamInstrumentor {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@JIInstrumentationMethod @JIInstrumentationMethod
public void write(byte b[], int off, int len) throws IOException { public void write(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.SOCKET_WRITE; EventConfiguration eventConfiguration = EventConfigurations.SOCKET_WRITE;
if (!handler.isEnabled()) { if (!eventConfiguration.isEnabled()) {
write(b, off, len); write(b, off, len);
return; return;
} }
int bytesWritten = 0; int bytesWritten = 0;
long start = 0; long start = 0;
try { try {
start = EventHandler.timestamp(); start = EventConfiguration.timestamp();
write(b, off, len); write(b, off, len);
bytesWritten = len; bytesWritten = len;
} finally { } finally {
long duration = EventHandler.timestamp() - start; long duration = EventConfiguration.timestamp() - start;
if (handler.shouldCommit(duration)) { if (eventConfiguration.shouldCommit(duration)) {
InetAddress remote = parent.getInetAddress(); InetAddress remote = parent.getInetAddress();
handler.write( SocketWriteEvent.commit(
start, start,
duration, duration,
remote.getHostName(), remote.getHostName(),

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022, 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
@ -27,8 +27,10 @@ package jdk.jfr.internal.instrument;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import jdk.jfr.events.Handlers; import jdk.jfr.events.EventConfigurations;
import jdk.jfr.internal.handlers.EventHandler; import jdk.jfr.events.ErrorThrownEvent;
import jdk.jfr.events.ExceptionThrownEvent;
import jdk.jfr.internal.event.EventConfiguration;
public final class ThrowableTracer { public final class ThrowableTracer {
@ -38,24 +40,24 @@ public final class ThrowableTracer {
if (e instanceof OutOfMemoryError) { if (e instanceof OutOfMemoryError) {
return; return;
} }
long timestamp = EventHandler.timestamp(); long timestamp = EventConfiguration.timestamp();
EventHandler h1 = Handlers.ERROR_THROWN; EventConfiguration eventConfiguration1 = EventConfigurations.ERROR_THROWN;
if (h1.isEnabled()) { if (eventConfiguration1.isEnabled()) {
h1.write(timestamp, 0L, message, e.getClass()); ErrorThrownEvent.commit(timestamp, 0L, message, e.getClass());
} }
EventHandler h2 = Handlers.EXCEPTION_THROWN; EventConfiguration eventConfiguration2 = EventConfigurations.EXCEPTION_THROWN;
if (h2.isEnabled()) { if (eventConfiguration2.isEnabled()) {
h2.write(timestamp, 0L, message, e.getClass()); ExceptionThrownEvent.commit(timestamp, 0L, message, e.getClass());
} }
numThrowables.incrementAndGet(); numThrowables.incrementAndGet();
} }
public static void traceThrowable(Throwable t, String message) { public static void traceThrowable(Throwable t, String message) {
EventHandler h = Handlers.EXCEPTION_THROWN; EventConfiguration eventConfiguration = EventConfigurations.EXCEPTION_THROWN;
if (h.isEnabled()) { if (eventConfiguration.isEnabled()) {
long timestamp = EventHandler.timestamp(); long timestamp = EventConfiguration.timestamp();
h.write(timestamp, 0L, message, t.getClass()); ExceptionThrownEvent.commit(timestamp, 0L, message, t.getClass());
} }
numThrowables.incrementAndGet(); numThrowables.incrementAndGet();
} }

View File

@ -0,0 +1,34 @@
/*
* 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. 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.jvm;
//Purpose of this class is to have something to
//statically link against for TestGetEventWriter.
//
// When the class is loaded "jdk.jfr.jvm.E" will be
// replaced with "jdk.jfr.Event"
public class E {
}

View File

@ -0,0 +1,39 @@
/*
* 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.
*/
package jdk.jfr.jvm;
import jdk.jfr.Registered;
// Class used by TestGetEventWriter
@Registered(false)
public class MyCommitRegisteredFalseEvent extends E implements Runnable {
public void myCommit() {
PlaceholderEventWriterFactory.getEventWriter(4711L);
throw new RuntimeException("Should not reach here");
}
@Override
public void run() {
myCommit();
}
}

View File

@ -0,0 +1,39 @@
/*
* 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.
*/
package jdk.jfr.jvm;
import jdk.jfr.Registered;
// Class used by TestGetEventWriter
@Registered(true)
public class MyCommitRegisteredTrueEvent extends E implements Runnable {
public void myCommit() {
PlaceholderEventWriterFactory.getEventWriter(4711L);
throw new RuntimeException("Should not reach here");
}
@Override
public void run() {
myCommit();
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
package jdk.jfr.jvm;
// Class used by TestGetEventWriter
public class NonEvent implements Runnable {
public void commit() {
PlaceholderEventWriter ew = PlaceholderEventWriterFactory.getEventWriter(4711L);
throw new RuntimeException("Should not reach here " + ew);
}
@Override
public void run() {
commit();
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.
*/
package jdk.jfr.jvm;
// Purpose of this class is to have something to
// statically link against for TestGetEventWriter.
//
// When the class is loaded "jdk.jfr.jvm.PlaceholderEventWriter"
// will be replaced with "jdk.jfr.internal.event.EventWriter"
public class PlaceholderEventWriter {
}

View File

@ -0,0 +1,35 @@
/*
* 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.
*/
package jdk.jfr.jvm;
// Purpose of this class is to have something to
// statically link against for TestGetEventWriter.
//
// When the class is loaded "jdk.jfr.jvm.PlaceholderEventWriterFactory"
// will be replaced with "jdk.jfr.internal.event.EventWriterFactory"
public class PlaceholderEventWriterFactory {
public static PlaceholderEventWriter getEventWriter(long value) {
throw new RuntimeException("Test error, PlaceholderEventWriterFactory class should have been replaced with EventWriterFactory");
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.
*/
package jdk.jfr.jvm;
import jdk.jfr.Registered;
// Class used by TestGetEventWriter
@Registered(false)
public class RegisteredFalseEvent extends E {
public void commit() {
PlaceholderEventWriterFactory.getEventWriter(4711L);
throw new RuntimeException("Should not reach here");
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.
*/
package jdk.jfr.jvm;
import jdk.jfr.Registered;
// Class used by TestGetEventWriter
@Registered(true)
public class RegisteredTrueEvent extends E {
public void commit() {
PlaceholderEventWriterFactory.getEventWriter(4711L);
throw new RuntimeException("Should not reach here");
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.
*/
package jdk.jfr.jvm;
// Class used by TestGetEventWriter
public class StaticCommitEvent implements Runnable {
String message;
int value;
public static void commit(long start, long duration, String message, int value) {
PlaceholderEventWriterFactory.getEventWriter(4711L);
throw new RuntimeException("Should not reach here");
}
@Override
public void run() {
commit(System.nanoTime(), 0L, "hello, world!", 4711);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2022, 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
@ -37,6 +37,6 @@ public class TestEventWriterLog {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:jfr+system+bytecode=trace", "-XX:StartFlightRecording", "-version"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:jfr+system+bytecode=trace", "-XX:StartFlightRecording", "-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start()); OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("extends jdk/jfr/internal/handlers/EventHandler"); output.shouldContain("extends jdk/jfr/events/AbstractJDKEvent");
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2022, 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,27 +23,298 @@
package jdk.jfr.jvm; package jdk.jfr.jvm;
import static jdk.test.lib.Asserts.assertNotNull; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.jfr.internal.EventWriter; import java.lang.invoke.MethodType;
import jdk.jfr.internal.JVM; import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import jdk.jfr.Event;
import jdk.jfr.FlightRecorder;
import jdk.jfr.Recording;
/** /**
* @test TestGetEventWriter * @test TestGetEventWriter
* @key jfr * @key jfr
* @requires vm.hasJFR * @requires vm.hasJFR
* @library /test/lib * @library /test/lib
* @modules jdk.jfr/jdk.jfr.internal *
* @compile PlaceholderEventWriter.java
* @compile PlaceholderEventWriterFactory.java
* @compile E.java
* @compile NonEvent.java
* @compile RegisteredTrueEvent.java
* @compile RegisteredFalseEvent.java
* @compile MyCommitRegisteredTrueEvent.java
* @compile MyCommitRegisteredFalseEvent.java
* @compile StaticCommitEvent.java
* *
* @run main/othervm jdk.jfr.jvm.TestGetEventWriter * @run main/othervm jdk.jfr.jvm.TestGetEventWriter
*
* @run main/othervm/timeout=300 -Xint -XX:+UseInterpreter -Dinterpreted=true
* jdk.jfr.jvm.TestGetEventWriter
*
* @run main/othervm/timeout=300 -Xcomp -XX:-UseInterpreter -Dinterpreted=false
* jdk.jfr.jvm.TestGetEventWriter
*
* @run main/othervm/timeout=300 -Xcomp -XX:TieredStopAtLevel=1 -XX:-UseInterpreter -Dinterpreted=false
* jdk.jfr.jvm.TestGetEventWriter
*
* @run main/othervm/timeout=300 -Xcomp -XX:TieredStopAtLevel=4 -XX:-TieredCompilation -XX:-UseInterpreter -Dinterpreted=false
* jdk.jfr.jvm.TestGetEventWriter
*/ */
public class TestGetEventWriter { public class TestGetEventWriter {
public static void main(String... args) { static class InitializationEvent extends Event {
JVM jvm = JVM.getJVM(); }
jvm.createNativeJFR();
EventWriter writer = EventWriter.getEventWriter(); public static void main(String... args) throws Throwable {
assertNotNull(writer, "EventWriter should not be null"); try (Recording r = new Recording()) {
jvm.destroyNativeJFR(); r.start();
// Unlocks access to jdk.jfr.internal.event
InitializationEvent e = new InitializationEvent();
e.commit();
}
// Make sure EventWriterFactory can be accessed.
Class<?> clazz = Class.forName("jdk.jfr.internal.event.EventWriterFactory");
if (clazz == null) {
throw new Exception("Test error, not able to access jdk.jfr.internal.event.EventWriterFactory class");
}
testRegisteredTrueEvent();
testRegisteredFalseEvent();
testMyCommitRegisteredTrue();
testMyCommitRegisteredFalse();
testStaticCommit();
testMethodHandleEvent();
testReflectionEvent();
testNonEvent();
}
// The class does not inherit jdk.jfr.Event and, as such, does not implement the
// API. It has its own stand-alone "commit()V", which is not an override, that
// attempts to resolve and link against EventWriterFactory. This user implementation
// is not blessed for linkage.
private static void testNonEvent() throws Throwable {
Runnable e = newEventObject("NonEvent");
try {
e.run(); // invokes commit()
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessError iae) {
// OK, as expected
return;
}
}
// The user has defined a class which overrides and implements the "commit()V"
// method declared final in jdk.jfr.Event.
// This user implementation is not blessed for linkage.
private static void testRegisteredTrueEvent() throws Throwable {
Event e = newEventObject("RegisteredTrueEvent");
try {
e.commit(); // throws
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessError iae) {
// OK, as expected
return;
}
}
// The user has defined a class which overrides and implements the "commit()V"
// method declared final in jdk.jfr.Event. This user implementation is not
// blessed for linkage. If a class have user-defined implementations
// of any methods declared final, it is not instrumented.
// Although it is a subclass of jdk.jfr.Event, on initial load, we will
// classify it as being outside of the JFR system. Attempting to register
// such a class throws an IllegalArgumentException. The user-defined
// "commit()V" method is still not blessed for linkage, even after registration.
private static void testRegisteredFalseEvent() throws Throwable {
Event e = newEventObject("RegisteredFalseEvent");
try {
e.commit(); // throws
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessError iae) {
// OK, as expected
}
try {
FlightRecorder.register(e.getClass());
} catch (IllegalArgumentException iae) {
// OK, as expected.
// Can't register an event class where the user has managed to override
// methods in jdk.jfr.Event
}
}
// The user has implemented another method, "myCommit()V", not an override nor
// overload. that attempts to resolve and link EventWriterFactory. This will fail,
// because "myCommit()V" is not blessed for linkage.
private static void testMyCommitRegisteredTrue() throws Throwable {
Runnable e = newEventObject("MyCommitRegisteredTrueEvent");
try {
e.run(); // Invoking the user-defined method throws.
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessError iae) {
// OK, as expected
return;
}
}
// The user has implemented another method, "myCommit()V", not an override,
// nor overload. This linkage will fail because "myCommit()V" is not blessed.
// Since the user has not defined any final methods in jdk.jfr.Event,
// the class is not excluded wholesale from the JFR system.
// Invoking the real "commit()V", installed by the framework, is OK.
private static void testMyCommitRegisteredFalse() throws Throwable {
Runnable e = newEventObject("MyCommitRegisteredFalseEvent");
try {
e.run(); // Invoking the user-defined method throws.
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessError iae) {
// OK, as expected
}
// Instrumentation added.
FlightRecorder.register(e.getClass().asSubclass(Event.class));
Event event = (Event) e;
event.commit(); // Invoking the JFR provided method is OK
}
// Events located in the boot class loader can create a static
// commit-method to emit events. It must not be used by code
// outside of the boot class loader.
private static void testStaticCommit() throws Throwable {
Runnable e = newEventObject("StaticCommitEvent");
try {
e.run(); // Invokes commit(long, long, String, int)
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessError iae) {
// OK, as expected
}
}
static class MethodHandleEvent extends Event {
public void myCommit() throws Throwable {
try {
Class<?> ew = Class.forName("jdk.jfr.internal.event.EventWriter");
MethodType t = MethodType.methodType(ew, List.of(long.class));
Class<?> factory = Class.forName("jdk.jfr.internal.event.EventWriterFactory");
MethodHandle mh = MethodHandles.lookup().findStatic(factory, "getEventWriter", t);
mh.invoke(Long.valueOf(4711)); // throws IllegalAccessException
} catch (ClassNotFoundException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
// The user has implemented another method, "myCommit()V", not an override,
// nor overload. This linkage will fail, because "myCommit()V" is not blessed.
// Using a MethodHandle for linkage is transparent and immaterial.
private static void testMethodHandleEvent() throws Throwable {
MethodHandleEvent e = new MethodHandleEvent();
try {
e.myCommit();
throw new RuntimeException("Should not reach here");
} catch (IllegalAccessException iaex) {
if (iaex.getCause() instanceof IllegalAccessError iae) {
if (iae.getMessage().contains("getEventWriter(long)")) {
// OK, as expected
return;
}
}
}
}
static class ReflectionEvent extends Event {
public void myCommit() throws Throwable {
Class<?> c;
try {
c = Class.forName("jdk.jfr.internal.event.EventWriterFactory");
Method m = c.getMethod("getEventWriter", new Class[] {long.class});
m.invoke(null, Long.valueOf(4711)); // throws InternalError
} catch (ClassNotFoundException | SecurityException e) {
throw new RuntimeException(e);
}
}
}
// The user has implemented another method, "myCommit()V", not an override,
// nor overload, that uses Reflection. This linkage will fail, because
// "myCommit()V" is not blessed. Reflection is using method handles,
// but using a MethodHandle for linkage is transparent and immaterial.
private static void testReflectionEvent() throws Throwable {
ReflectionEvent e = new ReflectionEvent();
try {
e.myCommit(); // throws
throw new RuntimeException("Should not reach here");
} catch (InternalError ie) {
if (ie.getCause() instanceof IllegalAccessException iaex) {
if (iaex.getCause() instanceof IllegalAccessError iae) {
if (iae.getMessage().contains("getEventWriter(long)")) {
// OK, as expected
return;
}
}
}
}
}
private static class BytesClassLoader extends ClassLoader {
private final byte[] bytes;
private final String className;
BytesClassLoader(byte[] bytes, String name) {
this.bytes = bytes;
this.className = name;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals(className)) {
return defineClass(name, bytes, 0, bytes.length);
} else {
return super.loadClass(name);
}
}
}
private static byte[] replace(byte[] bytes, String match, String replacement) {
if (match.length() != replacement.length()) {
throw new IllegalArgumentException("Match must be same size as replacement");
}
for (int i = 0; i < bytes.length - match.length(); i++) {
if (match(bytes, i, match)) {
for (int j = 0; j < replacement.length(); j++) {
bytes[i + j] = (byte) replacement.charAt(j);
}
}
}
return bytes;
}
private static boolean match(byte[] bytes, int offset, String text) {
for (int i = 0; i < text.length(); i++) {
if (bytes[offset + i] != text.charAt(i)) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
private static <T> T newEventObject(String name) throws Throwable {
String r = name + ".class";
String fullName = "jdk.jfr.jvm." + name;
var is = TestGetEventWriter.class.getResourceAsStream(r);
if (is == null) {
throw new Exception("Test error, could not located class file for " + name);
}
byte[] bytes = is.readAllBytes();
is.close();
bytes = replace(bytes, "jdk/jfr/jvm/E", "jdk/jfr/Event");
bytes = replace(bytes, "jdk/jfr/jvm/PlaceholderEventWriterFactory", "jdk/jfr/internal/event/EventWriterFactory");
bytes = replace(bytes, "jdk/jfr/jvm/PlaceholderEventWriter", "jdk/jfr/internal/event/EventWriter");
BytesClassLoader bc = new BytesClassLoader(bytes, fullName);
Class<?> clazz = bc.loadClass(fullName);
Constructor<?> constructor = clazz.getConstructor(new Class[0]);
System.out.println("About to invoke " + fullName + ".commit()");
return (T) constructor.newInstance();
} }
} }

View File

@ -0,0 +1,78 @@
/*
* 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.
*/
package jdk.jfr.jvm;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import jdk.jfr.Event;
import jdk.jfr.FlightRecorder;
import jdk.jfr.Recording;
import jdk.jfr.Registered;
/**
* @test Tests that a module can't execute code in jdk.jfr.internal.event unless an event has been registered.
* @key jfr
* @requires vm.hasJFR
* @library /test/lib
* @run main/othervm
* --add-opens jdk.jfr/jdk.jfr.events=ALL-UNNAMED
* jdk.jfr.jvm.TestGetEventWriterPackage
*/
public class TestGetEventWriterPackage {
@Registered(false)
static class PackageUnlockEvent extends Event {
}
public static void main(String... args) throws Throwable {
// --add-opens jdk.jfr/jdk.jfr.events=ALL-UNNAMED gives access to
// the FileReadEvent class in the jdk.jfr module.
// When JFR is initialized the FileReadEvent is registered and an EventConfiguration object
// assigned to its static field eventConfiguration
try (Recording r = new Recording()) {
r.start();
}
// The tests gets the EventConfiguration object from the class
Class<?>c = Class.forName("jdk.jfr.events.FileReadEvent");
Field f = c.getDeclaredField("eventConfiguration");
f.setAccessible(true);
Object o = f.get(null);
Class<?> clazz = Class.forName("jdk.jfr.internal.event.EventConfiguration");
Method m = clazz.getDeclaredMethod("isRegistered", new Class[0]);
// it then tries to execute a method on the object from the unnamed module
try {
System.out.println("Is registered: " + m.invoke(o, new Object[0]));
throw new Exception("Did NOT expect unnamed module to be able to execute method in EventConfiguration object before event registration");
} catch (IllegalAccessException iae) {
// OK, as expected
}
// The registration makes the jdk.jfr.internal.event accessible
FlightRecorder.register(PackageUnlockEvent.class);
try {
System.out.println("Is registered: " + m.invoke(o, new Object[0]));
} catch (IllegalAccessException iae) {
throw new Exception("Did expect unnamed module to be able to execute method in EventConfiguration object efter event registration", iae);
}
// If a Security Manager would be present, the caller would need
// to have FlightRecorderPermission("registerEvent")
}
}

View File

@ -0,0 +1,115 @@
/*
* 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.
*/
package jdk.jfr.jvm;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InaccessibleObjectException;
import jdk.jfr.Event;
import jdk.jfr.Registered;
/**
* @test Tests that reflective access works as (normally) expected
* @key jfr
* @requires vm.hasJFR
* @library /test/lib
*
* @run main/othervm jdk.jfr.jvm.TestGetEventWriterReflection
*/
public class TestGetEventWriterReflection {
@Registered(false)
static class InitializeEvent extends Event {
}
public static void main(String... args) throws Throwable {
testReflectionGetConstructor();
testReflectionGetDeclaredConstructor();
testReflectionGetDeclaredConstructorSetAccessible();
testReflectionGetDeclaredFieldSetAccessible();
}
// getConstructor() only return public members.
private static void testReflectionGetConstructor() throws Exception {
try {
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
Constructor<?> constructor = c.getConstructor(new Class[0]);
throw new RuntimeException("Should not reach here " + constructor);
} catch (NoSuchMethodException nsme) {
// OK, as expected. The constructor is private.
}
}
// getDeclaredConstructor() return also a private constructor.
// Invoking a private constructor is an instance of IllegalAccess.
private static void testReflectionGetDeclaredConstructor() throws Exception {
try {
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
Constructor<?> constructor = c.getDeclaredConstructor(new Class[0]);
constructor.newInstance();
throw new RuntimeException("Should not reach here " + constructor);
} catch (IllegalAccessException iae) {
if (iae.getMessage().contains("""
cannot access a member of class jdk.jfr.internal.event.EventWriter
(in module jdk.jfr) with modifiers \"private\"
""")) {
// OK, as expected. Private protection in effect.
}
}
}
// getDeclaredConstructor() return also a private constructor.
// setAccessible(true) attempts to make the private constructor public for external access.
// With JEP 403: Strongly Encapsulate JDK Internals, the module and package must first
// be explicitly opened for setAccessible(true) to succeed.
private static void testReflectionGetDeclaredConstructorSetAccessible() throws Exception {
try {
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
Constructor<?> constructor = c.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
throw new RuntimeException("Should not reach here " + constructor);
} catch (InaccessibleObjectException ioe) {
if (ioe.getMessage().contains("module jdk.jfr does not \"opens jdk.jfr.internal.event")) {
// OK, as expected. Even when using setAccessible(true), by default, the jdk.jfr module
// is not open for reflective access to private members.
}
}
}
// getDeclaredField() return also a private field.
// setAccessible(true) attempts to make the private field public for external access.
// With JEP 403: Strongly Encapsulate JDK Internals, the module and package must first
// be explicitly opened for setAccessible(true) to succeed.
private static void testReflectionGetDeclaredFieldSetAccessible() throws Exception {
try {
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
Field field = c.getDeclaredField("jvm");
field.setAccessible(true);
throw new RuntimeException("Should not reach here " + field);
} catch (InaccessibleObjectException ioe) {
if (ioe.getMessage().contains("module jdk.jfr does not \"opens jdk.jfr.internal.event")) {
// OK, as expected. Even when using setAccessible(true), by default, the jdk.jfr module
// is not open for reflective access to private members.
}
}
}
}

View File

@ -60,7 +60,7 @@ public class TestJFRIntrinsic {
TestJFRIntrinsic() throws Exception { TestJFRIntrinsic() throws Exception {
// the intrinsic is premised on this class being loaded already - the event writer object is massaged heavily before returning // the intrinsic is premised on this class being loaded already - the event writer object is massaged heavily before returning
eventWriterClazz = Class.forName("jdk.jfr.internal.EventWriter", true, TestJFRIntrinsic.class.getClassLoader()); eventWriterClazz = Class.forName("jdk.jfr.internal.event.EventWriter", true, TestJFRIntrinsic.class.getClassLoader());
} }
public static void main(String... args) throws Exception { public static void main(String... args) throws Exception {