mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8203629: Produce events in the JDK without a dependency on jdk.jfr
Reviewed-by: mgronlun
This commit is contained in:
parent
7d2ac4cc31
commit
ba18b569ef
22 changed files with 444 additions and 136 deletions
|
@ -27,6 +27,8 @@
|
||||||
#include "classfile/classFileParser.hpp"
|
#include "classfile/classFileParser.hpp"
|
||||||
#include "classfile/classFileStream.hpp"
|
#include "classfile/classFileStream.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
#include "classfile/moduleEntry.hpp"
|
||||||
|
#include "classfile/modules.hpp"
|
||||||
#include "classfile/stackMapTable.hpp"
|
#include "classfile/stackMapTable.hpp"
|
||||||
#include "classfile/verificationType.hpp"
|
#include "classfile/verificationType.hpp"
|
||||||
#include "interpreter/bytecodes.hpp"
|
#include "interpreter/bytecodes.hpp"
|
||||||
|
@ -61,25 +63,26 @@ static const char* utf8_constants[] = {
|
||||||
"J", // 1
|
"J", // 1
|
||||||
"commit", // 2
|
"commit", // 2
|
||||||
"eventHandler", // 3
|
"eventHandler", // 3
|
||||||
"Ljdk/jfr/internal/handlers/EventHandler;", // 4
|
"duration", // 4
|
||||||
"duration", // 5
|
"begin", // 5
|
||||||
"begin", // 6
|
"()V", // 6
|
||||||
"()V", // 7
|
"isEnabled", // 7
|
||||||
"isEnabled", // 8
|
"()Z", // 8
|
||||||
"()Z", // 9
|
"end", // 9
|
||||||
"end", // 10
|
"shouldCommit", // 10
|
||||||
"shouldCommit", // 11
|
"startTime", // 11 // LAST_REQUIRED_UTF8
|
||||||
"startTime", // 12
|
"Ljdk/jfr/internal/handlers/EventHandler;", // 12
|
||||||
"<clinit>", // 13
|
"Ljava/lang/Object;", // 13
|
||||||
"jdk/jfr/FlightRecorder", // 14
|
"<clinit>", // 14
|
||||||
"register", // 15
|
"jdk/jfr/FlightRecorder", // 15
|
||||||
"(Ljava/lang/Class;)V", // 16 // LAST_REQUIRED_UTF8
|
"register", // 16
|
||||||
"StackMapTable", // 17
|
"(Ljava/lang/Class;)V", // 17
|
||||||
"Exceptions", // 18
|
"StackMapTable", // 18
|
||||||
|
"Exceptions", // 19
|
||||||
"LineNumberTable", // 20
|
"LineNumberTable", // 20
|
||||||
"LocalVariableTable", // 21
|
"LocalVariableTable", // 21
|
||||||
"LocalVariableTypeTable", // 22
|
"LocalVariableTypeTable", // 22
|
||||||
"RuntimeVisibleAnnotation" // 23
|
"RuntimeVisibleAnnotation", // 23
|
||||||
};
|
};
|
||||||
|
|
||||||
enum utf8_req_symbols {
|
enum utf8_req_symbols {
|
||||||
|
@ -87,7 +90,6 @@ enum utf8_req_symbols {
|
||||||
UTF8_REQ_J_FIELD_DESC,
|
UTF8_REQ_J_FIELD_DESC,
|
||||||
UTF8_REQ_commit,
|
UTF8_REQ_commit,
|
||||||
UTF8_REQ_eventHandler,
|
UTF8_REQ_eventHandler,
|
||||||
UTF8_REQ_eventHandler_FIELD_DESC,
|
|
||||||
UTF8_REQ_duration,
|
UTF8_REQ_duration,
|
||||||
UTF8_REQ_begin,
|
UTF8_REQ_begin,
|
||||||
UTF8_REQ_EMPTY_VOID_METHOD_DESC,
|
UTF8_REQ_EMPTY_VOID_METHOD_DESC,
|
||||||
|
@ -96,15 +98,17 @@ enum utf8_req_symbols {
|
||||||
UTF8_REQ_end,
|
UTF8_REQ_end,
|
||||||
UTF8_REQ_shouldCommit,
|
UTF8_REQ_shouldCommit,
|
||||||
UTF8_REQ_startTime,
|
UTF8_REQ_startTime,
|
||||||
UTF8_REQ_clinit,
|
|
||||||
UTF8_REQ_FlightRecorder,
|
|
||||||
UTF8_REQ_register,
|
|
||||||
UTF8_REQ_CLASS_VOID_METHOD_DESC,
|
|
||||||
NOF_UTF8_REQ_SYMBOLS
|
NOF_UTF8_REQ_SYMBOLS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum utf8_opt_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_Exceptions,
|
||||||
UTF8_OPT_LineNumberTable,
|
UTF8_OPT_LineNumberTable,
|
||||||
UTF8_OPT_LocalVariableTable,
|
UTF8_OPT_LocalVariableTable,
|
||||||
|
@ -353,7 +357,7 @@ class AnnotationIterator : public StackObj {
|
||||||
|
|
||||||
static unsigned int unused_hash = 0;
|
static unsigned int unused_hash = 0;
|
||||||
static const char value_name[] = "value";
|
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");
|
assert(annotation_type != NULL, "invariant");
|
||||||
AnnotationArray* class_annotations = ik->class_annotations();
|
AnnotationArray* class_annotations = ik->class_annotations();
|
||||||
if (class_annotations == NULL) {
|
if (class_annotations == NULL) {
|
||||||
|
@ -383,16 +387,51 @@ static bool has_registered_annotation(const InstanceKlass* ik, const Symbol* ann
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool registered_annotation_value(const InstanceKlass* ik, const Symbol* const registered_symbol) {
|
// Evaluate to the value of the first found Symbol* annotation type.
|
||||||
assert(registered_symbol != NULL, "invariant");
|
// 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(ik != NULL, "invariant");
|
||||||
|
assert(annotation_type != NULL, "invariant");
|
||||||
assert(JdkJfrEvent::is_a(ik), "invariant");
|
assert(JdkJfrEvent::is_a(ik), "invariant");
|
||||||
bool registered_value = false;
|
if (has_annotation(ik, annotation_type, value)) {
|
||||||
if (has_registered_annotation(ik, registered_symbol, registered_value)) {
|
return true;
|
||||||
return registered_value;
|
|
||||||
}
|
}
|
||||||
InstanceKlass* super = InstanceKlass::cast(ik->super());
|
InstanceKlass* const super = InstanceKlass::cast(ik->super());
|
||||||
return registered_annotation_value(super, registered_symbol);
|
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;";
|
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.
|
// Evaluate to the value of the first found "Ljdk/jfr/Registered;" annotation.
|
||||||
// Searching moves upwards in the klass hierarchy in order to support
|
// Searching moves upwards in the klass hierarchy in order to support
|
||||||
// inherited annotations in addition to the ability to override.
|
// inherited annotations in addition to the ability to override.
|
||||||
static bool should_register_klass(const InstanceKlass* ik) {
|
static bool should_register_klass(const InstanceKlass* ik, bool& untypedEventHandler) {
|
||||||
static const Symbol* const registered_symbol = SymbolTable::lookup_only(registered_constant,
|
assert(ik != NULL, "invariant");
|
||||||
sizeof registered_constant - 1,
|
assert(JdkJfrEvent::is_a(ik), "invariant");
|
||||||
unused_hash);
|
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");
|
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
|
* 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 orig_cp_len,
|
||||||
u2& number_of_new_constants,
|
u2& number_of_new_constants,
|
||||||
TRAPS) {
|
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(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(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");
|
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) {
|
TRAPS) {
|
||||||
assert(utf8_indexes != NULL, "invariant");
|
assert(utf8_indexes != NULL, "invariant");
|
||||||
return add_method_ref_info(writer,
|
return add_method_ref_info(writer,
|
||||||
utf8_indexes[UTF8_REQ_FlightRecorder],
|
utf8_indexes[UTF8_OPT_FlightRecorder],
|
||||||
utf8_indexes[UTF8_REQ_register],
|
utf8_indexes[UTF8_OPT_register],
|
||||||
utf8_indexes[UTF8_REQ_CLASS_VOID_METHOD_DESC],
|
utf8_indexes[UTF8_OPT_CLASS_VOID_METHOD_DESC],
|
||||||
orig_cp_len,
|
orig_cp_len,
|
||||||
number_of_new_constants,
|
number_of_new_constants,
|
||||||
THREAD);
|
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) {
|
static jlong add_field_info(JfrBigEndianWriter& writer, u2 name_index, u2 desc_index, bool is_static = false) {
|
||||||
assert(name_index > 0, "invariant");
|
assert(name_index != invalid_cp_index, "invariant");
|
||||||
assert(desc_index > 0, "invariant");
|
assert(desc_index != invalid_cp_index, "invariant");
|
||||||
DEBUG_ONLY(const jlong start_offset = writer.current_offset();)
|
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<u2>(JVM_ACC_SYNTHETIC | JVM_ACC_PRIVATE | (is_static ? JVM_ACC_STATIC : JVM_ACC_TRANSIENT)); // flags
|
||||||
writer.write(name_index);
|
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();
|
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");
|
assert(utf8_indexes != NULL, "invariant");
|
||||||
add_field_info(writer,
|
add_field_info(writer,
|
||||||
utf8_indexes[UTF8_REQ_eventHandler],
|
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
|
true); // static
|
||||||
|
|
||||||
add_field_info(writer,
|
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
|
// This is to ensure that padding can be done
|
||||||
// where needed and to simplify size calculations.
|
// where needed and to simplify size calculations.
|
||||||
static const u2 injected_code_length = 8;
|
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 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_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);
|
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* const utf8_indexes,
|
||||||
u2 orig_cp_len,
|
u2 orig_cp_len,
|
||||||
const Method* clinit_method,
|
const Method* clinit_method,
|
||||||
|
bool register_klass,
|
||||||
|
bool untypedEventHandler,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
assert(utf8_indexes != NULL, "invariant");
|
assert(utf8_indexes != NULL, "invariant");
|
||||||
u2 added_cp_entries = 0;
|
u2 added_cp_entries = 0;
|
||||||
// resolve all required symbols
|
// resolve all required symbols
|
||||||
for (u2 index = 0; index < NOF_UTF8_REQ_SYMBOLS; ++index) {
|
for (u2 index = 0; index < NOF_UTF8_REQ_SYMBOLS; ++index) {
|
||||||
utf8_indexes[index] = find_or_add_utf8_info(writer,
|
utf8_indexes[index] = find_or_add_utf8_info(writer, ik, utf8_constants[index], orig_cp_len, added_cp_entries, THREAD);
|
||||||
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()) {
|
if (clinit_method != NULL && clinit_method->has_stackmap_table()) {
|
||||||
utf8_indexes[UTF8_OPT_StackMapTable] =
|
utf8_indexes[UTF8_OPT_StackMapTable] =
|
||||||
find_or_add_utf8_info(writer,
|
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_StackMapTable], orig_cp_len, added_cp_entries, THREAD);
|
||||||
ik,
|
|
||||||
utf8_constants[UTF8_OPT_StackMapTable],
|
|
||||||
orig_cp_len,
|
|
||||||
added_cp_entries,
|
|
||||||
THREAD);
|
|
||||||
} else {
|
} else {
|
||||||
utf8_indexes[UTF8_OPT_StackMapTable] = invalid_cp_index;
|
utf8_indexes[UTF8_OPT_StackMapTable] = invalid_cp_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clinit_method != NULL && clinit_method->has_linenumber_table()) {
|
if (clinit_method != NULL && clinit_method->has_linenumber_table()) {
|
||||||
utf8_indexes[UTF8_OPT_LineNumberTable] =
|
utf8_indexes[UTF8_OPT_LineNumberTable] =
|
||||||
find_or_add_utf8_info(writer,
|
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LineNumberTable], orig_cp_len, added_cp_entries, THREAD);
|
||||||
ik,
|
|
||||||
utf8_constants[UTF8_OPT_LineNumberTable],
|
|
||||||
orig_cp_len,
|
|
||||||
added_cp_entries,
|
|
||||||
THREAD);
|
|
||||||
} else {
|
} else {
|
||||||
utf8_indexes[UTF8_OPT_LineNumberTable] = invalid_cp_index;
|
utf8_indexes[UTF8_OPT_LineNumberTable] = invalid_cp_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clinit_method != NULL && clinit_method->has_localvariable_table()) {
|
if (clinit_method != NULL && clinit_method->has_localvariable_table()) {
|
||||||
utf8_indexes[UTF8_OPT_LocalVariableTable] =
|
utf8_indexes[UTF8_OPT_LocalVariableTable] =
|
||||||
find_or_add_utf8_info(writer,
|
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LocalVariableTable], orig_cp_len, added_cp_entries, THREAD);
|
||||||
ik,
|
|
||||||
utf8_constants[UTF8_OPT_LocalVariableTable],
|
|
||||||
orig_cp_len,
|
|
||||||
added_cp_entries,
|
|
||||||
THREAD);
|
|
||||||
|
|
||||||
utf8_indexes[UTF8_OPT_LocalVariableTypeTable] =
|
utf8_indexes[UTF8_OPT_LocalVariableTypeTable] =
|
||||||
find_or_add_utf8_info(writer,
|
find_or_add_utf8_info(writer, ik, utf8_constants[UTF8_OPT_LocalVariableTypeTable], orig_cp_len, added_cp_entries, THREAD);
|
||||||
ik,
|
|
||||||
utf8_constants[UTF8_OPT_LocalVariableTypeTable],
|
|
||||||
orig_cp_len,
|
|
||||||
added_cp_entries,
|
|
||||||
THREAD);
|
|
||||||
} else {
|
} else {
|
||||||
utf8_indexes[UTF8_OPT_LocalVariableTable] = invalid_cp_index;
|
utf8_indexes[UTF8_OPT_LocalVariableTable] = invalid_cp_index;
|
||||||
utf8_indexes[UTF8_OPT_LocalVariableTypeTable] = 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
|
// If the class already has a clinit method
|
||||||
// we need to take that into account
|
// we need to take that into account
|
||||||
const Method* clinit_method = ik->class_initializer();
|
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 ClassFileStream* const orig_stream = parser.clone_stream();
|
||||||
const int orig_stream_size = orig_stream->length();
|
const int orig_stream_size = orig_stream->length();
|
||||||
assert(orig_stream->current_offset() == 0, "invariant");
|
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
|
// Resolve_utf8_indexes will be conservative in attempting to
|
||||||
// locate an existing UTF8_INFO; it will only append constants
|
// locate an existing UTF8_INFO; it will only append constants
|
||||||
// that is absolutely required
|
// 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
|
// UTF8_INFO entries now added to the constant pool
|
||||||
// In order to invoke a method we would need additional
|
// In order to invoke a method we would need additional
|
||||||
// constants, JVM_CONSTANT_Class, JVM_CONSTANT_NameAndType
|
// 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");
|
assert(writer.is_valid(), "invariant");
|
||||||
// We are sitting just after the original number of field_infos
|
// We are sitting just after the original number of field_infos
|
||||||
// so this is a position where we can add (append) new 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");
|
assert(writer.is_valid(), "invariant");
|
||||||
const jlong new_method_len_offset = writer.current_offset();
|
const jlong new_method_len_offset = writer.current_offset();
|
||||||
// Additional field_infos added, update classfile fields_count
|
// 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));
|
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||||
initialize(THREAD);
|
initialize(THREAD);
|
||||||
assert(empty_java_util_arraylist != NULL, "should have been setup already!");
|
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;
|
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);
|
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;
|
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 bool found_jdk_jfr_event_klass = false;
|
||||||
|
|
||||||
static void check_klass(const Klass* klass) {
|
static void check_klass(const Klass* klass) {
|
||||||
assert(klass != NULL, "invariant");
|
assert(klass != NULL, "invariant");
|
||||||
if (found_jdk_jfr_event_klass) {
|
if (found_jdk_internal_event_klass && found_jdk_jfr_event_klass) {
|
||||||
return;
|
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;
|
static const Symbol* jdk_jfr_event_sym = NULL;
|
||||||
if (jdk_jfr_event_sym == NULL) {
|
if (jdk_jfr_event_sym == NULL) {
|
||||||
// setup when loading the first TypeArrayKlass (Universe::genesis) hence single threaded invariant
|
// 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());
|
jdk_jfr_event_sym = SymbolTable::new_permanent_symbol("jdk/jfr/Event", Thread::current());
|
||||||
}
|
}
|
||||||
assert(jdk_jfr_event_sym != NULL, "invariant");
|
assert(jdk_jfr_event_sym != NULL, "invariant");
|
||||||
if (jdk_jfr_event_sym == klass->name() && klass->class_loader() == NULL) {
|
const Symbol* const klass_name = klass->name();
|
||||||
found_jdk_jfr_event_klass = true;
|
|
||||||
JfrTraceId::tag_as_jdk_jfr_event(klass);
|
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) {
|
inline void JfrTraceId::tag_as_jdk_jfr_event(const Klass* klass) {
|
||||||
assert(klass != NULL, "invariant");
|
assert(klass != NULL, "invariant");
|
||||||
assert(IS_NOT_AN_EVENT_KLASS(klass), "invariant");
|
|
||||||
SET_TAG(klass, JDK_JFR_EVENT_KLASS);
|
SET_TAG(klass, JDK_JFR_EVENT_KLASS);
|
||||||
assert(IS_JDK_JFR_EVENT_KLASS(klass), "invariant");
|
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) {
|
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) {
|
inline void JfrTraceId::tag_as_jdk_jfr_event_sub(const Klass* k) {
|
||||||
assert(k != NULL, "invariant");
|
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);
|
SET_TAG(k, JDK_JFR_EVENT_SUBKLASS);
|
||||||
}
|
}
|
||||||
assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
|
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;
|
java.security.sasl;
|
||||||
exports jdk.internal to
|
exports jdk.internal to
|
||||||
jdk.jfr;
|
jdk.jfr;
|
||||||
|
exports jdk.internal.event to
|
||||||
|
jdk.jfr;
|
||||||
exports jdk.internal.jimage to
|
exports jdk.internal.jimage to
|
||||||
jdk.jlink;
|
jdk.jlink;
|
||||||
exports jdk.internal.jimage.decompressor to
|
exports jdk.internal.jimage.decompressor to
|
||||||
|
|
|
@ -88,7 +88,7 @@ package jdk.jfr;
|
||||||
@Enabled(true)
|
@Enabled(true)
|
||||||
@StackTrace(true)
|
@StackTrace(true)
|
||||||
@Registered(true)
|
@Registered(true)
|
||||||
abstract public class Event {
|
abstract public class Event extends jdk.internal.event.Event {
|
||||||
/**
|
/**
|
||||||
* Sole constructor, for invocation by subclass constructors, typically
|
* Sole constructor, for invocation by subclass constructors, typically
|
||||||
* implicit.
|
* implicit.
|
||||||
|
|
|
@ -41,7 +41,6 @@ import java.util.Set;
|
||||||
import jdk.internal.module.Modules;
|
import jdk.internal.module.Modules;
|
||||||
import jdk.jfr.AnnotationElement;
|
import jdk.jfr.AnnotationElement;
|
||||||
import jdk.jfr.Enabled;
|
import jdk.jfr.Enabled;
|
||||||
import jdk.jfr.Event;
|
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
import jdk.jfr.Period;
|
import jdk.jfr.Period;
|
||||||
import jdk.jfr.SettingControl;
|
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);
|
this(es);
|
||||||
defineSettings(eventClass);
|
defineSettings(eventClass);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,11 +93,11 @@ final class EventHandlerCreator {
|
||||||
return EventHandler.class.getName() + id + SUFFIX;
|
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));
|
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<>();
|
List<FieldInfo> fieldInfos = new ArrayList<>();
|
||||||
for (ValueDescriptor v : type.getFields()) {
|
for (ValueDescriptor v : type.getFields()) {
|
||||||
// Only value descriptors that are not fields on the event class.
|
// 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 ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class);
|
||||||
private static final Type TYPE_EVENT_HANDLER = Type.getType(EventHandler.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_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_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]);
|
||||||
private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]);
|
private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]);
|
||||||
private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]);
|
private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]);
|
||||||
|
@ -117,6 +118,7 @@ public final class EventInstrumentation {
|
||||||
private final Method writeMethod;
|
private final Method writeMethod;
|
||||||
private final String eventHandlerXInternalName;
|
private final String eventHandlerXInternalName;
|
||||||
private final String eventName;
|
private final String eventName;
|
||||||
|
private final boolean untypedEventHandler;
|
||||||
private boolean guardHandlerReference;
|
private boolean guardHandlerReference;
|
||||||
private Class<?> superClass;
|
private Class<?> superClass;
|
||||||
|
|
||||||
|
@ -125,11 +127,20 @@ public final class EventInstrumentation {
|
||||||
this.classNode = createClassNode(bytes);
|
this.classNode = createClassNode(bytes);
|
||||||
this.settingInfos = buildSettingInfos(superClass, classNode);
|
this.settingInfos = buildSettingInfos(superClass, classNode);
|
||||||
this.fieldInfos = buildFieldInfos(superClass, classNode);
|
this.fieldInfos = buildFieldInfos(superClass, classNode);
|
||||||
|
this.untypedEventHandler = hasUntypedHandler();
|
||||||
this.writeMethod = makeWriteMethod(fieldInfos);
|
this.writeMethod = makeWriteMethod(fieldInfos);
|
||||||
this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id));
|
this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id));
|
||||||
String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class);
|
String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class);
|
||||||
this.eventName = n == null ? classNode.name.replace("/", ".") : n;
|
this.eventName = n == null ? classNode.name.replace("/", ".") : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
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()) {
|
for (java.lang.reflect.Method method : c.getDeclaredMethods()) {
|
||||||
if (!methodSet.contains(method.getName())) {
|
if (!methodSet.contains(method.getName())) {
|
||||||
// skip private method in base classes
|
// skip private method in base classes
|
||||||
|
@ -249,7 +260,6 @@ public final class EventInstrumentation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return settingInfos;
|
return settingInfos;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
|
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("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
||||||
fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
||||||
for (FieldNode field : classNode.fields) {
|
for (FieldNode field : classNode.fields) {
|
||||||
String className = Type.getType(field.desc).getClassName();
|
if (!fieldSet.contains(field.name) && isValidField(field.access, Type.getType(field.desc).getClassName())) {
|
||||||
if (!fieldSet.contains(field.name) && isValidField(field.access, className)) {
|
|
||||||
FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name);
|
FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name);
|
||||||
fieldInfos.add(fi);
|
fieldInfos.add(fi);
|
||||||
fieldSet.add(field.name);
|
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()) {
|
for (Field field : c.getDeclaredFields()) {
|
||||||
// skip private field in base classes
|
// skip private field in base classes
|
||||||
if (!Modifier.isPrivate(field.getModifiers())) {
|
if (!Modifier.isPrivate(field.getModifiers())) {
|
||||||
|
@ -321,10 +330,10 @@ public final class EventInstrumentation {
|
||||||
updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
|
updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
|
||||||
Label nullLabel = new Label();
|
Label nullLabel = new Label();
|
||||||
if (guardHandlerReference) {
|
if (guardHandlerReference) {
|
||||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
|
getEventHandler(methodVisitor);
|
||||||
methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel);
|
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);
|
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED);
|
||||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||||
if (guardHandlerReference) {
|
if (guardHandlerReference) {
|
||||||
|
@ -408,7 +417,7 @@ public final class EventInstrumentation {
|
||||||
// eventHandler.write(...);
|
// eventHandler.write(...);
|
||||||
// }
|
// }
|
||||||
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
|
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
|
||||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
getEventHandler(methodVisitor);
|
||||||
|
|
||||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
||||||
for (FieldInfo fi : fieldInfos) {
|
for (FieldInfo fi : fieldInfos) {
|
||||||
|
@ -426,8 +435,8 @@ public final class EventInstrumentation {
|
||||||
// MyEvent#shouldCommit()
|
// MyEvent#shouldCommit()
|
||||||
updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
|
updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
|
||||||
Label fail = new Label();
|
Label fail = new Label();
|
||||||
// if (!eventHandler.shoouldCommit(duration) goto fail;
|
// if (!eventHandler.shouldCommit(duration) goto fail;
|
||||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(EventHandler.class));
|
getEventHandler(methodVisitor);
|
||||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
|
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
|
||||||
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT);
|
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT);
|
||||||
|
@ -435,7 +444,11 @@ public final class EventInstrumentation {
|
||||||
for (SettingInfo si : settingInfos) {
|
for (SettingInfo si : settingInfos) {
|
||||||
// if (!settingsMethod(eventHandler.settingX)) goto fail;
|
// if (!settingsMethod(eventHandler.settingX)) goto fail;
|
||||||
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
|
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.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
||||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
|
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
|
||||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName);
|
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() {
|
private void makeUninstrumented() {
|
||||||
updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT);
|
updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT);
|
||||||
updateExistingWithReturnFalse(METHOD_IS_ENABLED);
|
updateExistingWithReturnFalse(METHOD_IS_ENABLED);
|
||||||
|
|
|
@ -106,11 +106,11 @@ public final class JVM {
|
||||||
public native void endRecording();
|
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.
|
* @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}
|
* 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 java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import jdk.jfr.Event;
|
|
||||||
import jdk.jfr.internal.handlers.EventHandler;
|
import jdk.jfr.internal.handlers.EventHandler;
|
||||||
import jdk.jfr.internal.instrument.JDKEvents;
|
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 {
|
static byte[] onRetransform(long traceId, boolean dummy, Class<?> clazz, byte[] oldBytes) throws Throwable {
|
||||||
try {
|
try {
|
||||||
if (Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
|
if (jdk.internal.event.Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
|
||||||
EventHandler handler = Utils.getHandler(clazz.asSubclass(Event.class));
|
EventHandler handler = Utils.getHandler(clazz.asSubclass(jdk.internal.event.Event.class));
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request.");
|
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request.");
|
||||||
// Probably triggered by some other agent
|
// Probably triggered by some other agent
|
||||||
|
|
|
@ -33,6 +33,7 @@ import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -56,6 +57,7 @@ public final class MetadataRepository {
|
||||||
private final List<EventControl> nativeControls = new ArrayList<EventControl>(100);
|
private final List<EventControl> nativeControls = new ArrayList<EventControl>(100);
|
||||||
private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
|
private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
|
||||||
private final SettingsManager settingsManager = new SettingsManager();
|
private final SettingsManager settingsManager = new SettingsManager();
|
||||||
|
private final Map<String, Class<? extends Event>> mirrors = new HashMap<>();
|
||||||
private boolean staleMetadata = true;
|
private boolean staleMetadata = true;
|
||||||
private boolean unregistered;
|
private boolean unregistered;
|
||||||
private long lastUnloaded = -1;
|
private long lastUnloaded = -1;
|
||||||
|
@ -105,7 +107,7 @@ public final class MetadataRepository {
|
||||||
return eventTypes;
|
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);
|
EventHandler h = getHandler(eventClass);
|
||||||
if (h != null && h.isRegistered()) {
|
if (h != null && h.isRegistered()) {
|
||||||
return h.getEventType();
|
return h.getEventType();
|
||||||
|
@ -121,15 +123,20 @@ public final class MetadataRepository {
|
||||||
}
|
}
|
||||||
// never registered, ignore call
|
// 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());
|
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();
|
Utils.checkRegisterPermission();
|
||||||
EventHandler handler = getHandler(eventClass);
|
EventHandler handler = getHandler(eventClass);
|
||||||
if (handler == null) {
|
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);
|
handler.setRegistered(true);
|
||||||
typeLibrary.addType(handler.getPlatformEventType());
|
typeLibrary.addType(handler.getPlatformEventType());
|
||||||
|
@ -143,16 +150,32 @@ public final class MetadataRepository {
|
||||||
return handler.getEventType();
|
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);
|
Utils.ensureValidEventSubclass(eventClass);
|
||||||
SecuritySupport.makeVisibleToJFR(eventClass);
|
SecuritySupport.makeVisibleToJFR(eventClass);
|
||||||
Utils.ensureInitialized(eventClass);
|
Utils.ensureInitialized(eventClass);
|
||||||
return Utils.getHandler(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);
|
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);
|
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
|
||||||
EventControl ec = new EventControl(pEventType, eventClass);
|
EventControl ec = new EventControl(pEventType, eventClass);
|
||||||
Class<? extends EventHandler> handlerClass = null;
|
Class<? extends EventHandler> handlerClass = null;
|
||||||
|
@ -198,9 +221,9 @@ public final class MetadataRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<EventHandler> getEventHandlers() {
|
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());
|
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);
|
EventHandler eh = Utils.getHandler(clazz);
|
||||||
if (eh != null) {
|
if (eh != null) {
|
||||||
eventHandlers.add(eh);
|
eventHandlers.add(eh);
|
||||||
|
@ -252,9 +275,9 @@ public final class MetadataRepository {
|
||||||
long unloaded = jvm.getUnloadedEventClassCount();
|
long unloaded = jvm.getUnloadedEventClassCount();
|
||||||
if (this.lastUnloaded != unloaded) {
|
if (this.lastUnloaded != unloaded) {
|
||||||
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());
|
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));
|
knownIds.add(Type.getTypeId(ec));
|
||||||
}
|
}
|
||||||
for (Type type : typeLibrary.getTypes()) {
|
for (Type type : typeLibrary.getTypes()) {
|
||||||
|
@ -270,8 +293,18 @@ public final class MetadataRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized public void setUnregistered() {
|
synchronized void setUnregistered() {
|
||||||
unregistered = true;
|
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");
|
Logger.log(JFR_SYSTEM, INFO, "Registered JDK events");
|
||||||
JDKEvents.addInstrumentation();
|
JDKEvents.addInstrumentation();
|
||||||
startDiskMonitor();
|
startDiskMonitor();
|
||||||
SecuritySupport.registerEvent(ActiveRecordingEvent.class);
|
|
||||||
activeRecordingEvent = EventType.getEventType(ActiveRecordingEvent.class);
|
activeRecordingEvent = EventType.getEventType(ActiveRecordingEvent.class);
|
||||||
SecuritySupport.registerEvent(ActiveSettingEvent.class);
|
|
||||||
activeSettingEvent = EventType.getEventType(ActiveSettingEvent.class);
|
activeSettingEvent = EventType.getEventType(ActiveSettingEvent.class);
|
||||||
shutdownHook = SecuritySupport.createThreadWitNoPermissions("JFR: Shutdown Hook", new ShutdownHook(this));
|
shutdownHook = SecuritySupport.createThreadWitNoPermissions("JFR: Shutdown Hook", new ShutdownHook(this));
|
||||||
SecuritySupport.setUncaughtExceptionHandler(shutdownHook, new ShutdownHook.ExceptionHandler());
|
SecuritySupport.setUncaughtExceptionHandler(shutdownHook, new ShutdownHook.ExceptionHandler());
|
||||||
|
@ -91,6 +89,7 @@ public final class PlatformRecorder {
|
||||||
timer = createTimer();
|
timer = createTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Timer createTimer() {
|
private static Timer createTimer() {
|
||||||
try {
|
try {
|
||||||
List<Timer> result = new CopyOnWriteArrayList<>();
|
List<Timer> result = new CopyOnWriteArrayList<>();
|
||||||
|
|
|
@ -262,8 +262,12 @@ public final class SecuritySupport {
|
||||||
Modules.addExports(JFR_MODULE, Utils.HANDLERS_PACKAGE_NAME, clazz.getModule());
|
Modules.addExports(JFR_MODULE, Utils.HANDLERS_PACKAGE_NAME, clazz.getModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerEvent(Class<? extends Event> eventClass) {
|
public static void registerEvent(Class<? extends jdk.internal.event.Event> eventClass) {
|
||||||
doPrivileged(() -> FlightRecorder.register(eventClass), new FlightRecorderPermission(Utils.REGISTER_EVENT));
|
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) {
|
static boolean getBooleanProperty(String propertyName) {
|
||||||
|
|
|
@ -37,7 +37,6 @@ import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
import jdk.jfr.Event;
|
|
||||||
import jdk.jfr.internal.handlers.EventHandler;
|
import jdk.jfr.internal.handlers.EventHandler;
|
||||||
|
|
||||||
final class SettingsManager {
|
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<>();
|
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);
|
EventHandler eh = Utils.getHandler(eventClass);
|
||||||
if (eh != null ) {
|
if (eh != null ) {
|
||||||
PlatformEventType eventType = eh.getPlatformEventType();
|
PlatformEventType eventType = eh.getPlatformEventType();
|
||||||
|
|
|
@ -71,10 +71,11 @@ public class Type implements Comparable<Type> {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String superType;
|
private final String superType;
|
||||||
private final boolean constantPool;
|
private final boolean constantPool;
|
||||||
private final long id;
|
|
||||||
private final ArrayList<ValueDescriptor> fields = new ArrayList<>();
|
private final ArrayList<ValueDescriptor> fields = new ArrayList<>();
|
||||||
private Boolean simpleType; // calculated lazy
|
private Boolean simpleType; // calculated lazy
|
||||||
private boolean remove = true;
|
private boolean remove = true;
|
||||||
|
private long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a type
|
* Creates a type
|
||||||
*
|
*
|
||||||
|
@ -318,4 +319,8 @@ public class Type implements Comparable<Type> {
|
||||||
public boolean getRemove() {
|
public boolean getRemove() {
|
||||||
return remove;
|
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.AnnotationElement;
|
||||||
import jdk.jfr.Description;
|
import jdk.jfr.Description;
|
||||||
import jdk.jfr.Event;
|
|
||||||
import jdk.jfr.Label;
|
import jdk.jfr.Label;
|
||||||
import jdk.jfr.MetadataDefinition;
|
import jdk.jfr.MetadataDefinition;
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
|
@ -240,7 +239,7 @@ public final class TypeLibrary {
|
||||||
// STRUCT
|
// STRUCT
|
||||||
String superType = null;
|
String superType = null;
|
||||||
boolean eventType = false;
|
boolean eventType = false;
|
||||||
if (Event.class.isAssignableFrom(clazz)) {
|
if (jdk.internal.event.Event.class.isAssignableFrom(clazz)) {
|
||||||
superType = Type.SUPER_TYPE_EVENT;
|
superType = Type.SUPER_TYPE_EVENT;
|
||||||
eventType= true;
|
eventType= true;
|
||||||
}
|
}
|
||||||
|
@ -489,4 +488,8 @@ public final class TypeLibrary {
|
||||||
aQ.addAll(ae.getAnnotationElements());
|
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());
|
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);
|
Utils.ensureValidEventSubclass(eventClass);
|
||||||
try {
|
try {
|
||||||
Field f = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
|
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);
|
Utils.ensureValidEventSubclass(eventClass);
|
||||||
try {
|
try {
|
||||||
Field field = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
|
Field field = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
|
||||||
|
@ -322,7 +322,7 @@ public final class Utils {
|
||||||
static List<Field> getVisibleEventFields(Class<?> clazz) {
|
static List<Field> getVisibleEventFields(Class<?> clazz) {
|
||||||
Utils.ensureValidEventSubclass(clazz);
|
Utils.ensureValidEventSubclass(clazz);
|
||||||
List<Field> fields = new ArrayList<>();
|
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()) {
|
for (Field field : c.getDeclaredFields()) {
|
||||||
// skip private field in base classes
|
// skip private field in base classes
|
||||||
if (c == clazz || !Modifier.isPrivate(field.getModifiers())) {
|
if (c == clazz || !Modifier.isPrivate(field.getModifiers())) {
|
||||||
|
@ -334,10 +334,10 @@ public final class Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureValidEventSubclass(Class<?> eventClass) {
|
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");
|
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());
|
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);
|
SecuritySupport.ensureClassIsInitialized(eventClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,6 +499,50 @@ public final class Utils {
|
||||||
return eventName;
|
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) {
|
public static String makeFilename(Recording recording) {
|
||||||
String pid = JVM.getJVM().getPid();
|
String pid = JVM.getJVM().getPid();
|
||||||
String date = Repository.REPO_DATE_FORMAT.format(LocalDateTime.now());
|
String date = Repository.REPO_DATE_FORMAT.format(LocalDateTime.now());
|
||||||
|
|
|
@ -51,6 +51,9 @@ import jdk.jfr.internal.Utils;
|
||||||
|
|
||||||
public final class JDKEvents {
|
public final class JDKEvents {
|
||||||
|
|
||||||
|
private static final Class<?>[] mirrorEventClasses = {
|
||||||
|
};
|
||||||
|
|
||||||
private static final Class<?>[] eventClasses = {
|
private static final Class<?>[] eventClasses = {
|
||||||
FileForceEvent.class,
|
FileForceEvent.class,
|
||||||
FileReadEvent.class,
|
FileReadEvent.class,
|
||||||
|
@ -90,6 +93,9 @@ public final class JDKEvents {
|
||||||
Modules.addExports(jdkJfrModule, Utils.EVENTS_PACKAGE_NAME, javaBaseModule);
|
Modules.addExports(jdkJfrModule, Utils.EVENTS_PACKAGE_NAME, javaBaseModule);
|
||||||
Modules.addExports(jdkJfrModule, Utils.INSTRUMENT_PACKAGE_NAME, javaBaseModule);
|
Modules.addExports(jdkJfrModule, Utils.INSTRUMENT_PACKAGE_NAME, javaBaseModule);
|
||||||
Modules.addExports(jdkJfrModule, Utils.HANDLERS_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) {
|
for (Class<?> eventClass : eventClasses) {
|
||||||
SecuritySupport.registerEvent((Class<? extends Event>) eventClass);
|
SecuritySupport.registerEvent((Class<? extends Event>) eventClass);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,8 +104,9 @@ public class TestGetAllEventClasses {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
private static void assertEvents(JVM jvm, boolean inclusion, Class<? extends Event>... targetEvents) {
|
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) {
|
for (Class<? extends Event> ev : targetEvents) {
|
||||||
if (list.contains(ev)) {
|
if (list.contains(ev)) {
|
||||||
if (inclusion) {
|
if (inclusion) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue