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
src
test/jdk/jdk/jfr/jvm

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

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,7 @@
class MemoryBuffer;
class GraphBuilder {
friend class JfrResolution;
private:
// Per-scope data. These are pushed and popped as we descend into
// inlined methods. Currently in order to generate good code in the

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -53,8 +53,6 @@ private:
DEBUG_ONLY(bool sid_ok();)
Symbol* get_symbol() const { return _symbol; }
const char* type_string() { return "ciSymbol"; }
void print_impl(outputStream* st);
@ -106,6 +104,9 @@ public:
bool equals(ciSymbol* obj) { return this->_symbol == obj->get_symbol(); }
bool is_signature_polymorphic_name() const;
Symbol* get_symbol() const { return _symbol; }
};
#endif // SHARE_CI_CISYMBOL_HPP

@ -60,6 +60,10 @@
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
//------------------------------------------------------------------------------------------------------------------------
// Implementation of CallInfo
@ -1092,6 +1096,7 @@ void LinkResolver::resolve_static_call(CallInfo& result,
// setup result
result.set_static(resolved_klass, methodHandle(THREAD, resolved_method), CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
}
// throws linktime exceptions
@ -1297,6 +1302,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
// setup result
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,
@ -1417,6 +1423,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
}
// setup result
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,
@ -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)
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());
Handle appendix(THREAD, cpce->appendix_if_resolved(pool));
result.set_handle(resolved_klass, method, appendix, CHECK_false);
JFR_ONLY(Jfr::on_resolution(result, CHECK_false);)
return true;
} else {
return false;
@ -1730,6 +1739,7 @@ void LinkResolver::resolve_handle_call(CallInfo& result,
Handle resolved_appendix;
Method* resolved_method = lookup_polymorphic_method(link_info, &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) {
@ -1811,6 +1821,7 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
bootstrap_specifier.resolve_newly_linked_invokedynamic(result, CHECK);
// Exceptions::wrap_dynamic_exception not used because
// set_handle doesn't throw linkage errors
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
}
// Selected method is abstract.

@ -32,13 +32,13 @@
#include "classfile/modules.hpp"
#include "classfile/stackMapTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verificationType.hpp"
#include "interpreter/bytecodes.hpp"
#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
#include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/jni/jfrUpcalls.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/support/jfrJdkJfrEvent.hpp"
#include "jfr/utilities/jfrBigEndian.hpp"
@ -47,16 +47,19 @@
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/array.hpp"
#include "oops/constMethod.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/method.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
static const u2 number_of_new_methods = 5;
@ -68,7 +71,7 @@ static const char* utf8_constants[] = {
"Code", // 0
"J", // 1
"commit", // 2
"eventHandler", // 3
"eventConfiguration", // 3
"duration", // 4
"begin", // 5
"()V", // 6
@ -77,7 +80,7 @@ static const char* utf8_constants[] = {
"end", // 9
"shouldCommit", // 10
"startTime", // 11 // LAST_REQUIRED_UTF8
"Ljdk/jfr/internal/handlers/EventHandler;", // 12
"Ljdk/jfr/internal/event/EventConfiguration;", // 12
"Ljava/lang/Object;", // 13
"<clinit>", // 14
"jdk/jfr/FlightRecorder", // 15
@ -95,7 +98,7 @@ enum utf8_req_symbols {
UTF8_REQ_Code,
UTF8_REQ_J_FIELD_DESC,
UTF8_REQ_commit,
UTF8_REQ_eventHandler,
UTF8_REQ_eventConfiguration,
UTF8_REQ_duration,
UTF8_REQ_begin,
UTF8_REQ_EMPTY_VOID_METHOD_DESC,
@ -108,7 +111,7 @@ enum utf8_req_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_clinit,
UTF8_OPT_FlightRecorder,
@ -565,11 +568,11 @@ static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_i
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");
add_field_info(writer,
utf8_indexes[UTF8_REQ_eventHandler],
untypedEventHandler ? utf8_indexes[UTF8_OPT_LjavaLangObject] : utf8_indexes[UTF8_OPT_eventHandler_FIELD_DESC],
utf8_indexes[UTF8_REQ_eventConfiguration],
untypedEventConfiguration ? utf8_indexes[UTF8_OPT_LjavaLangObject] : utf8_indexes[UTF8_OPT_eventConfiguration_FIELD_DESC],
true); // static
add_field_info(writer,
@ -1111,11 +1114,40 @@ static jlong insert_clinit_method(const InstanceKlass* ik,
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
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));
initialize_symbols();
static const u2 public_final_flag_mask = JVM_ACC_PUBLIC | JVM_ACC_FINAL;
const ClassFileStream* const orig_stream = parser.clone_stream();
assert(orig_stream != NULL, "invariant");
const int orig_stream_length = orig_stream->length();
// allocate an identically sized buffer
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,
const Method* clinit_method,
bool register_klass,
bool untypedEventHandler,
bool untypedEventConfiguration,
TRAPS) {
assert(utf8_indexes != NULL, "invariant");
u2 added_cp_entries = 0;
@ -1212,10 +1244,10 @@ static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
}
// resolve optional constants
utf8_indexes[UTF8_OPT_eventHandler_FIELD_DESC] = untypedEventHandler ? invalid_cp_index :
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_eventHandler_FIELD_DESC], orig_cp_len, added_cp_entries, THREAD);
utf8_indexes[UTF8_OPT_eventConfiguration_FIELD_DESC] = untypedEventConfiguration ? invalid_cp_index :
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;
if (register_klass) {
@ -1261,7 +1293,7 @@ static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
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,
jint& size_of_new_bytes,
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);
if (new_buffer == NULL) {
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;
}
assert(new_buffer != NULL, "invariant");
@ -1382,6 +1414,10 @@ static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
return new_buffer;
}
static bool should_force_instrumentation() {
return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation();
}
static void log_pending_exception(oop throwable) {
assert(throwable != NULL, "invariant");
oop msg = java_lang_Throwable::message(throwable);
@ -1393,73 +1429,254 @@ static void log_pending_exception(oop throwable) {
}
}
static bool should_force_instrumentation() {
return !JfrOptionSet::allow_event_retransforms() || JfrEventClassTransformer::is_force_instrumentation();
static bool has_pending_exception(TRAPS) {
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");
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;
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) {
return NULL;
}
assert(new_bytes != NULL, "invariant");
assert(size_of_new_bytes > 0, "invariant");
bool force_instrumentation = should_force_instrumentation();
const bool force_instrumentation = should_force_instrumentation();
if (Jfr::is_recording() || force_instrumentation) {
jint size_instrumented_data = 0;
unsigned char* instrumented_data = NULL;
const jclass super = (jclass)JNIHandles::make_local(ik->super()->java_mirror());
jint size_of_instrumented_bytes = 0;
unsigned char* instrumented_bytes = NULL;
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),
force_instrumentation,
boot_class_loader,
super,
size_of_new_bytes,
new_bytes,
&size_instrumented_data,
&instrumented_data,
t);
if (t->has_pending_exception()) {
log_pending_exception(t->pending_exception());
t->clear_pending_exception();
&size_of_instrumented_bytes,
&instrumented_bytes,
THREAD);
JfrJavaSupport::destroy_local_jni_handle(super);
if (has_pending_exception(THREAD)) {
return NULL;
}
assert(instrumented_data != NULL, "invariant");
assert(size_instrumented_data > 0, "invariant");
return new ClassFileStream(instrumented_data, size_instrumented_data, NULL, ClassFileStream::verify);
assert(instrumented_bytes != NULL, "invariant");
assert(size_of_instrumented_bytes > 0, "invariant");
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);
}
static bool cache_bytes(InstanceKlass* ik, ClassFileStream* new_stream, InstanceKlass* new_ik, TRAPS) {
assert(ik != NULL, "invariant");
static bool _force_instrumentation = false;
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->name() != NULL, "invariant");
assert(new_stream != NULL, "invariant");
assert(!HAS_PENDING_EXCEPTION, "invariant");
static const bool can_retransform = JfrOptionSet::allow_retransforms();
if (!can_retransform) {
return true;
assert(thread != NULL, "invariant");
assert(!thread->has_pending_exception(), "invariant");
if (!JfrOptionSet::allow_retransforms()) {
return;
}
const jint stream_len = new_stream->length();
JvmtiCachedClassFileData* p =
(JvmtiCachedClassFileData*)NEW_C_HEAP_ARRAY_RETURN_NULL(u1, offset_of(JvmtiCachedClassFileData, data) + stream_len, mtInternal);
if (p == NULL) {
log_error(jfr, system)("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT
" bytes failed in JfrClassAdapter::on_klass_creation", (size_t)offset_of(JvmtiCachedClassFileData, data) + stream_len);
return false;
log_error(jfr, system)("Allocation using C_HEAP_ARRAY for " SIZE_FORMAT " bytes failed in JfrEventClassTransformer::cache_class_file_data",
static_cast<size_t>(offset_of(JvmtiCachedClassFileData, data) + stream_len));
return;
}
p->length = stream_len;
memcpy(p->data, new_stream->buffer(), stream_len);
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);
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) {
@ -1491,88 +1708,105 @@ static InstanceKlass* create_new_instance_klass(InstanceKlass* ik, ClassFileStre
assert(new_ik != 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");
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) {
assert(ik != NULL, "invariant");
assert(new_ik != NULL, "invariant");
assert(new_ik->name() != NULL, "invariant");
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;
static InstanceKlass* create_instance_klass(InstanceKlass*& ik, ClassFileStream* stream, bool is_initial_load, JavaThread* thread) {
if (stream == NULL) {
if (is_initial_load) {
log_error(jfr, system)("JfrEventClassTransformer: unable to create ClassFileStream for %s", ik->external_name());
}
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;
return NULL;
}
InstanceKlass* const new_ik = create_new_instance_klass(ik, stream, thread);
if (new_ik == NULL) {
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
assert(!JdkJfrEvent::is(new_ik), "invariant");
JdkJfrEvent::tag_as(new_ik);
assert(JdkJfrEvent::is(new_ik), "invariant");
rewrite_klass_pointer(ik, new_ik, parser, THREAD);
}
return new_ik;
}
static void transform(InstanceKlass*& ik, ClassFileParser& parser, JavaThread* 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;
}
assert(JdkJfrEvent::is_subklass(ik), "invariant");
if (ik->is_abstract() || is_retransforming(ik, THREAD)) {
// abstract and scratch classes are not instrumented
if (existing_klass != NULL) {
transfer_cached_class_file_data(ik, new_ik, parser, thread);
} 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;
}
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
ClassFileStream* const new_stream = create_new_bytes_for_subklass(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);
transform(ik, parser, THREAD);
}
static bool _force_instrumentation = false;
void JfrEventClassTransformer::set_force_instrumentation(bool force_instrumentation) {
_force_instrumentation = force_instrumentation;
static bool is_static_commit_method_blessed(const Array<Method*>* methods) {
assert(methods != NULL, "invariant");
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() {
return _force_instrumentation;
static bool is_instance_commit_method_blessed(const Array<Method*>* methods) {
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);
}

@ -28,6 +28,7 @@
#include "memory/allStatic.hpp"
#include "utilities/exceptions.hpp"
class CallInfo;
class ClassFileParser;
class InstanceKlass;
@ -38,6 +39,7 @@ class InstanceKlass;
class JfrEventClassTransformer : AllStatic {
public:
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 bool is_force_instrumentation();
};

@ -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.
*
* 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;
/* Set 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));
check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
return jvmti_ret_code == JVMTI_ERROR_NONE;

@ -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);
}
}

@ -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

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "jfr/instrumentation/jfrResolution.hpp"
#include "jfr/jfr.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
@ -30,6 +31,7 @@
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/support/jfrThreadLocal.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);
}
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) {
if (JfrRecorder::is_recording()) {
JfrEmergencyDump::on_vm_shutdown(exception_handler);

@ -27,11 +27,18 @@
#include "jni.h"
#include "memory/allStatic.hpp"
#include "utilities/exceptions.hpp"
#include "oops/oopsHierarchy.hpp"
#include "utilities/globalDefinitions.hpp"
class CallInfo;
class ciKlass;
class ciMethod;
class GraphBuilder;
class JavaThread;
class Klass;
class outputStream;
class Parse;
class Thread;
extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass);
@ -53,6 +60,9 @@ class Jfr : AllStatic {
static void exclude_thread(Thread* thread);
static void on_thread_start(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_set_current_thread(JavaThread* jt, oop thread);
static void on_vm_shutdown(bool exception_handler = false);

@ -28,6 +28,7 @@
#include "classfile/symbolTable.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
#include "jfr/jni/jfrJavaCall.hpp"
#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
@ -762,7 +763,7 @@ bool JfrJavaSupport::is_excluded(Thread* 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(descriptor != NULL, "invariant");
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);
}
assert(ik->is_being_initialized() || ik->is_initialized(), "invariant");
const Klass* const typed_field_holder = ik->find_field(vmSymbols::eventHandler_name(),
vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(),
const Klass* const typed_field_holder = ik->find_field(vmSymbols::eventConfiguration_name(),
vmSymbols::jdk_jfr_internal_event_EventConfiguration_signature(),
true,
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
true,
descriptor);
}
jobject JfrJavaSupport::get_handler(jobject clazz, TRAPS) {
jobject JfrJavaSupport::get_configuration(jobject clazz, TRAPS) {
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
HandleMark hm(THREAD);
const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz)));
assert(h_mirror.not_null(), "invariant");
fieldDescriptor handler_field_descriptor;
const Klass* const field_holder = get_handler_field_descriptor(h_mirror, &handler_field_descriptor, THREAD);
fieldDescriptor configuration_field_descriptor;
const Klass* const field_holder = get_configuration_field_descriptor(h_mirror, &configuration_field_descriptor, THREAD);
if (field_holder == NULL) {
// The only reason should be that klass initialization failed.
return NULL;
}
assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant");
oop handler_oop = h_mirror->obj_field(handler_field_descriptor.offset());
return handler_oop != NULL ? JfrJavaSupport::local_jni_handle(handler_oop, THREAD) : NULL;
oop configuration_oop = h_mirror->obj_field(configuration_field_descriptor.offset());
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));
HandleMark hm(THREAD);
const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz)));
assert(h_mirror.not_null(), "invariant");
fieldDescriptor handler_field_descriptor;
const Klass* const field_holder = get_handler_field_descriptor(h_mirror, &handler_field_descriptor, THREAD);
fieldDescriptor configuration_field_descriptor;
const Klass* const field_holder = get_configuration_field_descriptor(h_mirror, &configuration_field_descriptor, THREAD);
if (field_holder == NULL) {
// The only reason should be that klass initialization failed.
return false;
}
assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant");
const oop handler_oop = JNIHandles::resolve(handler);
assert(handler_oop != NULL, "invariant");
h_mirror->obj_field_put(handler_field_descriptor.offset(), handler_oop);
const oop configuration_oop = JNIHandles::resolve(configuration);
assert(configuration_oop != NULL, "invariant");
h_mirror->obj_field_put(configuration_field_descriptor.offset(), configuration_oop);
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) {
assert(t != NULL, "invariant");
assert(Thread::current() == t, "invariant");

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

@ -366,10 +366,18 @@ JVM_ENTRY_NO_ENV(jlong, jfr_chunk_start_nanos(JNIEnv* env, jobject jvm))
return JfrRepository::current_chunk_start_nanos();
JVM_END
JVM_ENTRY_NO_ENV(jobject, jfr_get_handler(JNIEnv * env, jobject jvm, jobject clazz))
return JfrJavaSupport::get_handler(clazz, thread);
JVM_ENTRY_NO_ENV(jobject, jfr_get_configuration(JNIEnv * env, jobject jvm, jobject clazz))
return JfrJavaSupport::get_configuration(clazz, thread);
JVM_END
JVM_ENTRY_NO_ENV(jboolean, jfr_set_handler(JNIEnv * env, jobject jvm, jobject clazz, jobject handler))
return JfrJavaSupport::set_handler(clazz, handler, thread);
JVM_ENTRY_NO_ENV(jboolean, jfr_set_configuration(JNIEnv * env, jobject jvm, jobject clazz, jobject configuration))
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

@ -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.
*
* 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);
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);
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
}
#endif
#endif // SHARE_JFR_JNI_JFRJNIMETHOD_HPP

@ -69,9 +69,9 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"isAvailable", (char*)"()Z", (void*)jfr_is_available,
(char*)"getTimeConversionFactor", (char*)"()D", (void*)jfr_time_conv_factor,
(char*)"getTypeId", (char*)"(Ljava/lang/Class;)J", (void*)jfr_type_id,
(char*)"getEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_get_event_writer,
(char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer,
(char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush,
(char*)"getEventWriter", (char*)"()Ljdk/jfr/internal/event/EventWriter;", (void*)jfr_get_event_writer,
(char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/event/EventWriter;", (void*)jfr_new_event_writer,
(char*)"flush", (char*)"(Ljdk/jfr/internal/event/EventWriter;II)Z", (void*)jfr_event_writer_flush,
(char*)"flush", (char*)"()V", (void*)jfr_flush,
(char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location,
(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*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded,
(char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos,
(char*)"getHandler", (char*)"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)jfr_get_handler,
(char*)"setHandler", (char*)"(Ljava/lang/Class;Ljdk/jfr/internal/handlers/EventHandler;)Z", (void*)jfr_set_handler,
(char*)"getTypeId", (char*)"(Ljava/lang/String;)J", (void*)jfr_get_type_id_from_string
(char*)"getConfiguration", (char*)"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)jfr_get_configuration,
(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*)"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);
@ -105,3 +107,4 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
env->DeleteLocalRef(jfr_clz);
}
}

@ -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.
*
* 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));
jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls");
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_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_sig_sym = SymbolTable::new_permanent_symbol("()V");
initialized = unhide_internal_types_sig_sym != NULL;
@ -67,6 +67,7 @@ static bool initialize(TRAPS) {
static const typeArrayOop invoke(jlong trace_id,
jboolean force_instrumentation,
jboolean boot_class_loader,
jclass class_being_redefined,
jint class_data_len,
const unsigned char* class_data,
@ -83,6 +84,7 @@ static const typeArrayOop invoke(jlong trace_id,
JfrJavaArguments args(&result, klass, method_sym, signature_sym);
args.push_long(trace_id);
args.push_int(force_instrumentation);
args.push_int(boot_class_loader);
args.push_jobject(class_being_redefined);
args.push_oop(old_byte_array);
JfrJavaSupport::call_static(&args, THREAD);
@ -129,6 +131,7 @@ void JfrUpcalls::on_retransform(jlong trace_id,
initialize(THREAD);
const typeArrayOop new_byte_array = invoke(trace_id,
false,
false, // not used
class_being_redefined,
class_data_len,
class_data,
@ -152,6 +155,7 @@ void JfrUpcalls::on_retransform(jlong trace_id,
void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id,
jboolean force_instrumentation,
jboolean boot_class_loader,
jclass super,
jint class_data_len,
const unsigned char* class_data,
@ -167,6 +171,7 @@ void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id,
initialize(THREAD);
const typeArrayOop new_byte_array = invoke(trace_id,
force_instrumentation,
boot_class_loader,
super,
class_data_len,
class_data,

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,6 +39,7 @@ class JfrUpcalls : AllStatic {
public:
static void new_bytes_eager_instrumentation(jlong trace_id,
jboolean force_instrumentation,
jboolean boot_class_loader,
jclass super,
jint class_data_len,
const unsigned char* class_data,

@ -28,16 +28,15 @@
#include "classfile/symbolTable.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "oops/arrayKlass.inline.hpp"
#include "oops/klass.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/atomic.hpp"
#include "runtime/vm_version.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/debug.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/growableArray.hpp"
// returns updated value
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) {
assert(klass != NULL, "invariant");
assert(klass != nullptr, "invariant");
klass->set_trace_id(next_class_id());
check_klass(klass);
const Klass* const super = klass->super();
if (super == NULL) {
if (super == nullptr) {
return;
}
if (IS_EVENT_KLASS(super)) {
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);
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");
}

@ -120,6 +120,7 @@ class JfrTraceId : public AllStatic {
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 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 jclass jc);

@ -54,6 +54,7 @@
#define TRANSIENT_BIT (TRANSIENT_META_BIT << META_SHIFT)
#define SERIALIZED_META_BIT (BIT << 4)
#define SERIALIZED_BIT (SERIALIZED_META_BIT << META_SHIFT)
#define BLESSED_METHOD_BIT (JDK_JFR_EVENT_SUBKLASS)
#define TRACE_ID_SHIFT 16
#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)
@ -104,6 +105,7 @@
#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_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
#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 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 BLESS_METHOD(method) (METHOD_FLAG_TAG(method, BLESSED_METHOD_BIT))
// types
#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 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 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 EVENT_KLASS_MASK(kls) (TRACE_ID_RAW(kls) & EVENT_BITS)

@ -45,19 +45,21 @@ class JfrIntrinsicSupport : AllStatic {
#define JFR_HAVE_INTRINSICS
#define JFR_TEMPLATES(template) \
template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \
template(jdk_jfr_internal_handlers_EventHandler_signature, "Ljdk/jfr/internal/handlers/EventHandler;") \
template(eventHandler_name, "eventHandler") \
template(void_eventWriter_signature, "()Ljdk/jfr/internal/EventWriter;") \
#define JFR_TEMPLATES(template) \
template(jdk_jfr_internal_JVM, "jdk/jfr/internal/JVM") \
template(jdk_jfr_internal_event_EventWriterFactory, "jdk/jfr/internal/event/EventWriterFactory") \
template(jdk_jfr_internal_event_EventConfiguration_signature, "Ljdk/jfr/internal/event/EventConfiguration;") \
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) \
do_intrinsic(_counterTime, jdk_jfr_internal_JVM, counterTime_name, void_long_signature, F_SN) \
do_name( counterTime_name, "counterTime") \
do_intrinsic(_getClassId, jdk_jfr_internal_JVM, getClassId_name, class_long_signature, F_SN) \
do_name( getClassId_name, "getClassId") \
do_intrinsic(_getEventWriter, jdk_jfr_internal_JVM, getEventWriter_name, void_eventWriter_signature, F_SN) \
do_name( getEventWriter_name, "getEventWriter") \
#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_name( counterTime_name, "counterTime") \
do_intrinsic(_getClassId, jdk_jfr_internal_JVM, getClassId_name, class_long_signature, F_SN) \
do_name( getClassId_name, "getClassId") \
do_intrinsic(_getEventWriter, jdk_jfr_internal_JVM, getEventWriter_name, getEventWriter_signature, F_SN) \
do_name( getEventWriter_name, "getEventWriter") \
#else // !INCLUDE_JFR

@ -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.
*
* 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) {
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());
}
@ -196,6 +200,10 @@ bool JdkJfrEvent::is_a(const jclass 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) {
return JfrTraceId::is_event_host(k);
}
@ -219,3 +227,8 @@ bool JdkJfrEvent::is_visible(const Klass* k) {
bool JdkJfrEvent::is_visible(const jclass jc) {
return JfrTraceId::in_visible_set(jc);
}
bool JdkJfrEvent::is_excluded(const jclass jc) {
return !JfrTraceId::in_visible_set(jc);
}

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

@ -38,6 +38,7 @@
#define EVENT_HOST_KLASS 64
#define EVENT_RESERVED 128
#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

@ -50,7 +50,7 @@ static int thread_id_offset = invalid_offset;
static int valid_offset = invalid_offset;
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);
assert(k_sym != NULL, "invariant");
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");
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(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 signature[] = "(JJJJZZ)V";
JavaValue result(T_OBJECT);

@ -41,6 +41,10 @@
#include "opto/subnode.hpp"
#include "prims/methodHandles.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) {
if (TraceTypeProfile || C->print_inlining()) {
@ -511,6 +515,7 @@ void Parse::do_call() {
ciKlass* holder = iter().get_declared_method_holder();
ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder);
assert(declared_signature != NULL, "cannot be null");
JFR_ONLY(Jfr::on_resolution(this, holder, orig_callee);)
// Bump max node limit for JSR292 users
if (bc() == Bytecodes::_invokedynamic || orig_callee->is_method_handle_intrinsic()) {

@ -3220,7 +3220,7 @@ bool LibraryCallKit::inline_native_getEventWriter() {
set_i_o(_gvn.transform(vthread_compare_io));
// 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");
ciInstanceKlass* const instklass_EventWriter = klass_EventWriter->as_instance_klass();
const TypeKlassPtr* const aklass = TypeKlassPtr::make(instklass_EventWriter);

@ -150,9 +150,9 @@ public final class EventFactory {
try {
return new EventFactory(eventClass, sanitizedAnnotation, sanitizedFields);
} 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) {
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());
}
}

@ -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.
*
* 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 {
// The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, Class)
// commit(..., String, Class)
@Label("Message")
public String message;
@Label("Class")
public Class<?> thrownClass;
public static void commit(long start, long duration, String message, Class<? extends Error> thrownClass) {
// Generated
}
}

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

@ -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.
*
* 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 {
// The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, Class)
// commit(..., String, Class)
@Label("Message")
public String message;
@Label("Class")
public Class<?> thrownClass;
public static void commit(long start, long duration, String message, Class<? extends Throwable> thrownClass) {
// Generated
}
}

@ -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.
*
* 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 {
// The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, boolean)
// commit(..., String, boolean)
@Label("Path")
@Description("Full path of the file")
@ -47,4 +47,8 @@ public final class FileForceEvent extends AbstractJDKEvent {
@Label("Update Metadata")
@Description("Whether the file metadata is updated")
public boolean metaData;
public static void commit(long start, long duration, String path, boolean metaData) {
// Generated
}
}

@ -39,7 +39,7 @@ import jdk.jfr.internal.Type;
public final class FileReadEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, long, boolean)
// commit(..., String, long, boolean)
@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")
@ -53,4 +53,8 @@ public final class FileReadEvent extends AbstractJDKEvent {
@Label("End of File")
@Description("If end of file was reached")
public boolean endOfFile;
public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) {
// Generated
}
}

@ -39,7 +39,7 @@ import jdk.jfr.internal.Type;
public final class FileWriteEvent extends AbstractJDKEvent {
// The order of these fields must be the same as the parameters in
// EventHandler::write(..., String, long)
// commit(..., String, long)
@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")
@ -49,4 +49,8 @@ public final class FileWriteEvent extends AbstractJDKEvent {
@Description("Number of bytes written to the file")
@DataAmount
public long bytesWritten;
public static void commit(long start, long duration, String path, long bytesWritten) {
// Generated
}
}

@ -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.
*
* 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 {
// 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")
public String host;
@ -63,4 +63,8 @@ public final class SocketReadEvent extends AbstractJDKEvent {
@Label("End of Stream")
@Description("If end of stream was reached")
public boolean endOfStream;
public static void commit(long start, long duration, String host, String address, int port, long timeout, long byteRead, boolean endOfStream) {
// Generated
}
}

@ -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.
*
* 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 {
// 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")
public String host;
@ -54,4 +54,8 @@ public final class SocketWriteEvent extends AbstractJDKEvent {
@Description("Number of bytes written to the socket")
@DataAmount
public long bytesWritten;
public static void commit(long start, long duration, String host, String address, int port, long bytes) {
// Generated
}
}

@ -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.
*
* 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.PrintWriter;
import java.util.List;
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.commons.Method;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
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) {
String typeName = v.getTypeName();
@ -79,7 +61,7 @@ final class ASMToolkit {
case "java.lang.String":
return TYPE_STRING;
case "java.lang.Thread":
return Type_THREAD;
return TYPE_THREAD;
case "java.lang.Class":
return TYPE_CLASS;
}
@ -135,18 +117,6 @@ final class ASMToolkit {
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) {
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className);
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());
};
}
}

@ -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.
*
* 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;
final class Bits { // package-private
public final class Bits {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final boolean unalignedAccess = unsafe.unalignedAccess();
@ -158,12 +158,12 @@ final class Bits { // package-private
}
// external api
static int putByte(long a, byte x) {
public static int putByte(long a, byte x) {
putByte_(a, x);
return Byte.BYTES;
}
static int putBoolean(long a, boolean x) {
public static int putBoolean(long a, boolean x) {
putBoolean_(a, x);
return Byte.BYTES;
}
@ -186,7 +186,7 @@ final class Bits { // package-private
return Short.BYTES;
}
static int putInt(long a, int x) {
public static int putInt(long a, int x) {
if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) {
putInt_(a, x);
return Integer.BYTES;
@ -204,7 +204,7 @@ final class Bits { // package-private
return Long.BYTES;
}
static int putFloat(long a, float x) {
public static int putFloat(long a, float x) {
if (unalignedAccess || isAddressAligned(a, Float.BYTES)) {
putFloat_(a, x);
return Float.BYTES;
@ -213,7 +213,7 @@ final class Bits { // package-private
return Float.BYTES;
}
static int putDouble(long a, double x) {
public static int putDouble(long a, double x) {
if (unalignedAccess || isAddressAligned(a, Double.BYTES)) {
putDouble_(a, x);
return Double.BYTES;

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

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -101,7 +101,7 @@ public final class EventClassBuilder {
private void buildConstructor() {
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null);
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.visitMaxs(0, 0);
}

@ -170,9 +170,8 @@ public final class EventControl {
Module settingModule = settingsClass.getModule();
Modules.addReads(settingModule, EventControl.class.getModule());
int index = settingInfos.size();
SettingInfo si = new SettingInfo(FIELD_SETTING_PREFIX + index, index);
si.settingControl = instantiateSettingControl(settingsClass);
Control c = new Control(si.settingControl, null);
SettingControl settingControl = instantiateSettingControl(settingsClass);
Control c = new Control(settingControl, null);
c.setDefault();
String defaultValue = c.getValue();
if (defaultValue != null) {
@ -187,7 +186,7 @@ public final class EventControl {
aes.trimToSize();
addControl(settingName, c);
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) {
// Programming error by user, fail fast

@ -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();
}
}

@ -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.
*
* 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.SettingControl;
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}.
*
*/
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
// used to check enablement before calling commit
// Methods on settingControl must never be invoked
// directly by JFR, instead use jdk.jfr.internal.Control
SettingControl settingControl;
public SettingInfo(String fieldName, int index) {
this.fieldName = fieldName;
this.index = index;
record SettingInfo(String fieldName, int index, Type paramType, String methodName, SettingControl settingControl) {
/**
* A malicious user must never be able to run a callback in the wrong
* context. Methods on SettingControl must therefore never be invoked directly
* by JFR, instead use jdk.jfr.internal.Control.
*/
public SettingControl settingControl() {
return this.settingControl;
}
}
static final class FieldInfo {
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);
}
record FieldInfo(String fieldName, String fieldDescriptor, String internalClassName) {
}
public static final String FIELD_EVENT_THREAD = "eventThread";
public static final String FIELD_STACK_TRACE = "stackTrace";
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";
private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class);
private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class);
private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class);
private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.class);
private static final String ANNOTATION_NAME_DESCRIPTOR = Type.getDescriptor(Name.class);
private static final String ANNOTATION_REGISTERED_DESCRIPTOR = Type.getDescriptor(Registered.class);
private static final String ANNOTATION_ENABLED_DESCRIPTOR = Type.getDescriptor(Enabled.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_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_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_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_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_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_RESET = new Method("reset", "()V");
private final ClassNode classNode;
private final List<SettingInfo> settingInfos;
private final List<FieldInfo> fieldInfos;;
private final Method writeMethod;
private final String eventHandlerXInternalName;
private final String eventName;
private final boolean untypedEventHandler;
private boolean guardHandlerReference;
private Class<?> superClass;
private final Class<?> superClass;
private final boolean untypedEventConfiguration;
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.classNode = createClassNode(bytes);
this.settingInfos = buildSettingInfos(superClass, classNode);
this.fieldInfos = buildFieldInfos(superClass, classNode);
this.untypedEventHandler = hasUntypedHandler();
this.writeMethod = makeWriteMethod(fieldInfos);
this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id));
String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class);
String n = annotationValue(classNode, ANNOTATION_NAME_DESCRIPTOR, String.class);
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() {
for (FieldNode field : classNode.fields) {
if (FIELD_EVENT_HANDLER.equals(field.name)) {
return field.desc.equals(TYPE_OBJECT.getDescriptor());
public static Method findStaticCommitMethod(ClassNode classNode, List<FieldInfo> fields) {
StringBuilder sb = new StringBuilder();
sb.append("(");
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() {
return classNode.name.replace("/",".");
return classNode.name.replace("/", ".");
}
private ClassNode createClassNode(byte[] bytes) {
@ -159,7 +166,7 @@ public final class EventInstrumentation {
}
boolean isRegistered() {
Boolean result = annotationValue(classNode, ANNOTATION_TYPE_REGISTERED.getDescriptor(), Boolean.class);
Boolean result = annotationValue(classNode, ANNOTATION_REGISTERED_DESCRIPTOR, Boolean.class);
if (result != null) {
return result.booleanValue();
}
@ -173,7 +180,7 @@ public final class EventInstrumentation {
}
boolean isEnabled() {
Boolean result = annotationValue(classNode, ANNOTATION_TYPE_ENABLED.getDescriptor(), Boolean.class);
Boolean result = annotationValue(classNode, ANNOTATION_ENABLED_DESCRIPTOR, Boolean.class);
if (result != null) {
return result.booleanValue();
}
@ -198,7 +205,7 @@ public final class EventInstrumentation {
if (key instanceof String keyName && value != null) {
if (type == value.getClass()) {
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) {
Set<String> methodSet = new HashSet<>();
List<SettingInfo> settingInfos = new ArrayList<>();
String settingDescriptor = Type.getType(SettingDefinition.class).getDescriptor();
String nameDescriptor = Type.getType(Name.class).getDescriptor();
for (MethodNode m : classNode.methods) {
if (m.visibleAnnotations != null) {
for (AnnotationNode an : m.visibleAnnotations) {
// We can't really validate the method at this
// stage. We would need to check that the parameter
// is an instance of SettingControl.
if (settingDescriptor.equals(an.desc)) {
if (TYPE_SETTING_DEFINITION_DESCRIPTOR.equals(an.desc)) {
String name = m.name;
for (AnnotationNode nameCandidate : m.visibleAnnotations) {
if (nameDescriptor.equals(nameCandidate.desc)) {
if (ANNOTATION_NAME_DESCRIPTOR.equals(nameCandidate.desc)) {
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);
}
}
@ -237,12 +242,8 @@ public final class EventInstrumentation {
Type paramType = args[0];
String fieldName = EventControl.FIELD_SETTING_PREFIX + 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);
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());
String fieldName = EventControl.FIELD_SETTING_PREFIX + 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());
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) {
Set<String> fieldSet = new HashSet<>();
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.
// The benefit of adding them manually is that we can
// control in which order they occur and we can add @Name, @Description
@ -339,17 +336,16 @@ public final class EventInstrumentation {
}
private void makeInstrumented() {
// MyEvent#isEnabled()
updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
Label nullLabel = new Label();
if (guardHandlerReference) {
getEventHandler(methodVisitor);
if (guardEventConfiguration) {
getEventConfiguration(methodVisitor);
methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel);
}
getEventHandler(methodVisitor);
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED);
getEventConfiguration(methodVisitor);
invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED);
methodVisitor.visitInsn(Opcodes.IRETURN);
if (guardHandlerReference) {
if (guardEventConfiguration) {
methodVisitor.visitLabel(nullLabel);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitInsn(Opcodes.ICONST_0);
@ -360,7 +356,7 @@ public final class EventInstrumentation {
// MyEvent#begin()
updateMethod(METHOD_BEGIN, methodVisitor -> {
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.visitInsn(Opcodes.RETURN);
});
@ -370,105 +366,301 @@ public final class EventInstrumentation {
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
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.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(0, 0);
});
updateMethod(METHOD_COMMIT, methodVisitor -> {
// if (!isEnable()) {
// return;
// }
methodVisitor.visitCode();
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false);
Label l0 = new Label();
methodVisitor.visitJumpInsn(Opcodes.IFNE, l0);
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitLabel(l0);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
// if (startTime == 0) {
// 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_HANDLER.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_HANDLER.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);
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false);
Label end = new Label();
// eventHandler.write(...);
// }
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
getEventHandler(methodVisitor);
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
for (FieldInfo fi : fieldInfos) {
// MyEvent#commit() or static MyEvent#commit(...)
if (staticCommitMethod != null) {
updateExistingWithEmptyVoidMethod(METHOD_COMMIT);
updateMethod(staticCommitMethod, mv -> {
// indexes the argument type array, the argument type array does not include
// 'this'
int argIndex = 0;
// indexes the proper slot in the local variable table, takes type size into
// account, therefore sometimes argIndex != slotIndex
int slotIndex = 0;
int fieldIndex = 0;
Type[] argumentTypes = Type.getArgumentTypes(staticCommitMethod.getDescriptor());
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);
getEventWriter(mv);
// stack: [EW]
mv.visitInsn(Opcodes.DUP);
// stack: [EW], [EW]
// write begin event
getEventConfiguration(mv);
// stack: [EW], [EW], [EventConfiguration]
mv.visitLdcInsn(eventTypeId);
// stack: [EW], [EW], [EventConfiguration] [long]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asASM());
// stack: [EW], [integer]
Label excluded = new Label();
mv.visitJumpInsn(Opcodes.IFEQ, excluded);
// stack: [EW]
// write startTime
mv.visitInsn(Opcodes.DUP);
// stack: [EW], [EW]
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
// stack: [EW], [EW], [long]
slotIndex += argumentTypes[argIndex++].getSize();
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
// stack: [EW]
fieldIndex++;
// write duration
mv.visitInsn(Opcodes.DUP);
// stack: [EW], [EW]
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
// stack: [EW], [EW], [long]
slotIndex += argumentTypes[argIndex++].getSize();
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
// stack: [EW]
fieldIndex++;
// write eventThread
mv.visitInsn(Opcodes.DUP);
// stack: [EW], [EW]
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM());
// stack: [EW]
// 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.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor);
}
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, eventHandlerXInternalName, writeMethod.getName(), writeMethod.getDescriptor(), false);
methodVisitor.visitLabel(end);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitEnd();
});
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false);
Label l0 = new Label();
methodVisitor.visitJumpInsn(Opcodes.IFNE, l0);
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitLabel(l0);
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
// if (startTime == 0) {
// 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()
updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
Label fail = new Label();
if (guardHandlerReference) {
getEventHandler(methodVisitor);
if (guardEventConfiguration) {
getEventConfiguration(methodVisitor);
methodVisitor.visitJumpInsn(Opcodes.IFNULL, fail);
}
// if (!eventHandler.shouldCommit(duration) goto fail;
getEventHandler(methodVisitor);
// if (!eventConfiguration.shouldCommit(duration) goto fail;
getEventConfiguration(methodVisitor);
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
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);
int index = 0;
for (SettingInfo si : settingInfos) {
// if (!settingsMethod(eventHandler.settingX)) goto fail;
// if (!settingsMethod(eventConfiguration.settingX)) goto fail;
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
if (untypedEventHandler) {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor());
if (untypedEventConfiguration) {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_OBJECT_DESCRIPTOR);
} 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.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName);
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false);
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, TYPE_EVENT_CONFIGURATION.getInternalName());
methodVisitor.visitLdcInsn(index);
invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING);
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.paramType().getInternalName());
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.paramType().getDescriptor() + ")Z", false);
methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
index++;
}
// return true
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) {
if (untypedEventHandler) {
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor());
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, TYPE_EVENT_HANDLER.getInternalName());
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 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 {
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_IS_ENABLED);
updateExistingWithEmptyVoidMethod(METHOD_COMMIT);
if (staticCommitMethod != null) {
updateExistingWithEmptyVoidMethod(staticCommitMethod);
}
updateExistingWithEmptyVoidMethod(METHOD_BEGIN);
updateExistingWithEmptyVoidMethod(METHOD_END);
}
@ -533,33 +747,11 @@ public final class EventInstrumentation {
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() {
return classNode.name;
}
public List<SettingInfo> getSettingInfos() {
return settingInfos;
}
public List<FieldInfo> getFieldInfos() {
return fieldInfos;
}
public String getEventName() {
return eventName;
}
public void setGuardHandler(boolean guardHandlerReference) {
this.guardHandlerReference = guardHandlerReference;
}
}

@ -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.
}
}

