8282420: JFR: Remove event handlers
Reviewed-by: mgronlun
This commit is contained in:
parent
04bba07d65
commit
0f3773635d
src
hotspot/share
c1
ci
interpreter
jfr
instrumentation
jfrEventClassTransformer.cppjfrEventClassTransformer.hppjfrJvmtiAgent.cppjfrResolution.cppjfrResolution.hpp
jfr.cppjfr.hppjni
jfrJavaSupport.cppjfrJavaSupport.hppjfrJniMethod.cppjfrJniMethod.hppjfrJniMethodRegistration.cppjfrUpcalls.cppjfrUpcalls.hpp
recorder/checkpoint/types/traceid
support
writers
opto
jdk.jfr/share/classes/jdk/jfr
EventFactory.java
events
ErrorThrownEvent.javaEventConfigurations.javaExceptionThrownEvent.javaFileForceEvent.javaFileReadEvent.javaFileWriteEvent.javaSocketReadEvent.javaSocketWriteEvent.java
internal
ASMToolkit.javaBits.javaControl.javaEventClassBuilder.javaEventControl.javaEventHandlerCreator.javaEventInstrumentation.javaEventWriterFactoryRecipe.javaEventWriterKey.javaEventWriterMethod.javaJVM.javaJVMUpcalls.javaMetadataRepository.javaPlatformEventType.javaSecuritySupport.javaSettingsManager.javaStringPool.javaUtils.java
event
handlers
instrument
test/jdk/jdk/jfr/jvm
E.javaMyCommitRegisteredFalseEvent.javaMyCommitRegisteredTrueEvent.javaNonEvent.javaPlaceholderEventWriter.javaPlaceholderEventWriterFactory.javaRegisteredFalseEvent.javaRegisteredTrueEvent.javaStaticCommitEvent.javaTestEventWriterLog.javaTestGetEventWriter.javaTestGetEventWriterPackage.javaTestGetEventWriterReflection.javaTestJFRIntrinsic.java
@ -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;
|
||||
|
103
src/hotspot/share/jfr/instrumentation/jfrResolution.cpp
Normal file
103
src/hotspot/share/jfr/instrumentation/jfrResolution.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "c1/c1_GraphBuilder.hpp"
|
||||
#include "ci/ciKlass.hpp"
|
||||
#include "ci/ciMethod.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "jfr/instrumentation/jfrResolution.hpp"
|
||||
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
|
||||
#include "oops/method.inline.hpp"
|
||||
#include "opto/parse.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/vframe.inline.hpp"
|
||||
|
||||
static const char* const link_error_msg = "illegal access linking method 'jdk.jfr.internal.event.EventWriterFactory.getEventWriter(long)'";
|
||||
|
||||
static const Method* ljf_sender_method(JavaThread* jt) {
|
||||
assert(jt != nullptr, "invariant");
|
||||
if (!jt->has_last_Java_frame()) {
|
||||
return nullptr;
|
||||
}
|
||||
const vframeStream ljf(jt, false, false);
|
||||
return ljf.method();
|
||||
}
|
||||
|
||||
void JfrResolution::on_runtime_resolution(const CallInfo & info, TRAPS) {
|
||||
assert(info.selected_method() != nullptr, "invariant");
|
||||
assert(info.resolved_klass() != nullptr, "invariant");
|
||||
static const Symbol* const event_writer_method_name = vmSymbols::getEventWriter_name();
|
||||
assert(event_writer_method_name != nullptr, "invariant");
|
||||
// Fast path
|
||||
if (info.selected_method()->name() != event_writer_method_name) {
|
||||
return;
|
||||
}
|
||||
static const Symbol* const event_writer_factory_klass_name = vmSymbols::jdk_jfr_internal_event_EventWriterFactory();
|
||||
assert(event_writer_factory_klass_name != nullptr, "invariant");
|
||||
if (info.resolved_klass()->name() != event_writer_factory_klass_name) {
|
||||
return;
|
||||
}
|
||||
// Attempting to link against jdk.jfr.internal.event.EventWriterFactory.getEventWriter().
|
||||
// The sender, i.e. the method attempting to link, is in the ljf (if one exists).
|
||||
const Method* const sender = ljf_sender_method(THREAD);
|
||||
if (sender == nullptr) {
|
||||
// A compiler thread is doing linktime resolution but there is no information about the sender available.
|
||||
// For the compiler threads, the sender is instead found as part of bytecode parsing.
|
||||
return;
|
||||
}
|
||||
// Is the sender method blessed for linkage?
|
||||
if (IS_METHOD_BLESSED(sender)) {
|
||||
return;
|
||||
}
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), link_error_msg);
|
||||
}
|
||||
|
||||
static inline bool is_compiler_linking_event_writer(const ciKlass * holder, const ciMethod * target) {
|
||||
assert(holder != nullptr, "invariant");
|
||||
assert(target != nullptr, "invariant");
|
||||
static const Symbol* const event_writer_factory_klass_name = vmSymbols::jdk_jfr_internal_event_EventWriterFactory();
|
||||
assert(event_writer_factory_klass_name != nullptr, "invariant");
|
||||
if (holder->name()->get_symbol() != event_writer_factory_klass_name) {
|
||||
return false;
|
||||
}
|
||||
static const Symbol* const event_writer_method_name = vmSymbols::getEventWriter_name();
|
||||
assert(event_writer_method_name != nullptr, "invariant");
|
||||
return target->name()->get_symbol() == event_writer_method_name;
|
||||
}
|
||||
|
||||
// C1
|
||||
void JfrResolution::on_c1_resolution(const GraphBuilder * builder, const ciKlass * holder, const ciMethod * target) {
|
||||
if (is_compiler_linking_event_writer(holder, target) && !IS_METHOD_BLESSED(builder->method()->get_Method())) {
|
||||
builder->bailout(link_error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// C2
|
||||
void JfrResolution::on_c2_resolution(const Parse * parse, const ciKlass * holder, const ciMethod * target) {
|
||||
if (is_compiler_linking_event_writer(holder, target) && !IS_METHOD_BLESSED(parse->method()->get_Method())) {
|
||||
parse->C->record_failure(link_error_msg);
|
||||
}
|
||||
}
|
45
src/hotspot/share/jfr/instrumentation/jfrResolution.hpp
Normal file
45
src/hotspot/share/jfr/instrumentation/jfrResolution.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP
|
||||
#define SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
class CallInfo;
|
||||
class ciKlass;
|
||||
class ciMethod;
|
||||
class GraphBuilder;
|
||||
class Parse;
|
||||
|
||||
class JfrResolution : AllStatic {
|
||||
public:
|
||||
static void on_runtime_resolution(const CallInfo & info, TRAPS);
|
||||
static void on_c1_resolution(const GraphBuilder * builder, const ciKlass * holder, const ciMethod * target);
|
||||
static void on_c2_resolution(const Parse * parse, const ciKlass * holder, const ciMethod * target);
|
||||
};
|
||||
|
||||
#endif // SHARE_JFR_INSTRUMENTATION_JFRRESOLUTION_HPP
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
123
src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterKey.java
Normal file
123
src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterKey.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
// Purpose of this class is NOT to create a cryptographically
|
||||
// strong random number. but to quickly generate a value hard to guess
|
||||
// without the need to load classes or have an impact on security
|
||||
// related events, like SecureRandom::getAlgorithm("NativePRNGNonBlocking") does
|
||||
public final class EventWriterKey {
|
||||
private final static long KEY = createKey();
|
||||
private static boolean loaded;
|
||||
private static boolean logged;
|
||||
|
||||
public static long getKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
private static long createKey() {
|
||||
JVM jvm = JVM.getJVM();
|
||||
long r = mixMurmur64(System.identityHashCode(new Object()));
|
||||
r = 31 * r + mixMurmur64(jvm.getPid().hashCode());
|
||||
r = 31 * r + mixMurmur64(System.nanoTime());
|
||||
r = 31 * r + mixMurmur64(Thread.currentThread().threadId());
|
||||
r = 31 * r + mixMurmur64(System.currentTimeMillis());
|
||||
r = 31 * r + mixMurmur64(jvm.getTypeId(JVM.class));
|
||||
r = 31 * r + mixMurmur64(JVM.counterTime());
|
||||
return mixMurmur64(r);
|
||||
}
|
||||
|
||||
// Copied from jdk.internal.util.random.RandomSupport.mixMurmur64(long)
|
||||
private static long mixMurmur64(long z) {
|
||||
z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
|
||||
z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
|
||||
return z ^ (z >>> 33);
|
||||
}
|
||||
|
||||
public static void ensureEventWriterFactory() {
|
||||
if (loaded) {
|
||||
return;
|
||||
}
|
||||
String name = "/jdk/jfr/internal/EventWriterFactoryRecipe.class";
|
||||
try (InputStream is = EventWriterKey.class.getResourceAsStream(name)) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
bytes = replace(bytes,
|
||||
"jdk/jfr/internal/EventWriterFactoryRecipe",
|
||||
"jdk/jfr/internal/event/EventWriterFactory");
|
||||
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
|
||||
SecuritySupport.defineClass(c, bytes);
|
||||
loaded = true;
|
||||
} catch (Throwable e) {
|
||||
throw new InternalError("Could not read bytecode for " + name, e);
|
||||
}
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "EventWriterFactory created");
|
||||
}
|
||||
|
||||
// Starve the system of resources to prevent further attempts.
|
||||
// Note, code that have the capability to invoke this method
|
||||
// could spin in a loop anyway. Alternatives, such as System.exit(1),
|
||||
// may provide caller with additional capabilities.
|
||||
public static void block() {
|
||||
// Making this field variable a local variable leads to CTW failure
|
||||
logged = false;
|
||||
while (true) {
|
||||
try {
|
||||
if (!logged) {
|
||||
// Only log once to prevent flooding of log.
|
||||
logged = true;
|
||||
// Purposely don't call Thread::getName() since it can be overridden
|
||||
Logger.log(LogTag.JFR, LogLevel.ERROR, "Malicious attempt to access JFR buffers. Stopping thread from further execution.");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Ensure code can't break out and retry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] replace(byte[] bytes, String match, String replacement) {
|
||||
if (match.length() != replacement.length()) {
|
||||
throw new IllegalArgumentException("Match must be same size as replacement");
|
||||
}
|
||||
for (int i = 0; i < bytes.length - match.length(); i++) {
|
||||
if (match(bytes, i, match)) {
|
||||
for (int j = 0; j < replacement.length(); j++) {
|
||||
bytes[i + j] = (byte) replacement.charAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static boolean match(byte[] bytes, int offset, String text) {
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
if (bytes[offset + i] != text.charAt(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
34
test/jdk/jdk/jfr/jvm/E.java
Normal file
34
test/jdk/jdk/jfr/jvm/E.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
//Purpose of this class is to have something to
|
||||
//statically link against for TestGetEventWriter.
|
||||
//
|
||||
// When the class is loaded "jdk.jfr.jvm.E" will be
|
||||
// replaced with "jdk.jfr.Event"
|
||||
public class E {
|
||||
}
|
39
test/jdk/jdk/jfr/jvm/MyCommitRegisteredFalseEvent.java
Normal file
39
test/jdk/jdk/jfr/jvm/MyCommitRegisteredFalseEvent.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
import jdk.jfr.Registered;
|
||||
|
||||
// Class used by TestGetEventWriter
|
||||
@Registered(false)
|
||||
public class MyCommitRegisteredFalseEvent extends E implements Runnable {
|
||||
public void myCommit() {
|
||||
PlaceholderEventWriterFactory.getEventWriter(4711L);
|
||||
throw new RuntimeException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
myCommit();
|
||||
}
|
||||
}
|
39
test/jdk/jdk/jfr/jvm/MyCommitRegisteredTrueEvent.java
Normal file
39
test/jdk/jdk/jfr/jvm/MyCommitRegisteredTrueEvent.java
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
import jdk.jfr.Registered;
|
||||
|
||||
// Class used by TestGetEventWriter
|
||||
@Registered(true)
|
||||
public class MyCommitRegisteredTrueEvent extends E implements Runnable {
|
||||
public void myCommit() {
|
||||
PlaceholderEventWriterFactory.getEventWriter(4711L);
|
||||
throw new RuntimeException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
myCommit();
|
||||
}
|
||||
}
|
36
test/jdk/jdk/jfr/jvm/NonEvent.java
Normal file
36
test/jdk/jdk/jfr/jvm/NonEvent.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
// Class used by TestGetEventWriter
|
||||
public class NonEvent implements Runnable {
|
||||
public void commit() {
|
||||
PlaceholderEventWriter ew = PlaceholderEventWriterFactory.getEventWriter(4711L);
|
||||
throw new RuntimeException("Should not reach here " + ew);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
commit();
|
||||
}
|
||||
}
|
33
test/jdk/jdk/jfr/jvm/PlaceholderEventWriter.java
Normal file
33
test/jdk/jdk/jfr/jvm/PlaceholderEventWriter.java
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
// Purpose of this class is to have something to
|
||||
// statically link against for TestGetEventWriter.
|
||||
//
|
||||
// When the class is loaded "jdk.jfr.jvm.PlaceholderEventWriter"
|
||||
// will be replaced with "jdk.jfr.internal.event.EventWriter"
|
||||
public class PlaceholderEventWriter {
|
||||
|
||||
}
|
35
test/jdk/jdk/jfr/jvm/PlaceholderEventWriterFactory.java
Normal file
35
test/jdk/jdk/jfr/jvm/PlaceholderEventWriterFactory.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
// Purpose of this class is to have something to
|
||||
// statically link against for TestGetEventWriter.
|
||||
//
|
||||
// When the class is loaded "jdk.jfr.jvm.PlaceholderEventWriterFactory"
|
||||
// will be replaced with "jdk.jfr.internal.event.EventWriterFactory"
|
||||
public class PlaceholderEventWriterFactory {
|
||||
|
||||
public static PlaceholderEventWriter getEventWriter(long value) {
|
||||
throw new RuntimeException("Test error, PlaceholderEventWriterFactory class should have been replaced with EventWriterFactory");
|
||||
}
|
||||
}
|
34
test/jdk/jdk/jfr/jvm/RegisteredFalseEvent.java
Normal file
34
test/jdk/jdk/jfr/jvm/RegisteredFalseEvent.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
import jdk.jfr.Registered;
|
||||
|
||||
// Class used by TestGetEventWriter
|
||||
@Registered(false)
|
||||
public class RegisteredFalseEvent extends E {
|
||||
public void commit() {
|
||||
PlaceholderEventWriterFactory.getEventWriter(4711L);
|
||||
throw new RuntimeException("Should not reach here");
|
||||
}
|
||||
}
|
34
test/jdk/jdk/jfr/jvm/RegisteredTrueEvent.java
Normal file
34
test/jdk/jdk/jfr/jvm/RegisteredTrueEvent.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
import jdk.jfr.Registered;
|
||||
|
||||
// Class used by TestGetEventWriter
|
||||
@Registered(true)
|
||||
public class RegisteredTrueEvent extends E {
|
||||
public void commit() {
|
||||
PlaceholderEventWriterFactory.getEventWriter(4711L);
|
||||
throw new RuntimeException("Should not reach here");
|
||||
}
|
||||
}
|
41
test/jdk/jdk/jfr/jvm/StaticCommitEvent.java
Normal file
41
test/jdk/jdk/jfr/jvm/StaticCommitEvent.java
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
// Class used by TestGetEventWriter
|
||||
public class StaticCommitEvent implements Runnable {
|
||||
|
||||
String message;
|
||||
|
||||
int value;
|
||||
|
||||
public static void commit(long start, long duration, String message, int value) {
|
||||
PlaceholderEventWriterFactory.getEventWriter(4711L);
|
||||
throw new RuntimeException("Should not reach here");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
commit(System.nanoTime(), 0L, "hello, world!", 4711);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
78
test/jdk/jdk/jfr/jvm/TestGetEventWriterPackage.java
Normal file
78
test/jdk/jdk/jfr/jvm/TestGetEventWriterPackage.java
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.FlightRecorder;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.Registered;
|
||||
/**
|
||||
* @test Tests that a module can't execute code in jdk.jfr.internal.event unless an event has been registered.
|
||||
* @key jfr
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib
|
||||
* @run main/othervm
|
||||
* --add-opens jdk.jfr/jdk.jfr.events=ALL-UNNAMED
|
||||
* jdk.jfr.jvm.TestGetEventWriterPackage
|
||||
*/
|
||||
public class TestGetEventWriterPackage {
|
||||
|
||||
@Registered(false)
|
||||
static class PackageUnlockEvent extends Event {
|
||||
}
|
||||
public static void main(String... args) throws Throwable {
|
||||
// --add-opens jdk.jfr/jdk.jfr.events=ALL-UNNAMED gives access to
|
||||
// the FileReadEvent class in the jdk.jfr module.
|
||||
// When JFR is initialized the FileReadEvent is registered and an EventConfiguration object
|
||||
// assigned to its static field eventConfiguration
|
||||
try (Recording r = new Recording()) {
|
||||
r.start();
|
||||
}
|
||||
// The tests gets the EventConfiguration object from the class
|
||||
Class<?>c = Class.forName("jdk.jfr.events.FileReadEvent");
|
||||
Field f = c.getDeclaredField("eventConfiguration");
|
||||
f.setAccessible(true);
|
||||
Object o = f.get(null);
|
||||
Class<?> clazz = Class.forName("jdk.jfr.internal.event.EventConfiguration");
|
||||
Method m = clazz.getDeclaredMethod("isRegistered", new Class[0]);
|
||||
// it then tries to execute a method on the object from the unnamed module
|
||||
try {
|
||||
System.out.println("Is registered: " + m.invoke(o, new Object[0]));
|
||||
throw new Exception("Did NOT expect unnamed module to be able to execute method in EventConfiguration object before event registration");
|
||||
} catch (IllegalAccessException iae) {
|
||||
// OK, as expected
|
||||
}
|
||||
// The registration makes the jdk.jfr.internal.event accessible
|
||||
FlightRecorder.register(PackageUnlockEvent.class);
|
||||
try {
|
||||
System.out.println("Is registered: " + m.invoke(o, new Object[0]));
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new Exception("Did expect unnamed module to be able to execute method in EventConfiguration object efter event registration", iae);
|
||||
}
|
||||
// If a Security Manager would be present, the caller would need
|
||||
// to have FlightRecorderPermission("registerEvent")
|
||||
}
|
||||
}
|
115
test/jdk/jdk/jfr/jvm/TestGetEventWriterReflection.java
Normal file
115
test/jdk/jdk/jfr/jvm/TestGetEventWriterReflection.java
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.jvm;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InaccessibleObjectException;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Registered;
|
||||
/**
|
||||
* @test Tests that reflective access works as (normally) expected
|
||||
* @key jfr
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib
|
||||
*
|
||||
* @run main/othervm jdk.jfr.jvm.TestGetEventWriterReflection
|
||||
*/
|
||||
public class TestGetEventWriterReflection {
|
||||
|
||||
@Registered(false)
|
||||
static class InitializeEvent extends Event {
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
testReflectionGetConstructor();
|
||||
testReflectionGetDeclaredConstructor();
|
||||
testReflectionGetDeclaredConstructorSetAccessible();
|
||||
testReflectionGetDeclaredFieldSetAccessible();
|
||||
}
|
||||
|
||||
// getConstructor() only return public members.
|
||||
private static void testReflectionGetConstructor() throws Exception {
|
||||
try {
|
||||
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
|
||||
Constructor<?> constructor = c.getConstructor(new Class[0]);
|
||||
throw new RuntimeException("Should not reach here " + constructor);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// OK, as expected. The constructor is private.
|
||||
}
|
||||
}
|
||||
|
||||
// getDeclaredConstructor() return also a private constructor.
|
||||
// Invoking a private constructor is an instance of IllegalAccess.
|
||||
private static void testReflectionGetDeclaredConstructor() throws Exception {
|
||||
try {
|
||||
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
|
||||
Constructor<?> constructor = c.getDeclaredConstructor(new Class[0]);
|
||||
constructor.newInstance();
|
||||
throw new RuntimeException("Should not reach here " + constructor);
|
||||
} catch (IllegalAccessException iae) {
|
||||
if (iae.getMessage().contains("""
|
||||
cannot access a member of class jdk.jfr.internal.event.EventWriter
|
||||
(in module jdk.jfr) with modifiers \"private\"
|
||||
""")) {
|
||||
// OK, as expected. Private protection in effect.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getDeclaredConstructor() return also a private constructor.
|
||||
// setAccessible(true) attempts to make the private constructor public for external access.
|
||||
// With JEP 403: Strongly Encapsulate JDK Internals, the module and package must first
|
||||
// be explicitly opened for setAccessible(true) to succeed.
|
||||
private static void testReflectionGetDeclaredConstructorSetAccessible() throws Exception {
|
||||
try {
|
||||
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
|
||||
Constructor<?> constructor = c.getDeclaredConstructor(new Class[0]);
|
||||
constructor.setAccessible(true);
|
||||
throw new RuntimeException("Should not reach here " + constructor);
|
||||
} catch (InaccessibleObjectException ioe) {
|
||||
if (ioe.getMessage().contains("module jdk.jfr does not \"opens jdk.jfr.internal.event")) {
|
||||
// OK, as expected. Even when using setAccessible(true), by default, the jdk.jfr module
|
||||
// is not open for reflective access to private members.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getDeclaredField() return also a private field.
|
||||
// setAccessible(true) attempts to make the private field public for external access.
|
||||
// With JEP 403: Strongly Encapsulate JDK Internals, the module and package must first
|
||||
// be explicitly opened for setAccessible(true) to succeed.
|
||||
private static void testReflectionGetDeclaredFieldSetAccessible() throws Exception {
|
||||
try {
|
||||
Class<?> c = Class.forName("jdk.jfr.internal.event.EventWriter");
|
||||
Field field = c.getDeclaredField("jvm");
|
||||
field.setAccessible(true);
|
||||
throw new RuntimeException("Should not reach here " + field);
|
||||
} catch (InaccessibleObjectException ioe) {
|
||||
if (ioe.getMessage().contains("module jdk.jfr does not \"opens jdk.jfr.internal.event")) {
|
||||
// OK, as expected. Even when using setAccessible(true), by default, the jdk.jfr module
|
||||
// is not open for reflective access to private members.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user