changeset 57840:4b2d33292638

8227610: Remove allocation when getting EventHandle Reviewed-by: mgronlun
author egahlin
date Mon, 27 Jan 2020 14:30:57 +0100
parents 62d7f4566b6d
children 5d49b846aef7
files src/hotspot/share/jfr/jni/jfrJavaSupport.cpp src/hotspot/share/jfr/jni/jfrJavaSupport.hpp src/hotspot/share/jfr/jni/jfrJniMethod.cpp src/hotspot/share/jfr/jni/jfrJniMethod.hpp src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp src/hotspot/share/jfr/support/jfrIntrinsics.hpp src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java test/jdk/jdk/jfr/event/security/TestSecurityPropertyModificationEvent.java
diffstat 9 files changed, 134 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp	Mon Jan 27 14:30:57 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,7 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/threadSMR.hpp"
 #include "utilities/growableArray.hpp"
+#include "classfile/vmSymbols.hpp"
 
 #ifdef ASSERT
 void JfrJavaSupport::check_java_thread_in_vm(Thread* t) {
@@ -763,6 +764,74 @@
   return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);
 }
 
+jobject JfrJavaSupport::get_handler(jobject clazz, Thread* thread) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+  const oop klass_oop = JNIHandles::resolve(clazz);
+  assert(klass_oop != NULL, "invariant");
+  Klass* klass = java_lang_Class::as_Klass(klass_oop);
+  HandleMark hm(thread);
+  Handle h_klass_oop(Handle(thread, klass->java_mirror()));
+  InstanceKlass* const instance_klass = static_cast<InstanceKlass*>(klass);
+  assert(instance_klass->is_initialized(), "inavarient");
+
+  fieldDescriptor event_handler_field;
+  Klass* f = instance_klass->find_field(
+    vmSymbols::eventHandler_name(),
+    vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(),
+    true, &event_handler_field);
+  if (f != NULL) {
+    oop ret = h_klass_oop->obj_field(event_handler_field.offset());
+    return ret != NULL ? JfrJavaSupport::local_jni_handle(ret, thread) : NULL;
+  }
+
+  fieldDescriptor object_field;
+  Klass* g = instance_klass->find_field(
+    vmSymbols::eventHandler_name(),
+    vmSymbols::object_signature(),
+    true, &object_field);
+  if (g != NULL) {
+    oop ret = h_klass_oop->obj_field(object_field.offset());
+    return ret != NULL ? JfrJavaSupport::local_jni_handle(ret, thread) : NULL;
+  }
+  assert(f == NULL && g == NULL, "no handler field for class");
+  return NULL;
+}
+
+bool JfrJavaSupport::set_handler(jobject clazz, jobject handler, Thread* thread) {
+  DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
+  const oop klass_oop = JNIHandles::resolve(clazz);
+  assert(klass_oop != NULL, "invariant");
+  const oop handler_oop = JNIHandles::resolve(handler);
+  assert(handler_oop != NULL, "invariant");
+  Klass* klass = java_lang_Class::as_Klass(klass_oop);
+  HandleMark hm(thread);
+  Handle h_klass_oop(Handle(thread, klass->java_mirror()));
+  InstanceKlass* const instance_klass = static_cast<InstanceKlass*>(klass);
+  assert(instance_klass->is_initialized(), "inavarient");
+
+  fieldDescriptor event_handler_field;
+  Klass* f = instance_klass->find_field(
+    vmSymbols::eventHandler_name(),
+    vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(),
+    true, &event_handler_field);
+  if (f != NULL) {
+    h_klass_oop->obj_field_put(event_handler_field.offset(), handler_oop);
+    return true;
+  }
+
+  fieldDescriptor object_handler_field;
+  Klass* g = instance_klass->find_field(
+    vmSymbols::eventHandler_name(),
+    vmSymbols::object_signature(),
+    true, &object_handler_field);
+  if (g != NULL) {
+    h_klass_oop->obj_field_put(object_handler_field.offset(), handler_oop);
+    return true;
+  }
+  assert(f == NULL && g == NULL, "no handler field for class");
+  return false;
+}
+
 void JfrJavaSupport::on_thread_start(Thread* t) {
   assert(t != NULL, "invariant");
   assert(Thread::current() == t, "invariant");
--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp	Mon Jan 27 14:30:57 2020 +0100
@@ -95,6 +95,9 @@
   static bool is_excluded(jobject thread);
   static void on_thread_start(Thread* t);
 
+  static jobject get_handler(jobject clazz, Thread* thread);
+  static bool set_handler(jobject clazz, jobject handler, Thread* thread);
+
   // critical
   static void abort(jstring errorMsg, TRAPS);
   static void uncaught_exception(jthrowable throwable, Thread* t);
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp	Mon Jan 27 14:30:57 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -341,3 +341,12 @@
   return JfrRepository::current_chunk_start_nanos();
 JVM_END
 
+JVM_ENTRY_NO_ENV(jobject, jfr_get_handler(JNIEnv * env, jobject jvm, jobject clazz))
+  return JfrJavaSupport::get_handler(clazz, thread);
+JVM_END
+
+JVM_ENTRY_NO_ENV(jboolean, jfr_set_handler(JNIEnv * env, jobject jvm, jobject clazz, jobject handler))
+  return JfrJavaSupport::set_handler(clazz, handler, thread);
+JVM_END
+
+
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp	Mon Jan 27 14:30:57 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -144,6 +144,11 @@
 
 jlong JNICALL jfr_chunk_start_nanos(JNIEnv* env, jobject jvm);
 
+jobject JNICALL jfr_get_handler(JNIEnv* env, jobject jvm, jobject clazz);
+
+jboolean JNICALL jfr_set_handler(JNIEnv* env, jobject jvm, jobject clazz, jobject handler);
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp	Mon Jan 27 14:30:57 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -86,7 +86,9 @@
       (char*)"exclude", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_exclude_thread,
       (char*)"include", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_include_thread,
       (char*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded,
-      (char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos
+      (char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos,
+      (char*)"getHandler", (char*)"(Ljava/lang/Class;)Ljava/lang/Object;", (void*)jfr_get_handler,
+      (char*)"setHandler", (char*)"(Ljava/lang/Class;Ljdk/jfr/internal/handlers/EventHandler;)Z", (void*)jfr_set_handler
     };
 
     const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);
--- a/src/hotspot/share/jfr/support/jfrIntrinsics.hpp	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/hotspot/share/jfr/support/jfrIntrinsics.hpp	Mon Jan 27 14:30:57 2020 +0100
@@ -34,7 +34,9 @@
 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
 
 #define JFR_TEMPLATES(template) \
-  template(jdk_jfr_internal_JVM,          "jdk/jfr/internal/JVM")
+  template(jdk_jfr_internal_JVM,                                      "jdk/jfr/internal/JVM")                     \
+  template(jdk_jfr_internal_handlers_EventHandler_signature,          "Ljdk/jfr/internal/handlers/EventHandler;") \
+  template(eventHandler_name,                                         "eventHandler")                             \
 
 #define JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)                              \
   do_intrinsic(_counterTime,        jdk_jfr_internal_JVM, counterTime_name, void_long_signature, F_SN)       \
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java	Mon Jan 27 14:30:57 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
 
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.jfr.Event;
+import jdk.jfr.internal.handlers.EventHandler;
 
 /**
  * Interface against the JVM.
@@ -562,4 +563,24 @@
      */
     public native long getChunkStartNanos();
 
+    /**
+     * Stores an EventHandler to the eventHandler field of an event class.
+     *
+     * @param eventClass the class, not {@code null}
+     *
+     * @param handler the handler, may be {@code null}
+     *
+     * @return if the field could be set
+     */
+    public native boolean setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler);
+
+    /**
+     * Retrieves the EventHandler for an event class.
+     *
+     * @param eventClass the class, not {@code null}
+     *
+     * @return the handler, may be {@code null}
+     */
+    public native Object getHandler(Class<? extends jdk.internal.event.Event> eventClass);
+
 }
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Fri Jan 24 10:16:35 2020 +0100
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Utils.java	Mon Jan 27 14:30:57 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -328,23 +328,17 @@
 
     static synchronized EventHandler getHandler(Class<? extends jdk.internal.event.Event> eventClass) {
         Utils.ensureValidEventSubclass(eventClass);
-        try {
-            Field f = eventClass.getDeclaredField(EventInstrumentation.FIELD_EVENT_HANDLER);
-            SecuritySupport.setAccessible(f);
-            return (EventHandler) f.get(null);
-        } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
-            throw new InternalError("Could not access event handler");
+        Object handler = JVM.getJVM().getHandler(eventClass);
+        if (handler == null || handler instanceof EventHandler) {
+            return (EventHandler) handler;
         }
+        throw new InternalError("Could not access event 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);
-            SecuritySupport.setAccessible(field);
-            field.set(null, handler);
-        } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
-            throw new InternalError("Could not access event handler");
+        if (!JVM.getJVM().setHandler(eventClass, handler)) {
+            throw new InternalError("Could not set event handler");
         }
     }
 
--- a/test/jdk/jdk/jfr/event/security/TestSecurityPropertyModificationEvent.java	Fri Jan 24 10:16:35 2020 +0100
+++ b/test/jdk/jdk/jfr/event/security/TestSecurityPropertyModificationEvent.java	Mon Jan 27 14:30:57 2020 +0100
@@ -48,6 +48,15 @@
     static String keyValue = "shouldBecomeAnEvent";
 
     public static void main(String[] args) throws Exception {
+
+        // If events in java.base are used before JFR is initialized
+        // the event handler field will be of type java.lang.Object.
+        // Adding this for one of the security events makes sure
+        // we have test coverage of this mode as well.
+        for (String key : keys) {
+            Security.setProperty(key, keyValue);
+        }
+
         try (Recording recording = new Recording()) {
             recording.enable(EventNames.SecurityProperty);
             recording.start();