@ -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;
}
}

@ -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.
*
* 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.jfr.internal.EventInstrumentation.FieldInfo;
import jdk.jfr.internal.event.EventConfiguration;
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"),
PUT_BYTE("(B)V", "byte", "putByte"),
PUT_SHORT("(S)V", "short", "putShort"),
@ -42,12 +43,12 @@ public enum EventWriterMethod {
PUT_BOOLEAN("(Z)V", "boolean", "putBoolean"),
PUT_THREAD("(Ljava/lang/Thread;)V", Type.THREAD.getName(), "putThread"),
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_STACK_TRACE("()V", Type.TYPES_PREFIX + "StackTrace", "putStackTrace");
private final Method asmMethod;
private final String typeDescriptor;
final Method asmMethod;
final String typeDescriptor;
EventWriterMethod(String paramSignature, String typeName, String methodName) {
this.typeDescriptor = ASMToolkit.getDescriptor(typeName);
@ -68,14 +69,14 @@ public enum EventWriterMethod {
*/
public static EventWriterMethod lookupMethod(FieldInfo v) {
// event thread
if (v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD)) {
if (v.fieldName().equals(EventInstrumentation.FIELD_EVENT_THREAD)) {
return EventWriterMethod.PUT_EVENT_THREAD;
}
for (EventWriterMethod m : EventWriterMethod.values()) {
if (v.fieldDescriptor.equals(m.typeDescriptor)) {
if (v.fieldDescriptor().equals(m.typeDescriptor)) {
return m;
}
}
throw new Error("Unknown type " + v.fieldDescriptor);
throw new Error("Unknown type " + v.fieldDescriptor());
}
}

@ -29,8 +29,8 @@ import java.util.List;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.jfr.Event;
import jdk.jfr.internal.EventWriter;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.internal.event.EventWriter;
/**
* Interface against the JVM.
@ -212,7 +212,7 @@ public final class JVM {
*
* @throws IllegalStateException if wrong JVMTI phase.
*/
public synchronized native void retransformClasses(Class<?>[] classes);
public synchronized native void retransformClasses(Class<?>[] classes);
/**
* Enable event
@ -561,12 +561,30 @@ public final class JVM {
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
*/
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
*
@ -575,24 +593,24 @@ public final class JVM {
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 handler the handler, may be {@code null}
* @param configuration the configuration, may be {@code null}
*
* @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}
*
* @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.

@ -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.
*
* 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 jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.internal.event.EventConfiguration;
import jdk.jfr.internal.instrument.JDKEvents;
/**
* All upcalls from the JVM should go through this class.
*
@ -40,9 +39,16 @@ final class JVMUpcalls {
*
* @param traceId
* Id of the class
* @param dummy
* (not used but needed since invoke infrastructure in native
* uses same signature bytesForEagerInstrumentation)
* @param dummy1
* not used, but act as padding so bytesForEagerInstrumentation and
* 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
* class being retransformed
* @param oldBytes
@ -50,17 +56,19 @@ final class JVMUpcalls {
* @return byte code to use
* @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 {
if (jdk.internal.event.Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
EventHandler handler = Utils.getHandler(clazz.asSubclass(jdk.internal.event.Event.class));
if (handler == null) {
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request.");
EventWriterKey.ensureEventWriterFactory();
EventConfiguration configuration = Utils.getConfiguration(clazz.asSubclass(jdk.internal.event.Event.class));
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
return oldBytes;
}
boolean bootClassLoader = clazz.getClassLoader() == null;
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();
ASMToolkit.logASM(clazz.getName(), 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());
}
return oldBytes;
}
/**
@ -88,13 +95,13 @@ final class JVMUpcalls {
* @return byte code to use
* @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()) {
return oldBytes;
}
String eventName = "<Unknown>";
try {
EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId);
EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId, bootClassLoader, true);
eventName = ei.getEventName();
if (!forceInstrumentation) {
// Assume we are recording
@ -107,15 +114,8 @@ final class JVMUpcalls {
return oldBytes;
}
}
// Corner case when we are forced to generate bytecode. We can't reference the event
// handler in #isEnabled() before event class has been registered, so we add a
// guard against a null reference.
ei.setGuardHandler(true);
EventWriterKey.ensureEventWriterFactory();
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();
ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes);
return bytes;

@ -25,12 +25,11 @@
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.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
@ -39,6 +38,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.jfr.AnnotationElement;
import jdk.jfr.Event;
@ -47,9 +47,11 @@ import jdk.jfr.Period;
import jdk.jfr.StackTrace;
import jdk.jfr.Threshold;
import jdk.jfr.ValueDescriptor;
import jdk.jfr.SettingControl;
import jdk.jfr.internal.EventInstrumentation.SettingInfo;
import jdk.jfr.internal.RequestEngine.RequestHook;
import jdk.jfr.internal.consumer.RepositoryFiles;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.internal.event.EventConfiguration;
public final class MetadataRepository {
@ -61,10 +63,10 @@ public final class MetadataRepository {
private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
private final SettingsManager settingsManager = new SettingsManager();
private final Map<String, Class<? extends Event>> mirrors = new HashMap<>();
private Constructor<EventConfiguration> cachedEventConfigurationConstructor;
private boolean staleMetadata = true;
private boolean unregistered;
private long lastUnloaded = -1;
private Instant outputChange;
public MetadataRepository() {
initializeJVMEventTypes();
@ -100,11 +102,11 @@ public final class MetadataRepository {
}
public synchronized List<EventType> getRegisteredEventTypes() {
List<EventHandler> handlers = getEventHandlers();
List<EventType> eventTypes = new ArrayList<>(handlers.size() + nativeEventTypes.size());
for (EventHandler h : handlers) {
if (h.isRegistered()) {
eventTypes.add(h.getEventType());
List<EventConfiguration> configurations = getEventConfigurations();
List<EventType> eventTypes = new ArrayList<>(configurations.size() + nativeEventTypes.size());
for (EventConfiguration ec : configurations) {
if (ec.isRegistered()) {
eventTypes.add(ec.getEventType());
}
}
for (EventType t : nativeEventTypes) {
@ -116,18 +118,18 @@ public final class MetadataRepository {
}
public synchronized EventType getEventType(Class<? extends jdk.internal.event.Event> eventClass) {
EventHandler h = getHandler(eventClass, false);
if (h != null && h.isRegistered()) {
return h.getEventType();
EventConfiguration ec = getConfiguration(eventClass, false);
if (ec != null && ec.isRegistered()) {
return ec.getEventType();
}
throw new IllegalStateException("Event class " + eventClass.getName() + " is not registered");
}
public synchronized void unregister(Class<? extends Event> eventClass) {
Utils.checkRegisterPermission();
EventHandler handler = getHandler(eventClass, false);
if (handler != null) {
handler.setRegistered(false);
EventConfiguration configuration = getConfiguration(eventClass, false);
if (configuration != null) {
configuration.getPlatformEventType().setRegistered(false);
}
// 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) {
Utils.checkRegisterPermission();
EventHandler handler = getHandler(eventClass, true);
if (handler == null) {
if (jvm.isExcluded(eventClass)) {
// 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) {
// don't register mirrors
// Don't register mirror classes.
return null;
}
PlatformEventType pe = findMirrorType(eventClass);
handler = makeHandler(eventClass, pe, dynamicAnnotations, dynamicFields);
configuration = makeConfiguration(eventClass, pe, dynamicAnnotations, dynamicFields);
}
handler.setRegistered(true);
typeLibrary.addType(handler.getPlatformEventType());
configuration.getPlatformEventType().setRegistered(true);
typeLibrary.addType(configuration.getPlatformEventType());
if (jvm.isRecording()) {
settingsManager.setEventControl(handler.getEventControl());
settingsManager.setEventControl(configuration.getEventControl());
settingsManager.updateRetransform(Collections.singletonList((eventClass)));
}
setStaleMetadata();
return handler.getEventType();
return configuration.getEventType();
}
private PlatformEventType findMirrorType(Class<? extends jdk.internal.event.Event> eventClass) throws InternalError {
@ -170,40 +180,52 @@ public final class MetadataRepository {
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);
SecuritySupport.makeVisibleToJFR(eventClass);
if (ensureInitialized) {
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 {
SecuritySupport.addHandlerExport(eventClass);
private EventConfiguration newEventConfiguration(EventType eventType, EventControl ec, SettingControl[] settings) {
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) {
pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields);
}
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
EventControl ec = new EventControl(pEventType, eventClass);
Class<? extends EventHandler> handlerClass = null;
try {
String eventHandlerName = EventHandlerCreator.makeEventHandlerName(eventType.getId());
handlerClass = Class.forName(eventHandlerName, false, Event.class.getClassLoader()).asSubclass(EventHandler.class);
// Created eagerly on class load, tag as instrumented
pEventType.setInstrumented();
Logger.log(JFR_SYSTEM, DEBUG, "Found existing event handler for " + eventType.getName());
} catch (ClassNotFoundException cne) {
EventHandlerCreator ehc = new EventHandlerCreator(eventType.getId(), ec.getSettingInfos(), eventType, eventClass);
handlerClass = ehc.makeEventHandlerClass();
Logger.log(LogTag.JFR_SYSTEM, DEBUG, "Created event handler for " + eventType.getName());
}
EventHandler handler = EventHandlerCreator.instantiateEventHandler(handlerClass, true, eventType, ec);
Utils.setHandler(eventClass, handler);
return handler;
List<SettingInfo> settingInfos = ec.getSettingInfos();
SettingControl[] settings = new SettingControl[settingInfos.size()];
int index = 0;
for (var settingInfo : settingInfos) {
settings[index++] = settingInfo.settingControl();
}
EventConfiguration configuration = newEventConfiguration(eventType, ec, settings);
PlatformEventType pe = configuration.getPlatformEventType();
pe.setRegistered(true);
if (jvm.isInstrumented(eventClass)) {
pe.setInstrumented();
}
Utils.setConfiguration(eventClass, configuration);
return configuration;
}
public synchronized void setSettings(List<Map<String, String>> list) {
settingsManager.setSettings(list);
}
@ -219,7 +241,7 @@ public final class MetadataRepository {
ArrayList<EventControl> controls = new ArrayList<>(eventClasses.size() + nativeControls.size());
controls.addAll(nativeControls);
for (Class<? extends jdk.internal.event.Event> clazz : eventClasses) {
EventHandler eh = Utils.getHandler(clazz);
EventConfiguration eh = Utils.getConfiguration(clazz);
if (eh != null) {
controls.add(eh.getEventControl());
}
@ -232,16 +254,16 @@ public final class MetadataRepository {
staleMetadata = false;
}
private static List<EventHandler> getEventHandlers() {
private static List<EventConfiguration> getEventConfigurations() {
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) {
EventHandler eh = Utils.getHandler(clazz);
if (eh != null) {
eventHandlers.add(eh);
EventConfiguration ec = Utils.getConfiguration(clazz);
if (ec != null) {
eventConfigurations.add(ec);
}
}
return eventHandlers;
return eventConfigurations;
}
private byte[] getBinaryRepresentation() {

@ -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.
*
* 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;
}
private static boolean isUsingHandler(String name) {
private static boolean isUsingConfiguration(String name) {
switch (name) {
case Type.EVENT_NAME_PREFIX + "SocketRead" :
case Type.EVENT_NAME_PREFIX + "SocketWrite" :
@ -102,11 +102,11 @@ public final class PlatformEventType extends Type {
if (isExceptionEvent(name)) {
return 4;
}
if (isUsingHandler(name)) {
if (isUsingConfiguration(name)) {
return 3;
}
}
return 4;
return 3;
}
public void add(SettingDescriptor settingDescriptor) {

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

@ -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.
*
* 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 jdk.jfr.internal.EventControl.NamedControl;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.internal.event.EventConfiguration;
final class SettingsManager {
@ -154,9 +154,9 @@ final class SettingsManager {
public void updateRetransform(List<Class<? extends jdk.internal.event.Event>> eventClasses) {
List<Class<?>> classes = new ArrayList<>();
for(Class<? extends jdk.internal.event.Event> eventClass: eventClasses) {
EventHandler eh = Utils.getHandler(eventClass);
if (eh != null ) {
PlatformEventType eventType = eh.getPlatformEventType();
EventConfiguration ec = Utils.getConfiguration(eventClass);
if (ec != null ) {
PlatformEventType eventType = ec.getPlatformEventType();
if (eventType.isMarkedForInstrumentation()) {
classes.add(eventClass);
eventType.markForInstrumentation(false);

@ -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.
*
* 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;
public final class StringPool {
static final int MIN_LIMIT = 16;
static final int MAX_LIMIT = 128; /* 0 MAX means disabled */
public static final int MIN_LIMIT = 16;
public static final int MAX_LIMIT = 128; /* 0 MAX means disabled */
private static final long DO_NOT_POOL = -1;
private static final SimpleStringIdPool sp = new SimpleStringIdPool();
static long addString(String s) {
public static long addString(String s) {
return sp.addString(s);
}
static void reset() {
public static void reset() {
sp.reset();
}

@ -62,7 +62,7 @@ import jdk.jfr.Event;
import jdk.jfr.FlightRecorderPermission;
import jdk.jfr.Recording;
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.StackTraceSetting;
import jdk.jfr.internal.settings.ThresholdSetting;
@ -74,7 +74,7 @@ public final class Utils {
private static final String OFF = "off";
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 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 ACCESS_FLIGHT_RECORDER = "accessFlightRecorder";
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());
}
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);
Object handler = JVM.getJVM().getHandler(eventClass);
if (handler == null || handler instanceof EventHandler) {
return (EventHandler) handler;
Object configuration = JVM.getJVM().getConfiguration(eventClass);
if (configuration == null || configuration instanceof EventConfiguration) {
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);
if (!JVM.getJVM().setHandler(eventClass, handler)) {
throw new InternalError("Could not set event handler");
if (!JVM.getJVM().setConfiguration(eventClass, configuration)) {
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");
}
if (SAVE_GENERATED) {
className = className.substring(className.lastIndexOf("/") + 1, className.length());
try {
try (FileOutputStream fos = new FileOutputStream(className + ".class")) {
fos.write(bytes);

@ -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();
}
}

@ -23,17 +23,36 @@
* questions.
*/
package jdk.jfr.internal;
package jdk.jfr.internal.event;
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;
/**
* Class must reside in a package with package restriction.
*
* Users should not have direct access to underlying memory.
*
*/
// User code should not be able to get access to an EventWriter instance as it
// would allow it to write arbitrary data into buffers, potentially from
// different threads.
//
// 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 {
// Event may not exceed size for a padded integer
@ -55,9 +74,9 @@ public final class EventWriter {
private boolean flushOnEnd;
private boolean largeSize = false;
public static EventWriter getEventWriter() {
EventWriter ew = JVM.getEventWriter();
return ew != null ? ew : JVM.newEventWriter();
// User code must not be able to instantiate
private EventWriter() {
threadID = 0;
}
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) {
putByte(StringParser.Encoding.NULL.byteValue());
return;
@ -237,12 +256,19 @@ public final class EventWriter {
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) {
// thread is excluded from writing events
return false;
}
this.eventType = eventType;
this.eventType = configuration.getPlatformEventType();
reserveEventSizeField();
putLong(eventType.getId());
return true;

@ -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);
}
}

@ -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.
*
* 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.nio.ByteBuffer;
import jdk.jfr.events.Handlers;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.events.FileForceEvent;
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.
@ -45,19 +48,19 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void force(boolean metaData) throws IOException {
EventHandler handler = Handlers.FILE_FORCE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_FORCE;
if (!eventConfiguration.isEnabled()) {
force(metaData);
return;
}
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
force(metaData);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, metaData);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileForceEvent.commit(start, duration, path, metaData);
}
}
}
@ -65,22 +68,22 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int read(ByteBuffer dst) throws IOException {
EventHandler handler = Handlers.FILE_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!eventConfiguration.isEnabled()) {
return read(dst);
}
int bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesRead = read(dst);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true);
FileReadEvent.commit(start, duration, path, 0L, true);
} else {
handler.write(start, duration, path, bytesRead, false);
FileReadEvent.commit(start, duration, path, bytesRead, false);
}
}
}
@ -90,22 +93,22 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int read(ByteBuffer dst, long position) throws IOException {
EventHandler handler = Handlers.FILE_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!eventConfiguration.isEnabled()) {
return read(dst, position);
}
int bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesRead = read(dst, position);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true);
FileReadEvent.commit(start, duration, path, 0L, true);
} else {
handler.write(start, duration, path, bytesRead, false);
FileReadEvent.commit(start, duration, path, bytesRead, false);
}
}
}
@ -115,22 +118,22 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
EventHandler handler = Handlers.FILE_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!eventConfiguration.isEnabled()) {
return read(dsts, offset, length);
}
long bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesRead = read(dsts, offset, length);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true);
FileReadEvent.commit(start, duration, path, 0L, true);
} else {
handler.write(start, duration, path, bytesRead, false);
FileReadEvent.commit(start, duration, path, bytesRead, false);
}
}
}
@ -140,20 +143,20 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int write(ByteBuffer src) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
return write(src);
}
int bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesWritten = write(src);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten > 0 ? bytesWritten : 0;
handler.write(start, duration, path, bytes);
FileWriteEvent.commit(start, duration, path, bytes);
}
}
return bytesWritten;
@ -162,21 +165,21 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int write(ByteBuffer src, long position) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
return write(src, position);
}
int bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesWritten = write(src, position);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten > 0 ? bytesWritten : 0;
handler.write(start, duration, path, bytes);
FileWriteEvent.commit(start, duration, path, bytes);
}
}
return bytesWritten;
@ -185,20 +188,20 @@ final class FileChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
return write(srcs, offset, length);
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesWritten = write(srcs, offset, length);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten > 0 ? bytesWritten : 0;
handler.write(start, duration, path, bytes);
FileWriteEvent.commit(start, duration, path, bytes);
}
}
return bytesWritten;

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

