8203629: Produce events in the JDK without a dependency on jdk.jfr
Reviewed-by: mgronlun
This commit is contained in:
parent
7d2ac4cc31
commit
ba18b569ef
src
hotspot/share/jfr
instrumentation
jni
recorder/checkpoint/types/traceid
java.base/share/classes
jdk.jfr/share/classes/jdk/jfr
test/jdk/jdk/jfr/jvm
@ -27,6 +27,8 @@
|
||||
#include "classfile/classFileParser.hpp"
|
||||
#include "classfile/classFileStream.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/moduleEntry.hpp"
|
||||
#include "classfile/modules.hpp"
|
||||
#include "classfile/stackMapTable.hpp"
|
||||
#include "classfile/verificationType.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
@ -61,25 +63,26 @@ static const char* utf8_constants[] = {
|
||||
"J", // 1
|
||||
"commit", // 2
|
||||
"eventHandler", // 3
|
||||
"Ljdk/jfr/internal/handlers/EventHandler;", // 4
|
||||
"duration", // 5
|
||||
"begin", // 6
|
||||
"()V", // 7
|
||||
"isEnabled", // 8
|
||||
"()Z", // 9
|
||||
"end", // 10
|
||||
"shouldCommit", // 11
|
||||
"startTime", // 12
|
||||
"<clinit>", // 13
|
||||
"jdk/jfr/FlightRecorder", // 14
|
||||
"register", // 15
|
||||
"(Ljava/lang/Class;)V", // 16 // LAST_REQUIRED_UTF8
|
||||
"StackMapTable", // 17
|
||||
"Exceptions", // 18
|
||||
"duration", // 4
|
||||
"begin", // 5
|
||||
"()V", // 6
|
||||
"isEnabled", // 7
|
||||
"()Z", // 8
|
||||
"end", // 9
|
||||
"shouldCommit", // 10
|
||||
"startTime", // 11 // LAST_REQUIRED_UTF8
|
||||
"Ljdk/jfr/internal/handlers/EventHandler;", // 12
|
||||
"Ljava/lang/Object;", // 13
|
||||
"<clinit>", // 14
|
||||
"jdk/jfr/FlightRecorder", // 15
|
||||
"register", // 16
|
||||
"(Ljava/lang/Class;)V", // 17
|
||||
"StackMapTable", // 18
|
||||
"Exceptions", // 19
|
||||
"LineNumberTable", // 20
|
||||
"LocalVariableTable", // 21
|
||||
"LocalVariableTypeTable", // 22
|
||||
"RuntimeVisibleAnnotation" // 23
|
||||
"RuntimeVisibleAnnotation", // 23
|
||||
};
|
||||
|
||||
enum utf8_req_symbols {
|
||||
@ -87,7 +90,6 @@ enum utf8_req_symbols {
|
||||
UTF8_REQ_J_FIELD_DESC,
|
||||
UTF8_REQ_commit,
|
||||
UTF8_REQ_eventHandler,
|
||||
UTF8_REQ_eventHandler_FIELD_DESC,
|
||||
UTF8_REQ_duration,
|
||||
UTF8_REQ_begin,
|
||||
UTF8_REQ_EMPTY_VOID_METHOD_DESC,
|
||||
@ -96,15 +98,17 @@ enum utf8_req_symbols {
|
||||
UTF8_REQ_end,
|
||||
UTF8_REQ_shouldCommit,
|
||||
UTF8_REQ_startTime,
|
||||
UTF8_REQ_clinit,
|
||||
UTF8_REQ_FlightRecorder,
|
||||
UTF8_REQ_register,
|
||||
UTF8_REQ_CLASS_VOID_METHOD_DESC,
|
||||
NOF_UTF8_REQ_SYMBOLS
|
||||
};
|
||||
|
||||
enum utf8_opt_symbols {
|
||||
UTF8_OPT_StackMapTable = NOF_UTF8_REQ_SYMBOLS,
|
||||
UTF8_OPT_eventHandler_FIELD_DESC = NOF_UTF8_REQ_SYMBOLS,
|
||||
UTF8_OPT_LjavaLangObject,
|
||||
UTF8_OPT_clinit,
|
||||
UTF8_OPT_FlightRecorder,
|
||||
UTF8_OPT_register,
|
||||
UTF8_OPT_CLASS_VOID_METHOD_DESC,
|
||||
UTF8_OPT_StackMapTable,
|
||||
UTF8_OPT_Exceptions,
|
||||
UTF8_OPT_LineNumberTable,
|
||||
UTF8_OPT_LocalVariableTable,
|
||||
@ -353,7 +357,7 @@ class AnnotationIterator : public StackObj {
|
||||
|
||||
static unsigned int unused_hash = 0;
|
||||
static const char value_name[] = "value";
|
||||
static bool has_registered_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
|
||||
static bool has_annotation(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
|
||||
assert(annotation_type != NULL, "invariant");
|
||||
AnnotationArray* class_annotations = ik->class_annotations();
|
||||
if (class_annotations == NULL) {
|
||||
@ -383,16 +387,51 @@ static bool has_registered_annotation(const InstanceKlass* ik, const Symbol* ann
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool registered_annotation_value(const InstanceKlass* ik, const Symbol* const registered_symbol) {
|
||||
assert(registered_symbol != NULL, "invariant");
|
||||
// Evaluate to the value of the first found Symbol* annotation type.
|
||||
// Searching moves upwards in the klass hierarchy in order to support
|
||||
// inherited annotations in addition to the ability to override.
|
||||
static bool annotation_value(const InstanceKlass* ik, const Symbol* annotation_type, bool& value) {
|
||||
assert(ik != NULL, "invariant");
|
||||
assert(annotation_type != NULL, "invariant");
|
||||
assert(JdkJfrEvent::is_a(ik), "invariant");
|
||||
bool registered_value = false;
|
||||
if (has_registered_annotation(ik, registered_symbol, registered_value)) {
|
||||
return registered_value;
|
||||
if (has_annotation(ik, annotation_type, value)) {
|
||||
return true;
|
||||
}
|
||||
InstanceKlass* super = InstanceKlass::cast(ik->super());
|
||||
return registered_annotation_value(super, registered_symbol);
|
||||
InstanceKlass* const super = InstanceKlass::cast(ik->super());
|
||||
return super != NULL && JdkJfrEvent::is_a(super) ? annotation_value(super, annotation_type, value) : false;
|
||||
}
|
||||
|
||||
static const char jdk_jfr_module_name[] = "jdk.jfr";
|
||||
|
||||
static bool java_base_can_read_jdk_jfr() {
|
||||
static bool can_read = false;
|
||||
if (can_read) {
|
||||
return true;
|
||||
}
|
||||
static Symbol* jdk_jfr_module_symbol = NULL;
|
||||
if (jdk_jfr_module_symbol == NULL) {
|
||||
jdk_jfr_module_symbol = SymbolTable::lookup_only(jdk_jfr_module_name, sizeof jdk_jfr_module_name - 1, unused_hash);
|
||||
if (jdk_jfr_module_symbol == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(jdk_jfr_module_symbol != NULL, "invariant");
|
||||
ModuleEntryTable* const table = Modules::get_module_entry_table(Handle());
|
||||
assert(table != NULL, "invariant");
|
||||
const ModuleEntry* const java_base_module = table->javabase_moduleEntry();
|
||||
if (java_base_module == NULL) {
|
||||
return false;
|
||||
}
|
||||
assert(java_base_module != NULL, "invariant");
|
||||
ModuleEntry* const jdk_jfr_module = table->lookup_only(jdk_jfr_module_symbol);
|
||||
if (jdk_jfr_module == NULL) {
|
||||
return false;
|
||||
}
|
||||
assert(jdk_jfr_module != NULL, "invariant");
|
||||
if (java_base_module->can_read(jdk_jfr_module)) {
|
||||
can_read = true;
|
||||
}
|
||||
return can_read;
|
||||
}
|
||||
|
||||
static const char registered_constant[] = "Ljdk/jfr/Registered;";
|
||||
@ -400,13 +439,23 @@ static const char registered_constant[] = "Ljdk/jfr/Registered;";
|
||||
// Evaluate to the value of the first found "Ljdk/jfr/Registered;" annotation.
|
||||
// Searching moves upwards in the klass hierarchy in order to support
|
||||
// inherited annotations in addition to the ability to override.
|
||||
static bool should_register_klass(const InstanceKlass* ik) {
|
||||
static const Symbol* const registered_symbol = SymbolTable::lookup_only(registered_constant,
|
||||
sizeof registered_constant - 1,
|
||||
unused_hash);
|
||||
static bool should_register_klass(const InstanceKlass* ik, bool& untypedEventHandler) {
|
||||
assert(ik != NULL, "invariant");
|
||||
assert(JdkJfrEvent::is_a(ik), "invariant");
|
||||
assert(!untypedEventHandler, "invariant");
|
||||
static const Symbol* registered_symbol = NULL;
|
||||
if (registered_symbol == NULL) {
|
||||
registered_symbol = SymbolTable::lookup_only(registered_constant, sizeof registered_constant - 1, unused_hash);
|
||||
if (registered_symbol == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(registered_symbol != NULL, "invariant");
|
||||
return registered_annotation_value(ik, registered_symbol);
|
||||
bool value = false; // to be set by annotation_value
|
||||
untypedEventHandler = !(annotation_value(ik, registered_symbol, value) || java_base_can_read_jdk_jfr());
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map an utf8 constant back to its CONSTANT_UTF8_INFO
|
||||
*/
|
||||
@ -450,6 +499,9 @@ static u2 add_method_ref_info(JfrBigEndianWriter& writer,
|
||||
u2 orig_cp_len,
|
||||
u2& number_of_new_constants,
|
||||
TRAPS) {
|
||||
assert(cls_name_index != invalid_cp_index, "invariant");
|
||||
assert(method_index != invalid_cp_index, "invariant");
|
||||
assert(desc_index != invalid_cp_index, "invariant");
|
||||
assert(is_index_within_range(cls_name_index, orig_cp_len, number_of_new_constants), "invariant");
|
||||
assert(is_index_within_range(method_index, orig_cp_len, number_of_new_constants), "invariant");
|
||||
assert(is_index_within_range(desc_index, orig_cp_len, number_of_new_constants), "invariant");
|
||||
@ -477,9 +529,9 @@ static u2 add_flr_register_method_constants(JfrBigEndianWriter& writer,
|
||||
TRAPS) {
|
||||
assert(utf8_indexes != NULL, "invariant");
|
||||
return add_method_ref_info(writer,
|
||||
utf8_indexes[UTF8_REQ_FlightRecorder],
|
||||
utf8_indexes[UTF8_REQ_register],
|
||||
utf8_indexes[UTF8_REQ_CLASS_VOID_METHOD_DESC],
|
||||
utf8_indexes[UTF8_OPT_FlightRecorder],
|
||||
utf8_indexes[UTF8_OPT_register],
|
||||
utf8_indexes[UTF8_OPT_CLASS_VOID_METHOD_DESC],
|
||||
orig_cp_len,
|
||||
number_of_new_constants,
|
||||
THREAD);
|
||||
@ -495,8 +547,8 @@ static u2 add_flr_register_method_constants(JfrBigEndianWriter& writer,
|
||||
* }
|
||||
*/
|
||||
static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_index, bool is_static = false) {
|
||||
assert(name_index > 0, "invariant");
|
||||
assert(desc_index > 0, "invariant");
|
||||
assert(name_index != invalid_cp_index, "invariant");
|
||||
assert(desc_index != invalid_cp_index, "invariant");
|
||||
DEBUG_ONLY(const jlong start_offset = writer.current_offset();)
|
||||
writer.write<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PRIVATE | (is_static ? JVM_ACC_STATIC : JVM_ACC_TRANSIENT)); // flags
|
||||
writer.write(name_index);
|
||||
@ -507,11 +559,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) {
|
||||
static u2 add_field_infos(JfrBigEndianWriter& writer, const u2* utf8_indexes, bool untypedEventHandler) {
|
||||
assert(utf8_indexes != NULL, "invariant");
|
||||
add_field_info(writer,
|
||||
utf8_indexes[UTF8_REQ_eventHandler],
|
||||
utf8_indexes[UTF8_REQ_eventHandler_FIELD_DESC],
|
||||
untypedEventHandler ? utf8_indexes[UTF8_OPT_LjavaLangObject] : utf8_indexes[UTF8_OPT_eventHandler_FIELD_DESC],
|
||||
true); // static
|
||||
|
||||
add_field_info(writer,
|
||||
@ -989,7 +1041,8 @@ static jlong insert_clinit_method(const InstanceKlass* ik,
|
||||
// This is to ensure that padding can be done
|
||||
// where needed and to simplify size calculations.
|
||||
static const u2 injected_code_length = 8;
|
||||
const u2 name_index = utf8_indexes[UTF8_REQ_clinit];
|
||||
const u2 name_index = utf8_indexes[UTF8_OPT_clinit];
|
||||
assert(name_index != invalid_cp_index, "invariant");
|
||||
const u2 desc_index = utf8_indexes[UTF8_REQ_EMPTY_VOID_METHOD_DESC];
|
||||
const u2 max_stack = MAX2(clinit_method != NULL ? clinit_method->verifier_max_stack() : 1, 1);
|
||||
const u2 max_locals = MAX2(clinit_method != NULL ? clinit_method->max_locals() : 0, 0);
|
||||
@ -1138,59 +1191,58 @@ static u2 resolve_utf8_indexes(JfrBigEndianWriter& writer,
|
||||
u2* const utf8_indexes,
|
||||
u2 orig_cp_len,
|
||||
const Method* clinit_method,
|
||||
bool register_klass,
|
||||
bool untypedEventHandler,
|
||||
TRAPS) {
|
||||
assert(utf8_indexes != NULL, "invariant");
|
||||
u2 added_cp_entries = 0;
|
||||
// resolve all required symbols
|
||||
for (u2 index = 0; index < NOF_UTF8_REQ_SYMBOLS; ++index) {
|
||||
utf8_indexes[index] = find_or_add_utf8_info(writer,
|
||||
ik,
|
||||
utf8_constants[index],
|
||||
orig_cp_len,
|
||||
added_cp_entries,
|
||||
THREAD);
|
||||
utf8_indexes[index] = find_or_add_utf8_info(writer, ik, utf8_constants[index], orig_cp_len, added_cp_entries, THREAD);
|
||||
}
|
||||
// Now determine optional constants (mainly "Code" attributes)
|
||||
|
||||
// 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_LjavaLangObject] = untypedEventHandler ?
|
||||
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) {
|
||||
utf8_indexes[UTF8_OPT_clinit] =
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_clinit], orig_cp_len, added_cp_entries, THREAD);
|
||||
utf8_indexes[UTF8_OPT_FlightRecorder] =
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_FlightRecorder], orig_cp_len, added_cp_entries, THREAD);
|
||||
utf8_indexes[UTF8_OPT_register] =
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_register], orig_cp_len, added_cp_entries, THREAD);
|
||||
utf8_indexes[UTF8_OPT_CLASS_VOID_METHOD_DESC] =
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_CLASS_VOID_METHOD_DESC], orig_cp_len, added_cp_entries, THREAD);
|
||||
} else {
|
||||
utf8_indexes[UTF8_OPT_clinit] = invalid_cp_index;
|
||||
utf8_indexes[UTF8_OPT_FlightRecorder] = invalid_cp_index;
|
||||
utf8_indexes[UTF8_OPT_register] = invalid_cp_index;
|
||||
utf8_indexes[UTF8_OPT_CLASS_VOID_METHOD_DESC] = invalid_cp_index;
|
||||
}
|
||||
|
||||
if (clinit_method != NULL && clinit_method->has_stackmap_table()) {
|
||||
utf8_indexes[UTF8_OPT_StackMapTable] =
|
||||
find_or_add_utf8_info(writer,
|
||||
ik,
|
||||
utf8_constants[UTF8_OPT_StackMapTable],
|
||||
orig_cp_len,
|
||||
added_cp_entries,
|
||||
THREAD);
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_StackMapTable], orig_cp_len, added_cp_entries, THREAD);
|
||||
} else {
|
||||
utf8_indexes[UTF8_OPT_StackMapTable] = invalid_cp_index;
|
||||
}
|
||||
|
||||
if (clinit_method != NULL && clinit_method->has_linenumber_table()) {
|
||||
utf8_indexes[UTF8_OPT_LineNumberTable] =
|
||||
find_or_add_utf8_info(writer,
|
||||
ik,
|
||||
utf8_constants[UTF8_OPT_LineNumberTable],
|
||||
orig_cp_len,
|
||||
added_cp_entries,
|
||||
THREAD);
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LineNumberTable], orig_cp_len, added_cp_entries, THREAD);
|
||||
} else {
|
||||
utf8_indexes[UTF8_OPT_LineNumberTable] = invalid_cp_index;
|
||||
}
|
||||
|
||||
if (clinit_method != NULL && clinit_method->has_localvariable_table()) {
|
||||
utf8_indexes[UTF8_OPT_LocalVariableTable] =
|
||||
find_or_add_utf8_info(writer,
|
||||
ik,
|
||||
utf8_constants[UTF8_OPT_LocalVariableTable],
|
||||
orig_cp_len,
|
||||
added_cp_entries,
|
||||
THREAD);
|
||||
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LocalVariableTable], orig_cp_len, added_cp_entries, THREAD);
|
||||
utf8_indexes[UTF8_OPT_LocalVariableTypeTable] =
|
||||
find_or_add_utf8_info(writer,
|
||||
ik,
|
||||
utf8_constants[UTF8_OPT_LocalVariableTypeTable],
|
||||
orig_cp_len,
|
||||
added_cp_entries,
|
||||
THREAD);
|
||||
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LocalVariableTypeTable], orig_cp_len, added_cp_entries, THREAD);
|
||||
} else {
|
||||
utf8_indexes[UTF8_OPT_LocalVariableTable] = invalid_cp_index;
|
||||
utf8_indexes[UTF8_OPT_LocalVariableTypeTable] = invalid_cp_index;
|
||||
@ -1207,7 +1259,8 @@ static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
|
||||
// If the class already has a clinit method
|
||||
// we need to take that into account
|
||||
const Method* clinit_method = ik->class_initializer();
|
||||
const bool register_klass = should_register_klass(ik);
|
||||
bool untypedEventHandler = false;
|
||||
const bool register_klass = should_register_klass(ik, untypedEventHandler);
|
||||
const ClassFileStream* const orig_stream = parser.clone_stream();
|
||||
const int orig_stream_size = orig_stream->length();
|
||||
assert(orig_stream->current_offset() == 0, "invariant");
|
||||
@ -1241,7 +1294,8 @@ static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
|
||||
// Resolve_utf8_indexes will be conservative in attempting to
|
||||
// locate an existing UTF8_INFO; it will only append constants
|
||||
// that is absolutely required
|
||||
u2 number_of_new_constants = resolve_utf8_indexes(writer, ik, utf8_indexes, orig_cp_len, clinit_method, THREAD);
|
||||
u2 number_of_new_constants =
|
||||
resolve_utf8_indexes(writer, ik, utf8_indexes, orig_cp_len, clinit_method, register_klass, untypedEventHandler, THREAD);
|
||||
// UTF8_INFO entries now added to the constant pool
|
||||
// In order to invoke a method we would need additional
|
||||
// constants, JVM_CONSTANT_Class, JVM_CONSTANT_NameAndType
|
||||
@ -1274,7 +1328,7 @@ static u1* new_bytes_for_lazy_instrumentation(const InstanceKlass* ik,
|
||||
assert(writer.is_valid(), "invariant");
|
||||
// We are sitting just after the original number of field_infos
|
||||
// so this is a position where we can add (append) new field_infos
|
||||
const u2 number_of_new_fields = add_field_infos(writer, utf8_indexes);
|
||||
const u2 number_of_new_fields = add_field_infos(writer, utf8_indexes, untypedEventHandler);
|
||||
assert(writer.is_valid(), "invariant");
|
||||
const jlong new_method_len_offset = writer.current_offset();
|
||||
// Additional field_infos added, update classfile fields_count
|
||||
|
@ -132,7 +132,7 @@ jobject JfrEventClasses::get_all_event_classes(TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
initialize(THREAD);
|
||||
assert(empty_java_util_arraylist != NULL, "should have been setup already!");
|
||||
static const char jdk_jfr_event_name[] = "jdk/jfr/Event";
|
||||
static const char jdk_jfr_event_name[] = "jdk/internal/event/Event";
|
||||
unsigned int unused_hash = 0;
|
||||
Symbol* const event_klass_name = SymbolTable::lookup_only(jdk_jfr_event_name, sizeof jdk_jfr_event_name - 1, unused_hash);
|
||||
|
||||
|
@ -76,22 +76,43 @@ static traceid next_class_loader_data_id() {
|
||||
return atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT;
|
||||
}
|
||||
|
||||
static bool found_jdk_internal_event_klass = false;
|
||||
static bool found_jdk_jfr_event_klass = false;
|
||||
|
||||
static void check_klass(const Klass* klass) {
|
||||
assert(klass != NULL, "invariant");
|
||||
if (found_jdk_jfr_event_klass) {
|
||||
if (found_jdk_internal_event_klass && found_jdk_jfr_event_klass) {
|
||||
return;
|
||||
}
|
||||
static const Symbol* jdk_internal_event_sym = NULL;
|
||||
if (jdk_internal_event_sym == NULL) {
|
||||
// setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
|
||||
jdk_internal_event_sym = SymbolTable::new_permanent_symbol("jdk/internal/event/Event", Thread::current());
|
||||
}
|
||||
assert(jdk_internal_event_sym != NULL, "invariant");
|
||||
|
||||
static const Symbol* jdk_jfr_event_sym = NULL;
|
||||
if (jdk_jfr_event_sym == NULL) {
|
||||
// setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
|
||||
jdk_jfr_event_sym = SymbolTable::new_permanent_symbol("jdk/jfr/Event", Thread::current());
|
||||
}
|
||||
assert(jdk_jfr_event_sym != NULL, "invariant");
|
||||
if (jdk_jfr_event_sym == klass->name() && klass->class_loader() == NULL) {
|
||||
found_jdk_jfr_event_klass = true;
|
||||
JfrTraceId::tag_as_jdk_jfr_event(klass);
|
||||
const Symbol* const klass_name = klass->name();
|
||||
|
||||
if (!found_jdk_internal_event_klass) {
|
||||
if (jdk_internal_event_sym == klass_name && klass->class_loader() == NULL) {
|
||||
found_jdk_internal_event_klass = true;
|
||||
JfrTraceId::tag_as_jdk_jfr_event(klass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_jdk_jfr_event_klass) {
|
||||
if (jdk_jfr_event_sym == klass_name && klass->class_loader() == NULL) {
|
||||
found_jdk_jfr_event_klass = true;
|
||||
JfrTraceId::tag_as_jdk_jfr_event(klass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,10 +112,8 @@ inline bool JfrTraceId::is_jdk_jfr_event(const Klass* k) {
|
||||
|
||||
inline void JfrTraceId::tag_as_jdk_jfr_event(const Klass* klass) {
|
||||
assert(klass != NULL, "invariant");
|
||||
assert(IS_NOT_AN_EVENT_KLASS(klass), "invariant");
|
||||
SET_TAG(klass, JDK_JFR_EVENT_KLASS);
|
||||
assert(IS_JDK_JFR_EVENT_KLASS(klass), "invariant");
|
||||
assert(IS_NOT_AN_EVENT_SUB_KLASS(klass), "invariant");
|
||||
}
|
||||
|
||||
inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) {
|
||||
@ -125,7 +123,7 @@ inline bool JfrTraceId::is_jdk_jfr_event_sub(const Klass* k) {
|
||||
|
||||
inline void JfrTraceId::tag_as_jdk_jfr_event_sub(const Klass* k) {
|
||||
assert(k != NULL, "invariant");
|
||||
if (IS_NOT_AN_EVENT_KLASS(k)) {
|
||||
if (IS_NOT_AN_EVENT_SUB_KLASS(k)) {
|
||||
SET_TAG(k, JDK_JFR_EVENT_SUBKLASS);
|
||||
}
|
||||
assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
|
||||
|
94
src/java.base/share/classes/jdk/internal/event/Event.java
Normal file
94
src/java.base/share/classes/jdk/internal/event/Event.java
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.internal.event;
|
||||
|
||||
/**
|
||||
* Base class for events, to be subclassed in order to define events and their
|
||||
* fields.
|
||||
*/
|
||||
public abstract class Event {
|
||||
/**
|
||||
* Sole constructor, for invocation by subclass constructors, typically
|
||||
* implicit.
|
||||
*/
|
||||
protected Event() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timing of this event.
|
||||
*/
|
||||
public void begin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the timing of this event.
|
||||
*
|
||||
* The {@code end} method must be invoked after the {@code begin} method.
|
||||
*/
|
||||
public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the field values, time stamp, and event duration.
|
||||
* <p>
|
||||
* If the event starts with an invocation of the {@code begin} method, but does
|
||||
* not end with an explicit invocation of the {@code end} method, then the event
|
||||
* ends when the {@code commit} method is invoked.
|
||||
*/
|
||||
public void commit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the event is enabled, {@code false} otherwise
|
||||
*
|
||||
* @return {@code true} if event is enabled, {@code false} otherwise
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the event is enabled and if the duration is within
|
||||
* the threshold for the event, {@code false} otherwise.
|
||||
*
|
||||
* @return {@code true} if the event can be written, {@code false} otherwise
|
||||
*/
|
||||
public boolean shouldCommit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a field value.
|
||||
*
|
||||
* @param index the index of the field to set
|
||||
* @param value value to set, can be {@code null}
|
||||
* @throws UnsupportedOperationException if functionality is not supported
|
||||
* @throws IndexOutOfBoundsException if {@code index} is less than {@code 0} or
|
||||
* greater than or equal to the number of fields specified for the event
|
||||
*/
|
||||
public void set(int index, Object value) {
|
||||
}
|
||||
}
|
@ -136,6 +136,8 @@ module java.base {
|
||||
java.security.sasl;
|
||||
exports jdk.internal to
|
||||
jdk.jfr;
|
||||
exports jdk.internal.event to
|
||||
jdk.jfr;
|
||||
exports jdk.internal.jimage to
|
||||
jdk.jlink;
|
||||
exports jdk.internal.jimage.decompressor to
|
||||
|
@ -88,7 +88,7 @@ package jdk.jfr;
|
||||
@Enabled(true)
|
||||
@StackTrace(true)
|
||||
@Registered(true)
|
||||
abstract public class Event {
|
||||
abstract public class Event extends jdk.internal.event.Event {
|
||||
/**
|
||||
* Sole constructor, for invocation by subclass constructors, typically
|
||||
* implicit.
|
||||
|
@ -41,7 +41,6 @@ import java.util.Set;
|
||||
import jdk.internal.module.Modules;
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.SettingControl;
|
||||
@ -109,7 +108,7 @@ public final class EventControl {
|
||||
}
|
||||
}
|
||||
|
||||
EventControl(PlatformEventType es, Class<? extends Event> eventClass) {
|
||||
EventControl(PlatformEventType es, Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
this(es);
|
||||
defineSettings(eventClass);
|
||||
}
|
||||
|
@ -93,11 +93,11 @@ final class EventHandlerCreator {
|
||||
return EventHandler.class.getName() + id + SUFFIX;
|
||||
}
|
||||
|
||||
public EventHandlerCreator(long id, List<SettingInfo> settingInfos, EventType type, Class<? extends Event> eventClass) {
|
||||
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 Event> eventClass, EventType type) throws Error {
|
||||
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.
|
||||
|
@ -102,6 +102,7 @@ public final class EventInstrumentation {
|
||||
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 Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
|
||||
private static final Type TYPE_OBJECT = Type.getType(Object.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]);
|
||||
@ -117,6 +118,7 @@ public final class EventInstrumentation {
|
||||
private final Method writeMethod;
|
||||
private final String eventHandlerXInternalName;
|
||||
private final String eventName;
|
||||
private final boolean untypedEventHandler;
|
||||
private boolean guardHandlerReference;
|
||||
private Class<?> superClass;
|
||||
|
||||
@ -125,11 +127,20 @@ public final class EventInstrumentation {
|
||||
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);
|
||||
this.eventName = n == null ? classNode.name.replace("/", ".") : n;
|
||||
}
|
||||
|
||||
private boolean hasUntypedHandler() {
|
||||
for (FieldNode field : classNode.fields) {
|
||||
if (FIELD_EVENT_HANDLER.equals(field.name)) {
|
||||
return field.desc.equals(TYPE_OBJECT.getDescriptor());
|
||||
}
|
||||
}
|
||||
throw new InternalError("Class missing handler field");
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
@ -225,7 +236,7 @@ public final class EventInstrumentation {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
|
||||
for (Class<?> c = superClass; c != jdk.internal.event.Event.class; c = c.getSuperclass()) {
|
||||
for (java.lang.reflect.Method method : c.getDeclaredMethods()) {
|
||||
if (!methodSet.contains(method.getName())) {
|
||||
// skip private method in base classes
|
||||
@ -249,7 +260,6 @@ public final class EventInstrumentation {
|
||||
}
|
||||
}
|
||||
return settingInfos;
|
||||
|
||||
}
|
||||
|
||||
private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
|
||||
@ -264,14 +274,13 @@ public final class EventInstrumentation {
|
||||
fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
||||
fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
||||
for (FieldNode field : classNode.fields) {
|
||||
String className = Type.getType(field.desc).getClassName();
|
||||
if (!fieldSet.contains(field.name) && isValidField(field.access, className)) {
|
||||
if (!fieldSet.contains(field.name) && isValidField(field.access, Type.getType(field.desc).getClassName())) {
|
||||
FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name);
|
||||
fieldInfos.add(fi);
|
||||
fieldSet.add(field.name);
|
||||
}
|
||||
}
|
||||
for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
|
||||
for (Class<?> c = superClass; c != jdk.internal.event.Event.class; c = c.getSuperclass()) {
|
||||
for (Field field : c.getDeclaredFields()) {
|
||||
// skip private field in base classes
|
||||
if (!Modifier.isPrivate(field.getModifiers())) {
|
||||
@ -321,10 +330,10 @@ public final class EventInstrumentation {
|
||||
updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
|
||||
Label nullLabel = new Label();
|
||||
if (guardHandlerReference) {
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
|
||||
getEventHandler(methodVisitor);
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel);
|
||||
}
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
|
||||
getEventHandler(methodVisitor);
|
||||
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED);
|
||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||
if (guardHandlerReference) {
|
||||
@ -408,7 +417,7 @@ public final class EventInstrumentation {
|
||||
// eventHandler.write(...);
|
||||
// }
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
||||
getEventHandler(methodVisitor);
|
||||
|
||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
||||
for (FieldInfo fi : fieldInfos) {
|
||||
@ -426,8 +435,8 @@ public final class EventInstrumentation {
|
||||
// MyEvent#shouldCommit()
|
||||
updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
|
||||
Label fail = new Label();
|
||||
// if (!eventHandler.shoouldCommit(duration) goto fail;
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
||||
// if (!eventHandler.shouldCommit(duration) goto fail;
|
||||
getEventHandler(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);
|
||||
@ -435,7 +444,11 @@ public final class EventInstrumentation {
|
||||
for (SettingInfo si : settingInfos) {
|
||||
// if (!settingsMethod(eventHandler.settingX)) goto fail;
|
||||
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
||||
if (untypedEventHandler) {
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_OBJECT.getDescriptor());
|
||||
} else {
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
||||
}
|
||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
|
||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName);
|
||||
@ -452,6 +465,15 @@ public final class EventInstrumentation {
|
||||
});
|
||||
}
|
||||
|
||||
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());
|
||||
} else {
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
||||
}
|
||||
}
|
||||
|
||||
private void makeUninstrumented() {
|
||||
updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT);
|
||||
updateExistingWithReturnFalse(METHOD_IS_ENABLED);
|
||||
|
@ -106,11 +106,11 @@ public final class JVM {
|
||||
public native void endRecording();
|
||||
|
||||
/**
|
||||
* Return a list of all classes deriving from {@link Event}
|
||||
* Return a list of all classes deriving from {@link jdk.internal.event.Event}
|
||||
*
|
||||
* @return list of event classes.
|
||||
*/
|
||||
public native List<Class<? extends Event>> getAllEventClasses();
|
||||
public native List<Class<? extends jdk.internal.event.Event>> getAllEventClasses();
|
||||
|
||||
/**
|
||||
* Return a count of the number of unloaded classes deriving from {@link Event}
|
||||
|
@ -26,7 +26,6 @@ package jdk.jfr.internal;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
import jdk.jfr.internal.instrument.JDKEvents;
|
||||
|
||||
@ -53,8 +52,8 @@ final class JVMUpcalls {
|
||||
*/
|
||||
static byte[] onRetransform(long traceId, boolean dummy, Class<?> clazz, byte[] oldBytes) throws Throwable {
|
||||
try {
|
||||
if (Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
|
||||
EventHandler handler = Utils.getHandler(clazz.asSubclass(Event.class));
|
||||
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.");
|
||||
// Probably triggered by some other agent
|
||||
|
@ -33,6 +33,7 @@ import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -56,6 +57,7 @@ public final class MetadataRepository {
|
||||
private final List<EventControl> nativeControls = new ArrayList<EventControl>(100);
|
||||
private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
|
||||
private final SettingsManager settingsManager = new SettingsManager();
|
||||
private final Map<String, Class<? extends Event>> mirrors = new HashMap<>();
|
||||
private boolean staleMetadata = true;
|
||||
private boolean unregistered;
|
||||
private long lastUnloaded = -1;
|
||||
@ -105,7 +107,7 @@ public final class MetadataRepository {
|
||||
return eventTypes;
|
||||
}
|
||||
|
||||
public synchronized EventType getEventType(Class<? extends Event> eventClass) {
|
||||
public synchronized EventType getEventType(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
EventHandler h = getHandler(eventClass);
|
||||
if (h != null && h.isRegistered()) {
|
||||
return h.getEventType();
|
||||
@ -121,15 +123,20 @@ public final class MetadataRepository {
|
||||
}
|
||||
// never registered, ignore call
|
||||
}
|
||||
public synchronized EventType register(Class<? extends Event> eventClass) {
|
||||
public synchronized EventType register(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
return register(eventClass, Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
|
||||
public synchronized EventType register(Class<? extends Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
|
||||
public synchronized EventType register(Class<? extends jdk.internal.event.Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
|
||||
Utils.checkRegisterPermission();
|
||||
EventHandler handler = getHandler(eventClass);
|
||||
if (handler == null) {
|
||||
handler = makeHandler(eventClass, dynamicAnnotations, dynamicFields);
|
||||
if (eventClass.getAnnotation(MirrorEvent.class) != null) {
|
||||
// don't register mirrors
|
||||
return null;
|
||||
}
|
||||
PlatformEventType pe = findMirrorType(eventClass);
|
||||
handler = makeHandler(eventClass, pe, dynamicAnnotations, dynamicFields);
|
||||
}
|
||||
handler.setRegistered(true);
|
||||
typeLibrary.addType(handler.getPlatformEventType());
|
||||
@ -143,16 +150,32 @@ public final class MetadataRepository {
|
||||
return handler.getEventType();
|
||||
}
|
||||
|
||||
private EventHandler getHandler(Class<? extends Event> eventClass) {
|
||||
private PlatformEventType findMirrorType(Class<? extends jdk.internal.event.Event> eventClass) throws InternalError {
|
||||
String fullName = eventClass.getModule().getName() + ":" + eventClass.getName();
|
||||
Class<? extends Event> mirrorClass = mirrors.get(fullName);
|
||||
if (mirrorClass == null) {
|
||||
return null; // not a mirror
|
||||
}
|
||||
Utils.verifyMirror(mirrorClass, eventClass);
|
||||
PlatformEventType et = (PlatformEventType) TypeLibrary.createType(mirrorClass);
|
||||
typeLibrary.removeType(et.getId());
|
||||
long id = Type.getTypeId(eventClass);
|
||||
et.setId(id);
|
||||
return et;
|
||||
}
|
||||
|
||||
private EventHandler getHandler(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
SecuritySupport.makeVisibleToJFR(eventClass);
|
||||
Utils.ensureInitialized(eventClass);
|
||||
return Utils.getHandler(eventClass);
|
||||
}
|
||||
|
||||
private EventHandler makeHandler(Class<? extends Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) throws InternalError {
|
||||
private EventHandler makeHandler(Class<? extends jdk.internal.event.Event> eventClass, PlatformEventType pEventType, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) throws InternalError {
|
||||
SecuritySupport.addHandlerExport(eventClass);
|
||||
PlatformEventType pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields);
|
||||
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;
|
||||
@ -198,9 +221,9 @@ public final class MetadataRepository {
|
||||
}
|
||||
|
||||
private static List<EventHandler> getEventHandlers() {
|
||||
List<Class<? extends Event>> allEventClasses = jvm.getAllEventClasses();
|
||||
List<Class<? extends jdk.internal.event.Event>> allEventClasses = jvm.getAllEventClasses();
|
||||
List<EventHandler> eventHandlers = new ArrayList<>(allEventClasses.size());
|
||||
for (Class<? extends Event> clazz : allEventClasses) {
|
||||
for (Class<? extends jdk.internal.event.Event> clazz : allEventClasses) {
|
||||
EventHandler eh = Utils.getHandler(clazz);
|
||||
if (eh != null) {
|
||||
eventHandlers.add(eh);
|
||||
@ -252,9 +275,9 @@ public final class MetadataRepository {
|
||||
long unloaded = jvm.getUnloadedEventClassCount();
|
||||
if (this.lastUnloaded != unloaded) {
|
||||
this.lastUnloaded = unloaded;
|
||||
List<Class<? extends Event>> eventClasses = jvm.getAllEventClasses();
|
||||
List<Class<? extends jdk.internal.event.Event>> eventClasses = jvm.getAllEventClasses();
|
||||
HashSet<Long> knownIds = new HashSet<>(eventClasses.size());
|
||||
for (Class<? extends Event> ec: eventClasses) {
|
||||
for (Class<? extends jdk.internal.event.Event> ec: eventClasses) {
|
||||
knownIds.add(Type.getTypeId(ec));
|
||||
}
|
||||
for (Type type : typeLibrary.getTypes()) {
|
||||
@ -270,8 +293,18 @@ public final class MetadataRepository {
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void setUnregistered() {
|
||||
synchronized void setUnregistered() {
|
||||
unregistered = true;
|
||||
}
|
||||
|
||||
public synchronized void registerMirror(Class<? extends Event> eventClass) {
|
||||
MirrorEvent me = eventClass.getAnnotation(MirrorEvent.class);
|
||||
if (me != null) {
|
||||
String fullName = me.module() + ":" + me.className();
|
||||
mirrors.put(fullName, eventClass);
|
||||
return;
|
||||
}
|
||||
throw new InternalError("Mirror class must have annotation " + MirrorEvent.class.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
25
src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvent.java
Normal file
25
src/jdk.jfr/share/classes/jdk/jfr/internal/MirrorEvent.java
Normal file
@ -0,0 +1,25 @@
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface MirrorEvent {
|
||||
/**
|
||||
* Fully qualified name of the class to mirror metadata for (for example,
|
||||
* {@code "jdk.internal.event.Example"})
|
||||
*
|
||||
* @return the fully qualified class name of the event
|
||||
*/
|
||||
String className();
|
||||
|
||||
/**
|
||||
* The module where the event is located, by default {@code "java.base"}.
|
||||
*
|
||||
* @return the module name
|
||||
*/
|
||||
String module() default "java.base";
|
||||
}
|
@ -81,9 +81,7 @@ public final class PlatformRecorder {
|
||||
Logger.log(JFR_SYSTEM, INFO, "Registered JDK events");
|
||||
JDKEvents.addInstrumentation();
|
||||
startDiskMonitor();
|
||||
SecuritySupport.registerEvent(ActiveRecordingEvent.class);
|
||||
activeRecordingEvent = EventType.getEventType(ActiveRecordingEvent.class);
|
||||
SecuritySupport.registerEvent(ActiveSettingEvent.class);
|
||||
activeSettingEvent = EventType.getEventType(ActiveSettingEvent.class);
|
||||
shutdownHook = SecuritySupport.createThreadWitNoPermissions("JFR: Shutdown Hook", new ShutdownHook(this));
|
||||
SecuritySupport.setUncaughtExceptionHandler(shutdownHook, new ShutdownHook.ExceptionHandler());
|
||||
@ -91,6 +89,7 @@ public final class PlatformRecorder {
|
||||
timer = createTimer();
|
||||
}
|
||||
|
||||
|
||||
private static Timer createTimer() {
|
||||
try {
|
||||
List<Timer> result = new CopyOnWriteArrayList<>();
|
||||
|
@ -262,8 +262,12 @@ public final class SecuritySupport {
|
||||
Modules.addExports(JFR_MODULE, Utils.HANDLERS_PACKAGE_NAME, clazz.getModule());
|
||||
}
|
||||
|
||||
public static void registerEvent(Class<? extends Event> eventClass) {
|
||||
doPrivileged(() -> FlightRecorder.register(eventClass), new FlightRecorderPermission(Utils.REGISTER_EVENT));
|
||||
public static void registerEvent(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
doPrivileged(() -> MetadataRepository.getInstance().register(eventClass), new FlightRecorderPermission(Utils.REGISTER_EVENT));
|
||||
}
|
||||
|
||||
public static void registerMirror(Class<? extends Event> eventClass) {
|
||||
doPrivileged(() -> MetadataRepository.getInstance().registerMirror(eventClass), new FlightRecorderPermission(Utils.REGISTER_EVENT));
|
||||
}
|
||||
|
||||
static boolean getBooleanProperty(String propertyName) {
|
||||
|
@ -37,7 +37,6 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
|
||||
final class SettingsManager {
|
||||
@ -152,9 +151,9 @@ final class SettingsManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRetransform(List<Class<? extends Event>> eventClasses) {
|
||||
public void updateRetransform(List<Class<? extends jdk.internal.event.Event>> eventClasses) {
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for(Class<? extends Event> eventClass: eventClasses) {
|
||||
for(Class<? extends jdk.internal.event.Event> eventClass: eventClasses) {
|
||||
EventHandler eh = Utils.getHandler(eventClass);
|
||||
if (eh != null ) {
|
||||
PlatformEventType eventType = eh.getPlatformEventType();
|
||||
|
@ -71,10 +71,11 @@ public class Type implements Comparable<Type> {
|
||||
private final String name;
|
||||
private final String superType;
|
||||
private final boolean constantPool;
|
||||
private final long id;
|
||||
private final ArrayList<ValueDescriptor> fields = new ArrayList<>();
|
||||
private Boolean simpleType; // calculated lazy
|
||||
private boolean remove = true;
|
||||
private long id;
|
||||
|
||||
/**
|
||||
* Creates a type
|
||||
*
|
||||
@ -318,4 +319,8 @@ public class Type implements Comparable<Type> {
|
||||
public boolean getRemove() {
|
||||
return remove;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,6 @@ import java.util.stream.Stream;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.MetadataDefinition;
|
||||
import jdk.jfr.Name;
|
||||
@ -240,7 +239,7 @@ public final class TypeLibrary {
|
||||
// STRUCT
|
||||
String superType = null;
|
||||
boolean eventType = false;
|
||||
if (Event.class.isAssignableFrom(clazz)) {
|
||||
if (jdk.internal.event.Event.class.isAssignableFrom(clazz)) {
|
||||
superType = Type.SUPER_TYPE_EVENT;
|
||||
eventType= true;
|
||||
}
|
||||
@ -489,4 +488,8 @@ public final class TypeLibrary {
|
||||
aQ.addAll(ae.getAnnotationElements());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeType(long id) {
|
||||
types.remove(id);
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ public final class Utils {
|
||||
return (long) (nanos * JVM.getJVM().getTimeConversionFactor());
|
||||
}
|
||||
|
||||
static synchronized EventHandler getHandler(Class<? extends Event> eventClass) {
|
||||
static synchronized EventHandler getHandler(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
try {
|
||||
Field f = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
|
||||
@ -278,7 +278,7 @@ public final class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
static synchronized void setHandler(Class<? extends Event> eventClass, EventHandler handler) {
|
||||
static synchronized void setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler) {
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
try {
|
||||
Field field = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
|
||||
@ -322,7 +322,7 @@ public final class Utils {
|
||||
static List<Field> getVisibleEventFields(Class<?> clazz) {
|
||||
Utils.ensureValidEventSubclass(clazz);
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Class<?> c = clazz; c != Event.class; c = c.getSuperclass()) {
|
||||
for (Class<?> c = clazz; c != jdk.internal.event.Event.class; c = c.getSuperclass()) {
|
||||
for (Field field : c.getDeclaredFields()) {
|
||||
// skip private field in base classes
|
||||
if (c == clazz || !Modifier.isPrivate(field.getModifiers())) {
|
||||
@ -334,10 +334,10 @@ public final class Utils {
|
||||
}
|
||||
|
||||
public static void ensureValidEventSubclass(Class<?> eventClass) {
|
||||
if (Event.class.isAssignableFrom(eventClass) && Modifier.isAbstract(eventClass.getModifiers())) {
|
||||
if (jdk.internal.event.Event.class.isAssignableFrom(eventClass) && Modifier.isAbstract(eventClass.getModifiers())) {
|
||||
throw new IllegalArgumentException("Abstract event classes are not allowed");
|
||||
}
|
||||
if (eventClass == Event.class || !Event.class.isAssignableFrom(eventClass)) {
|
||||
if (eventClass == Event.class || eventClass == jdk.internal.event.Event.class || !jdk.internal.event.Event.class.isAssignableFrom(eventClass)) {
|
||||
throw new IllegalArgumentException("Must be a subclass to " + Event.class.getName());
|
||||
}
|
||||
}
|
||||
@ -366,7 +366,7 @@ public final class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureInitialized(Class<? extends Event> eventClass) {
|
||||
public static void ensureInitialized(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||
SecuritySupport.ensureClassIsInitialized(eventClass);
|
||||
}
|
||||
|
||||
@ -499,6 +499,50 @@ public final class Utils {
|
||||
return eventName;
|
||||
}
|
||||
|
||||
public static void verifyMirror(Class<?> mirror, Class<?> real) {
|
||||
Class<?> cMirror = Objects.requireNonNull(mirror);
|
||||
Class<?> cReal = Objects.requireNonNull(real);
|
||||
|
||||
while (cReal != null) {
|
||||
Map<String, Field> mirrorFields = new HashMap<>();
|
||||
if (cMirror != null) {
|
||||
for (Field f : cMirror.getDeclaredFields()) {
|
||||
if (isSupportedType(f.getType())) {
|
||||
mirrorFields.put(f.getName(), f);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Field realField : cReal.getDeclaredFields()) {
|
||||
if (isSupportedType(realField.getType())) {
|
||||
String fieldName = realField.getName();
|
||||
Field mirrorField = mirrorFields.get(fieldName);
|
||||
if (mirrorField == null) {
|
||||
throw new InternalError("Missing mirror field for " + cReal.getName() + "#" + fieldName);
|
||||
}
|
||||
if (realField.getModifiers() != mirrorField.getModifiers()) {
|
||||
throw new InternalError("Incorrect modifier for mirror field "+ cMirror.getName() + "#" + fieldName);
|
||||
}
|
||||
mirrorFields.remove(fieldName);
|
||||
}
|
||||
}
|
||||
if (!mirrorFields.isEmpty()) {
|
||||
throw new InternalError(
|
||||
"Found additional fields in mirror class " + cMirror.getName() + " " + mirrorFields.keySet());
|
||||
}
|
||||
if (cMirror != null) {
|
||||
cMirror = cMirror.getSuperclass();
|
||||
}
|
||||
cReal = cReal.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSupportedType(Class<?> type) {
|
||||
if (Modifier.isTransient(type.getModifiers()) || Modifier.isStatic(type.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
return Type.isValidJavaFieldType(type.getName());
|
||||
}
|
||||
|
||||
public static String makeFilename(Recording recording) {
|
||||
String pid = JVM.getJVM().getPid();
|
||||
String date = Repository.REPO_DATE_FORMAT.format(LocalDateTime.now());
|
||||
|
@ -51,6 +51,9 @@ import jdk.jfr.internal.Utils;
|
||||
|
||||
public final class JDKEvents {
|
||||
|
||||
private static final Class<?>[] mirrorEventClasses = {
|
||||
};
|
||||
|
||||
private static final Class<?>[] eventClasses = {
|
||||
FileForceEvent.class,
|
||||
FileReadEvent.class,
|
||||
@ -90,6 +93,9 @@ public final class JDKEvents {
|
||||
Modules.addExports(jdkJfrModule, Utils.EVENTS_PACKAGE_NAME, javaBaseModule);
|
||||
Modules.addExports(jdkJfrModule, Utils.INSTRUMENT_PACKAGE_NAME, javaBaseModule);
|
||||
Modules.addExports(jdkJfrModule, Utils.HANDLERS_PACKAGE_NAME, javaBaseModule);
|
||||
for (Class<?> mirrorEventClass : mirrorEventClasses) {
|
||||
SecuritySupport.registerMirror(((Class<? extends Event>)mirrorEventClass));
|
||||
}
|
||||
for (Class<?> eventClass : eventClasses) {
|
||||
SecuritySupport.registerEvent((Class<? extends Event>) eventClass);
|
||||
}
|
||||
|
@ -104,8 +104,9 @@ public class TestGetAllEventClasses {
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static void assertEvents(JVM jvm, boolean inclusion, Class<? extends Event>... targetEvents) {
|
||||
final List<Class<? extends Event>> list = jvm.getAllEventClasses();
|
||||
final List list = jvm.getAllEventClasses();
|
||||
for (Class<? extends Event> ev : targetEvents) {
|
||||
if (list.contains(ev)) {
|
||||
if (inclusion) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user