src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
changeset 52334 a181612f0715
parent 51334 cc2c79d22508
child 52671 600fca45232b
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Tue Oct 30 15:17:58 2018 -0700
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Wed Oct 31 02:10:21 2018 +0100
@@ -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 @@
   "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 @@
   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 @@
   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 @@
 
 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 @@
   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* 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;
   }
-  InstanceKlass* super = InstanceKlass::cast(ik->super());
-  return registered_annotation_value(super, registered_symbol);
+  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 @@
 // 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 @@
                               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 @@
                                             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 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 @@
   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 @@
   // 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 @@
                                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 @@
   // 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 @@
   // 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 @@
   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