@ -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.
*
* 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 jdk.jfr.events.Handlers;
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.
@ -44,21 +45,21 @@ final class FileOutputStreamInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void write(int b) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
write(b);
return;
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
write(b);
bytesWritten = 1;
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileWriteEvent.commit(start, duration, path, bytesWritten);
}
}
}
@ -66,21 +67,21 @@ final class FileOutputStreamInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void write(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
write(b);
return;
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
write(b);
bytesWritten = b.length;
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileWriteEvent.commit(start, duration, path, bytesWritten);
}
}
}
@ -88,21 +89,21 @@ final class FileOutputStreamInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void write(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
write(b, off, len);
return;
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
write(b, off, len);
bytesWritten = len;
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileWriteEvent.commit(start, duration, path, bytesWritten);
}
}
}

@ -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.
*
* 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 jdk.jfr.events.Handlers;
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.
@ -44,8 +46,8 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int read() throws IOException {
EventHandler handler = Handlers.FILE_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!eventConfiguration.isEnabled()) {
return read();
}
int result = 0;
@ -53,7 +55,7 @@ final class RandomAccessFileInstrumentor {
boolean endOfFile = false;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
result = read();
if (result < 0) {
endOfFile = true;
@ -61,9 +63,9 @@ final class RandomAccessFileInstrumentor {
bytesRead = 1;
}
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesRead, endOfFile);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileReadEvent.commit(start, duration, path, bytesRead, endOfFile);
}
}
return result;
@ -72,22 +74,22 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int read(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!eventConfiguration.isEnabled()) {
return read(b);
}
int bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesRead = read(b);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true);
FileReadEvent.commit(start, duration, path, 0L, true);
} else {
handler.write(start, duration, path, bytesRead, false);
FileReadEvent.commit(start, duration, path, bytesRead, false);
}
}
}
@ -97,22 +99,22 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int read(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_READ;
if (!eventConfiguration.isEnabled()) {
return read(b, off, len);
}
int bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesRead = read(b, off, len);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
if (bytesRead < 0) {
handler.write(start, duration, path, 0L, true);
FileReadEvent.commit(start, duration, path, 0L, true);
} else {
handler.write(start, duration, path, bytesRead, false);
FileReadEvent.commit(start, duration, path, bytesRead, false);
}
}
}
@ -122,21 +124,21 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void write(int b) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
write(b);
return;
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
write(b);
bytesWritten = 1;
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileWriteEvent.commit(start, duration, path, bytesWritten);
}
}
}
@ -144,21 +146,21 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void write(byte b[]) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
write(b);
return;
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
write(b);
bytesWritten = b.length;
} finally {
long duration = EventHandler.timestamp();
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten);
long duration = EventConfiguration.timestamp();
if (eventConfiguration.shouldCommit(duration)) {
FileWriteEvent.commit(start, duration, path, bytesWritten);
}
}
}
@ -166,21 +168,21 @@ final class RandomAccessFileInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public void write(byte b[], int off, int len) throws IOException {
EventHandler handler = Handlers.FILE_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.FILE_WRITE;
if (!eventConfiguration.isEnabled()) {
write(b, off, len);
return;
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
write(b, off, len);
bytesWritten = len;
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
handler.write(start, duration, path, bytesWritten);
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
FileWriteEvent.commit(start, duration, path, bytesWritten);
}
}
}

