src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp
changeset 59259 127ca611f19b
parent 50113 caf115bb98ad
equal deleted inserted replaced
59258:4c2557ab304e 59259:127ca611f19b
     1 /*
     1 /*
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    30 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
    30 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
    31 #include "jfr/recorder/service/jfrOptionSet.hpp"
    31 #include "jfr/recorder/service/jfrOptionSet.hpp"
    32 #include "jfr/support/jfrEventClass.hpp"
    32 #include "jfr/support/jfrEventClass.hpp"
    33 #include "logging/log.hpp"
    33 #include "logging/log.hpp"
    34 #include "memory/resourceArea.hpp"
    34 #include "memory/resourceArea.hpp"
       
    35 #include "prims/jvmtiEnvBase.hpp"
    35 #include "prims/jvmtiExport.hpp"
    36 #include "prims/jvmtiExport.hpp"
       
    37 #include "prims/jvmtiUtil.hpp"
    36 #include "runtime/interfaceSupport.inline.hpp"
    38 #include "runtime/interfaceSupport.inline.hpp"
    37 #include "runtime/thread.inline.hpp"
    39 #include "runtime/thread.inline.hpp"
    38 #include "utilities/exceptions.hpp"
    40 #include "utilities/exceptions.hpp"
    39 
    41 
    40 static const size_t ERROR_MSG_BUFFER_SIZE = 256;
    42 static const size_t ERROR_MSG_BUFFER_SIZE = 256;
    50                            NULL == errnum_str ? "Unknown" : errnum_str,
    52                            NULL == errnum_str ? "Unknown" : errnum_str,
    51                            NULL == str ? "" : str);
    53                            NULL == str ? "" : str);
    52   }
    54   }
    53 }
    55 }
    54 
    56 
    55 static jvmtiError set_event_notification_mode(jvmtiEventMode mode,
    57 static bool set_event_notification_mode(jvmtiEventMode mode,
    56                                               jvmtiEvent event,
    58                                         jvmtiEvent event,
    57                                               jthread event_thread,
    59                                         jthread event_thread,
    58                                               ...) {
    60                                         ...) {
    59   if (jfr_jvmti_env == NULL) {
    61   assert(jfr_jvmti_env != NULL, "invariant");
    60     return JVMTI_ERROR_NONE;
       
    61   }
       
    62   const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread);
    62   const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread);
    63   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode");
    63   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode");
    64   return jvmti_ret_code;
    64   return jvmti_ret_code == JVMTI_ERROR_NONE;
    65 }
    65 }
    66 
    66 
    67 static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) {
    67 static bool update_class_file_load_hook_event(jvmtiEventMode mode) {
    68   return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
    68   return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
    69 }
    69 }
    70 
    70 
    71 static JavaThread* current_java_thread() {
    71 static JavaThread* current_java_thread() {
    72   Thread* this_thread = Thread::current();
    72   Thread* this_thread = Thread::current();
   115     JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL);
   115     JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL);
   116   }
   116   }
   117   return classes;
   117   return classes;
   118 }
   118 }
   119 
   119 
   120 static void log_and_throw(TRAPS) {
   120 // caller needs ResourceMark
       
   121 static void log_and_throw(jvmtiError error, TRAPS) {
   121   if (!HAS_PENDING_EXCEPTION) {
   122   if (!HAS_PENDING_EXCEPTION) {
   122     DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
   123     DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
   123     ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
   124     ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
   124     log_error(jfr, system)("JfrJvmtiAgent::retransformClasses failed");
   125     const char base_error_msg[] = "JfrJvmtiAgent::retransformClasses failed: ";
   125     JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD);
   126     size_t length = sizeof base_error_msg; // includes terminating null
       
   127     const char* const jvmti_error_name = JvmtiUtil::error_name(error);
       
   128     assert(jvmti_error_name != NULL, "invariant");
       
   129     length += strlen(jvmti_error_name);
       
   130     char* error_msg = NEW_RESOURCE_ARRAY(char, length);
       
   131     jio_snprintf(error_msg, length, "%s%s", base_error_msg, jvmti_error_name);
       
   132     if (JVMTI_ERROR_INVALID_CLASS_FORMAT == error) {
       
   133       JfrJavaSupport::throw_class_format_error(error_msg, THREAD);
       
   134     } else {
       
   135       JfrJavaSupport::throw_runtime_exception(error_msg, THREAD);
       
   136     }
   126   }
   137   }
   127 }
   138 }
   128 
   139 
   129 static void check_exception_and_log(JNIEnv* env, TRAPS) {
   140 static void check_exception_and_log(JNIEnv* env, TRAPS) {
   130   assert(env != NULL, "invariant");
   141   assert(env != NULL, "invariant");
   135     log_error(jfr, system)("GetObjectArrayElement threw an exception");
   146     log_error(jfr, system)("GetObjectArrayElement threw an exception");
   136     return;
   147     return;
   137   }
   148   }
   138 }
   149 }
   139 
   150 
       
   151 static bool is_valid_jvmti_phase() {
       
   152   return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE;
       
   153 }
       
   154 
   140 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) {
   155 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) {
   141   assert(env != NULL, "invariant");
   156   assert(env != NULL, "invariant");
       
   157   assert(classes_array != NULL, "invariant");
       
   158   assert(is_valid_jvmti_phase(), "invariant");
   142   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
   159   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
   143   if (classes_array == NULL) {
       
   144     return;
       
   145   }
       
   146   const jint classes_count = env->GetArrayLength(classes_array);
   160   const jint classes_count = env->GetArrayLength(classes_array);
   147   if (classes_count <= 0) {
   161   if (classes_count <= 0) {
   148     return;
   162     return;
   149   }
   163   }
   150   ResourceMark rm(THREAD);
   164   ResourceMark rm(THREAD);
   151   jclass* const classes = create_classes_array(classes_count, CHECK);
   165   jclass* const classes = create_classes_array(classes_count, CHECK);
   152   assert(classes != NULL, "invariant");
   166   assert(classes != NULL, "invariant");
   153   for (jint i = 0; i < classes_count; i++) {
   167   for (jint i = 0; i < classes_count; i++) {
   154     jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i);
   168     jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i);
   155     check_exception_and_log(env, THREAD);
   169     check_exception_and_log(env, THREAD);
   156 
   170     classes[i] = clz;
       
   171   }
       
   172   {
   157     // inspecting the oop/klass requires a thread transition
   173     // inspecting the oop/klass requires a thread transition
   158     {
   174     ThreadInVMfromNative transition((JavaThread*)THREAD);
   159       ThreadInVMfromNative transition((JavaThread*)THREAD);
   175     for (jint i = 0; i < classes_count; ++i) {
   160       if (JdkJfrEvent::is_a(clz)) {
   176       jclass clz = classes[i];
   161         // should have been tagged already
   177       if (!JdkJfrEvent::is_a(clz)) {
   162         assert(JdkJfrEvent::is_subklass(clz), "invariant");
       
   163       } else {
       
   164         // outside the event hierarchy
   178         // outside the event hierarchy
   165         JdkJfrEvent::tag_as_host(clz);
   179         JdkJfrEvent::tag_as_host(clz);
   166       }
   180       }
   167     }
   181     }
   168 
   182   }
   169     classes[i] = clz;
   183   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
   170   }
   184   const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes);
   171   if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) {
   185   if (result != JVMTI_ERROR_NONE) {
   172     log_and_throw(THREAD);
   186     log_and_throw(result, THREAD);
   173   }
   187   }
   174 }
   188 }
   175 
   189 
   176 static jvmtiError register_callbacks(JavaThread* jt) {
   190 static bool register_callbacks(JavaThread* jt) {
   177   assert(jfr_jvmti_env != NULL, "invariant");
   191   assert(jfr_jvmti_env != NULL, "invariant");
   178   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
   192   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
   179   jvmtiEventCallbacks callbacks;
   193   jvmtiEventCallbacks callbacks;
   180   /* Set callbacks */
   194   /* Set callbacks */
   181   memset(&callbacks, 0, sizeof(callbacks));
   195   memset(&callbacks, 0, sizeof(callbacks));
   182   callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;
   196   callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;
   183   const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
   197   const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
   184   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
   198   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
   185   return jvmti_ret_code;
   199   return jvmti_ret_code == JVMTI_ERROR_NONE;
   186 }
   200 }
   187 
   201 
   188 static jvmtiError register_capabilities(JavaThread* jt) {
   202 static bool register_capabilities(JavaThread* jt) {
   189   assert(jfr_jvmti_env != NULL, "invariant");
   203   assert(jfr_jvmti_env != NULL, "invariant");
   190   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
   204   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
   191   jvmtiCapabilities capabilities;
   205   jvmtiCapabilities capabilities;
   192   /* Add JVMTI capabilities */
   206   /* Add JVMTI capabilities */
   193   (void)memset(&capabilities, 0, sizeof(capabilities));
   207   (void)memset(&capabilities, 0, sizeof(capabilities));
   194   capabilities.can_retransform_classes = 1;
   208   capabilities.can_retransform_classes = 1;
   195   capabilities.can_retransform_any_class = 1;
   209   capabilities.can_retransform_any_class = 1;
   196   const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities);
   210   const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities);
   197   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities");
   211   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities");
   198   return jvmti_ret_code;
   212   return jvmti_ret_code == JVMTI_ERROR_NONE;
   199 }
   213 }
   200 
   214 
   201 static jint create_jvmti_env(JavaThread* jt) {
   215 static jint create_jvmti_env(JavaThread* jt) {
   202   assert(jfr_jvmti_env == NULL, "invariant");
   216   assert(jfr_jvmti_env == NULL, "invariant");
   203   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
   217   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
   204   extern struct JavaVM_ main_vm;
   218   extern struct JavaVM_ main_vm;
   205   JavaVM* vm = &main_vm;
   219   JavaVM* vm = &main_vm;
   206   return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION);
   220   return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION);
   207 }
   221 }
   208 
   222 
   209 static jvmtiError unregister_callbacks(JavaThread* jt) {
   223 static bool unregister_callbacks(JavaThread* jt) {
   210   if (jfr_jvmti_env == NULL) {
   224   assert(jfr_jvmti_env != NULL, "invariant");
   211     return JVMTI_ERROR_NONE;
       
   212   }
       
   213   jvmtiEventCallbacks callbacks;
   225   jvmtiEventCallbacks callbacks;
   214   /* Set empty callbacks */
   226   /* Set empty callbacks */
   215   memset(&callbacks, 0, sizeof(callbacks));
   227   memset(&callbacks, 0, sizeof(callbacks));
   216   const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
   228   const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
   217   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
   229   check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
   218   return jvmti_ret_code;
   230   return jvmti_ret_code == JVMTI_ERROR_NONE;
   219 }
   231 }
   220 
   232 
   221 JfrJvmtiAgent::JfrJvmtiAgent() {}
   233 JfrJvmtiAgent::JfrJvmtiAgent() {}
   222 
   234 
   223 JfrJvmtiAgent::~JfrJvmtiAgent() {
   235 JfrJvmtiAgent::~JfrJvmtiAgent() {
   224   JavaThread* jt = current_java_thread();
   236   JavaThread* jt = current_java_thread();
   225   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
   237   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
   226   ThreadToNativeFromVM transition(jt);
       
   227   update_class_file_load_hook_event(JVMTI_DISABLE);
       
   228   unregister_callbacks(jt);
       
   229   if (jfr_jvmti_env != NULL) {
   238   if (jfr_jvmti_env != NULL) {
       
   239     ThreadToNativeFromVM transition(jt);
       
   240     update_class_file_load_hook_event(JVMTI_DISABLE);
       
   241     unregister_callbacks(jt);
   230     jfr_jvmti_env->DisposeEnvironment();
   242     jfr_jvmti_env->DisposeEnvironment();
   231     jfr_jvmti_env = NULL;
   243     jfr_jvmti_env = NULL;
   232   }
   244   }
   233   agent = NULL;
   245 }
   234 }
   246 
   235 
   247 static bool initialize(JavaThread* jt) {
   236 static bool initialize() {
       
   237   JavaThread* const jt = current_java_thread();
       
   238   assert(jt != NULL, "invariant");
   248   assert(jt != NULL, "invariant");
   239   assert(jt->thread_state() == _thread_in_vm, "invariant");
       
   240   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
   249   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
   241   ThreadToNativeFromVM transition(jt);
   250   ThreadToNativeFromVM transition(jt);
   242   if (create_jvmti_env(jt) != JNI_OK) {
   251   if (create_jvmti_env(jt) != JNI_OK) {
   243     assert(jfr_jvmti_env == NULL, "invariant");
   252     assert(jfr_jvmti_env == NULL, "invariant");
   244     return false;
   253     return false;
   245   }
   254   }
   246   assert(jfr_jvmti_env != NULL, "invariant");
   255   assert(jfr_jvmti_env != NULL, "invariant");
   247   if (register_capabilities(jt) != JVMTI_ERROR_NONE) {
   256   if (!register_capabilities(jt)) {
   248     return false;
   257     return false;
   249   }
   258   }
   250   if (register_callbacks(jt) != JVMTI_ERROR_NONE) {
   259   if (!register_callbacks(jt)) {
   251     return false;
   260     return false;
   252   }
   261   }
   253   if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) {
   262   return update_class_file_load_hook_event(JVMTI_ENABLE);
   254     return false;
   263 }
   255   }
   264 
   256   return true;
   265 static void log_and_throw_illegal_state_exception(TRAPS) {
       
   266   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
       
   267   const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence.";
       
   268   log_error(jfr, system)(illegal_state_msg);
       
   269   log_error(jfr, system)("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE.");
       
   270   log_error(jfr, system)("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START.");
       
   271   JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD);
   257 }
   272 }
   258 
   273 
   259 bool JfrJvmtiAgent::create() {
   274 bool JfrJvmtiAgent::create() {
   260   assert(jfr_jvmti_env == NULL, "invariant");
   275   assert(agent == NULL, "invariant");
       
   276   JavaThread* const jt = current_java_thread();
       
   277   if (!is_valid_jvmti_phase()) {
       
   278     log_and_throw_illegal_state_exception(jt);
       
   279     return false;
       
   280   }
   261   agent = new JfrJvmtiAgent();
   281   agent = new JfrJvmtiAgent();
   262   if (agent == NULL) {
   282   if (agent == NULL) {
   263     return false;
   283     return false;
   264   }
   284   }
   265   if (!initialize()) {
   285   if (!initialize(jt)) {
   266     delete agent;
   286     delete agent;
   267     agent = NULL;
   287     agent = NULL;
   268     return false;
   288     return false;
   269   }
   289   }
   270   return true;
   290   return true;
   274   if (agent != NULL) {
   294   if (agent != NULL) {
   275     delete agent;
   295     delete agent;
   276     agent = NULL;
   296     agent = NULL;
   277   }
   297   }
   278 }
   298 }
   279