@ -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.
*
* 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.UnixDomainSocketAddress;
import java.nio.ByteBuffer;
import jdk.jfr.events.Handlers;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.events.EventConfigurations;
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.
@ -45,18 +47,18 @@ final class SocketChannelImplInstrumentor {
@SuppressWarnings("deprecation")
@JIInstrumentationMethod
public int read(ByteBuffer dst) throws IOException {
EventHandler handler = Handlers.SOCKET_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.SOCKET_READ;
if (!eventConfiguration.isEnabled()) {
return read(dst);
}
int bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();;
bytesRead = read(dst);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) {
String hostString = isa.getAddress().toString();
@ -66,17 +68,17 @@ final class SocketChannelImplInstrumentor {
String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort();
if (bytesRead < 0) {
handler.write(start, duration, host, address, port, 0, 0L, true);
SocketReadEvent.commit(start, duration, host, address, port, 0, 0L, true);
} else {
handler.write(start, duration, host, address, port, 0, bytesRead, false);
SocketReadEvent.commit(start, duration, host, address, port, 0, bytesRead, false);
}
} else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
String path = "[" + udsa.getPath().toString() + "]";
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 {
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")
@JIInstrumentationMethod
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
EventHandler handler = Handlers.SOCKET_READ;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.SOCKET_READ;
if (!eventConfiguration.isEnabled()) {
return read(dsts, offset, length);
}
long bytesRead = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesRead = read(dsts, offset, length);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) {
String hostString = isa.getAddress().toString();
@ -108,17 +110,17 @@ final class SocketChannelImplInstrumentor {
String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort();
if (bytesRead < 0) {
handler.write(start, duration, host, address, port, 0, 0L, true);
SocketReadEvent.commit(start, duration, host, address, port, 0, 0L, true);
} else {
handler.write(start, duration, host, address, port, 0, bytesRead, false);
SocketReadEvent.commit(start, duration, host, address, port, 0, bytesRead, false);
}
} else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
String path = "[" + udsa.getPath().toString() + "]";
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 {
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")
@JIInstrumentationMethod
public int write(ByteBuffer buf) throws IOException {
EventHandler handler = Handlers.SOCKET_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.SOCKET_WRITE;
if (!eventConfiguration.isEnabled()) {
return write(buf);
}
int bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesWritten = write(buf);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten < 0 ? 0 : bytesWritten;
SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) {
@ -150,11 +152,11 @@ final class SocketChannelImplInstrumentor {
String host = hostString.substring(0, delimiterIndex);
String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort();
handler.write(start, duration, host, address, port, bytes);
SocketWriteEvent.commit(start, duration, host, address, port, bytes);
} else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
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")
@JIInstrumentationMethod
public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
EventHandler handler = Handlers.SOCKET_WRITE;
if (!handler.isEnabled()) {
EventConfiguration eventConfiguration = EventConfigurations.SOCKET_WRITE;
if (!eventConfiguration.isEnabled()) {
return write(srcs, offset, length);
}
long bytesWritten = 0;
long start = 0;
try {
start = EventHandler.timestamp();
start = EventConfiguration.timestamp();
bytesWritten = write(srcs, offset, length);
} finally {
long duration = EventHandler.timestamp() - start;
if (handler.shouldCommit(duration)) {
long duration = EventConfiguration.timestamp() - start;
if (eventConfiguration.shouldCommit(duration)) {
long bytes = bytesWritten < 0 ? 0 : bytesWritten;
SocketAddress remoteAddress = getRemoteAddress();
if (remoteAddress instanceof InetSocketAddress isa) {
@ -190,11 +192,11 @@ final class SocketChannelImplInstrumentor {
String host = hostString.substring(0, delimiterIndex);
String address = hostString.substring(delimiterIndex + 1);
int port = isa.getPort();
handler.write(start, duration, host, address, port, bytes);
SocketWriteEvent.commit(start, duration, host, address, port, bytes);
} else {
UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress;
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);
}
}
}

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

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

@ -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.
*
* 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 jdk.jfr.events.Handlers;
import jdk.jfr.internal.handlers.EventHandler;
import jdk.jfr.events.EventConfigurations;
import jdk.jfr.events.ErrorThrownEvent;
import jdk.jfr.events.ExceptionThrownEvent;
import jdk.jfr.internal.event.EventConfiguration;
public final class ThrowableTracer {
@ -38,24 +40,24 @@ public final class ThrowableTracer {
if (e instanceof OutOfMemoryError) {
return;
}
long timestamp = EventHandler.timestamp();
long timestamp = EventConfiguration.timestamp();
EventHandler h1 = Handlers.ERROR_THROWN;
if (h1.isEnabled()) {
h1.write(timestamp, 0L, message, e.getClass());
EventConfiguration eventConfiguration1 = EventConfigurations.ERROR_THROWN;
if (eventConfiguration1.isEnabled()) {
ErrorThrownEvent.commit(timestamp, 0L, message, e.getClass());
}
EventHandler h2 = Handlers.EXCEPTION_THROWN;
if (h2.isEnabled()) {
h2.write(timestamp, 0L, message, e.getClass());
EventConfiguration eventConfiguration2 = EventConfigurations.EXCEPTION_THROWN;
if (eventConfiguration2.isEnabled()) {
ExceptionThrownEvent.commit(timestamp, 0L, message, e.getClass());
}
numThrowables.incrementAndGet();
}
public static void traceThrowable(Throwable t, String message) {
EventHandler h = Handlers.EXCEPTION_THROWN;
if (h.isEnabled()) {
long timestamp = EventHandler.timestamp();
h.write(timestamp, 0L, message, t.getClass());
EventConfiguration eventConfiguration = EventConfigurations.EXCEPTION_THROWN;
if (eventConfiguration.isEnabled()) {
long timestamp = EventConfiguration.timestamp();
ExceptionThrownEvent.commit(timestamp, 0L, message, t.getClass());
}
numThrowables.incrementAndGet();
}

@ -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 {
}

@ -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();
}
}

@ -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();
}
}

@ -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();
}
}

@ -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 {
}

@ -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");
}
}

@ -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");
}
}

@ -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");
}
}

@ -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);
}
}

@ -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.
*
* 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 {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:jfr+system+bytecode=trace", "-XX:StartFlightRecording", "-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("extends jdk/jfr/internal/handlers/EventHandler");
output.shouldContain("extends jdk/jfr/events/AbstractJDKEvent");
}
}

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,27 +23,298 @@
package jdk.jfr.jvm;
import static jdk.test.lib.Asserts.assertNotNull;
import jdk.jfr.internal.EventWriter;
import jdk.jfr.internal.JVM;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
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
* @key jfr
* @requires vm.hasJFR
* @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/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 static void main(String... args) {
JVM jvm = JVM.getJVM();
jvm.createNativeJFR();
EventWriter writer = EventWriter.getEventWriter();
assertNotNull(writer, "EventWriter should not be null");
jvm.destroyNativeJFR();
static class InitializationEvent extends Event {
}
public static void main(String... args) throws Throwable {
try (Recording r = new Recording()) {
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();
}
}

@ -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")
}
}

@ -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.
}
}
}
}

@ -60,7 +60,7 @@ public class TestJFRIntrinsic {
TestJFRIntrinsic() throws Exception {
// 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 {