1.1 --- a/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp Sun Jun 07 18:57:54 2020 +0100 1.2 +++ b/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp Fri Jun 12 02:59:56 2020 +0100 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -31,7 +31,9 @@ 1.11 #include "jfr/recorder/service/jfrOptionSet.hpp" 1.12 #include "jfr/support/jfrEventClass.hpp" 1.13 #include "memory/resourceArea.hpp" 1.14 +#include "prims/jvmtiEnvBase.hpp" 1.15 #include "prims/jvmtiExport.hpp" 1.16 +#include "prims/jvmtiUtil.hpp" 1.17 #include "runtime/interfaceSupport.hpp" 1.18 #include "runtime/thread.inline.hpp" 1.19 #include "utilities/exceptions.hpp" 1.20 @@ -51,19 +53,17 @@ 1.21 } 1.22 } 1.23 1.24 -static jvmtiError set_event_notification_mode(jvmtiEventMode mode, 1.25 - jvmtiEvent event, 1.26 - jthread event_thread, 1.27 - ...) { 1.28 - if (jfr_jvmti_env == NULL) { 1.29 - return JVMTI_ERROR_NONE; 1.30 - } 1.31 +static bool set_event_notification_mode(jvmtiEventMode mode, 1.32 + jvmtiEvent event, 1.33 + jthread event_thread, 1.34 + ...) { 1.35 + assert(jfr_jvmti_env != NULL, "invariant"); 1.36 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread); 1.37 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode"); 1.38 - return jvmti_ret_code; 1.39 + return jvmti_ret_code == JVMTI_ERROR_NONE; 1.40 } 1.41 1.42 -static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) { 1.43 +static bool update_class_file_load_hook_event(jvmtiEventMode mode) { 1.44 return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); 1.45 } 1.46 1.47 @@ -116,12 +116,23 @@ 1.48 return classes; 1.49 } 1.50 1.51 -static void log_and_throw(TRAPS) { 1.52 +// caller needs ResourceMark 1.53 +static void log_and_throw(jvmtiError error, TRAPS) { 1.54 if (!HAS_PENDING_EXCEPTION) { 1.55 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); 1.56 ThreadInVMfromNative tvmfn((JavaThread*)THREAD); 1.57 - if (true) tty->print_cr("JfrJvmtiAgent::retransformClasses failed"); 1.58 - JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD); 1.59 + const char base_error_msg[] = "JfrJvmtiAgent::retransformClasses failed: "; 1.60 + size_t length = sizeof base_error_msg; // includes terminating null 1.61 + const char* const jvmti_error_name = JvmtiUtil::error_name(error); 1.62 + assert(jvmti_error_name != NULL, "invariant"); 1.63 + length += strlen(jvmti_error_name); 1.64 + char* error_msg = NEW_RESOURCE_ARRAY(char, length); 1.65 + jio_snprintf(error_msg, length, "%s%s", base_error_msg, jvmti_error_name); 1.66 + if (JVMTI_ERROR_INVALID_CLASS_FORMAT == error) { 1.67 + JfrJavaSupport::throw_class_format_error(error_msg, THREAD); 1.68 + } else { 1.69 + JfrJavaSupport::throw_runtime_exception(error_msg, THREAD); 1.70 + } 1.71 } 1.72 } 1.73 1.74 @@ -136,12 +147,15 @@ 1.75 } 1.76 } 1.77 1.78 +static bool is_valid_jvmti_phase() { 1.79 + return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE; 1.80 +} 1.81 + 1.82 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { 1.83 assert(env != NULL, "invariant"); 1.84 + assert(classes_array != NULL, "invariant"); 1.85 + assert(is_valid_jvmti_phase(), "invariant"); 1.86 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); 1.87 - if (classes_array == NULL) { 1.88 - return; 1.89 - } 1.90 const jint classes_count = env->GetArrayLength(classes_array); 1.91 if (classes_count <= 0) { 1.92 return; 1.93 @@ -152,27 +166,27 @@ 1.94 for (jint i = 0; i < classes_count; i++) { 1.95 jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); 1.96 check_exception_and_log(env, THREAD); 1.97 - 1.98 + classes[i] = clz; 1.99 + } 1.100 + { 1.101 // inspecting the oop/klass requires a thread transition 1.102 - { 1.103 - ThreadInVMfromNative transition((JavaThread*)THREAD); 1.104 - if (JdkJfrEvent::is_a(clz)) { 1.105 - // should have been tagged already 1.106 - assert(JdkJfrEvent::is_subklass(clz), "invariant"); 1.107 - } else { 1.108 + ThreadInVMfromNative transition((JavaThread*)THREAD); 1.109 + for (jint i = 0; i < classes_count; ++i) { 1.110 + jclass clz = classes[i]; 1.111 + if (!JdkJfrEvent::is_a(clz)) { 1.112 // outside the event hierarchy 1.113 JdkJfrEvent::tag_as_host(clz); 1.114 } 1.115 } 1.116 - 1.117 - classes[i] = clz; 1.118 } 1.119 - if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) { 1.120 - log_and_throw(THREAD); 1.121 + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); 1.122 + const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes); 1.123 + if (result != JVMTI_ERROR_NONE) { 1.124 + log_and_throw(result, THREAD); 1.125 } 1.126 } 1.127 1.128 -static jvmtiError register_callbacks(JavaThread* jt) { 1.129 +static bool register_callbacks(JavaThread* jt) { 1.130 assert(jfr_jvmti_env != NULL, "invariant"); 1.131 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); 1.132 jvmtiEventCallbacks callbacks; 1.133 @@ -181,10 +195,10 @@ 1.134 callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; 1.135 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 1.136 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); 1.137 - return jvmti_ret_code; 1.138 + return jvmti_ret_code == JVMTI_ERROR_NONE; 1.139 } 1.140 1.141 -static jvmtiError register_capabilities(JavaThread* jt) { 1.142 +static bool register_capabilities(JavaThread* jt) { 1.143 assert(jfr_jvmti_env != NULL, "invariant"); 1.144 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); 1.145 jvmtiCapabilities capabilities; 1.146 @@ -194,7 +208,7 @@ 1.147 capabilities.can_retransform_any_class = 1; 1.148 const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); 1.149 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); 1.150 - return jvmti_ret_code; 1.151 + return jvmti_ret_code == JVMTI_ERROR_NONE; 1.152 } 1.153 1.154 static jint create_jvmti_env(JavaThread* jt) { 1.155 @@ -205,16 +219,14 @@ 1.156 return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); 1.157 } 1.158 1.159 -static jvmtiError unregister_callbacks(JavaThread* jt) { 1.160 - if (jfr_jvmti_env == NULL) { 1.161 - return JVMTI_ERROR_NONE; 1.162 - } 1.163 +static bool unregister_callbacks(JavaThread* jt) { 1.164 + assert(jfr_jvmti_env != NULL, "invariant"); 1.165 jvmtiEventCallbacks callbacks; 1.166 /* Set empty callbacks */ 1.167 memset(&callbacks, 0, sizeof(callbacks)); 1.168 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 1.169 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); 1.170 - return jvmti_ret_code; 1.171 + return jvmti_ret_code == JVMTI_ERROR_NONE; 1.172 } 1.173 1.174 JfrJvmtiAgent::JfrJvmtiAgent() {} 1.175 @@ -222,20 +234,17 @@ 1.176 JfrJvmtiAgent::~JfrJvmtiAgent() { 1.177 JavaThread* jt = current_java_thread(); 1.178 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); 1.179 - ThreadToNativeFromVM transition(jt); 1.180 - update_class_file_load_hook_event(JVMTI_DISABLE); 1.181 - unregister_callbacks(jt); 1.182 if (jfr_jvmti_env != NULL) { 1.183 + ThreadToNativeFromVM transition(jt); 1.184 + update_class_file_load_hook_event(JVMTI_DISABLE); 1.185 + unregister_callbacks(jt); 1.186 jfr_jvmti_env->DisposeEnvironment(); 1.187 jfr_jvmti_env = NULL; 1.188 } 1.189 - agent = NULL; 1.190 } 1.191 1.192 -static bool initialize() { 1.193 - JavaThread* const jt = current_java_thread(); 1.194 +static bool initialize(JavaThread* jt) { 1.195 assert(jt != NULL, "invariant"); 1.196 - assert(jt->thread_state() == _thread_in_vm, "invariant"); 1.197 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); 1.198 ThreadToNativeFromVM transition(jt); 1.199 if (create_jvmti_env(jt) != JNI_OK) { 1.200 @@ -243,25 +252,38 @@ 1.201 return false; 1.202 } 1.203 assert(jfr_jvmti_env != NULL, "invariant"); 1.204 - if (register_capabilities(jt) != JVMTI_ERROR_NONE) { 1.205 + if (!register_capabilities(jt)) { 1.206 return false; 1.207 } 1.208 - if (register_callbacks(jt) != JVMTI_ERROR_NONE) { 1.209 + if (!register_callbacks(jt)) { 1.210 return false; 1.211 } 1.212 - if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) { 1.213 - return false; 1.214 + return update_class_file_load_hook_event(JVMTI_ENABLE); 1.215 +} 1.216 + 1.217 +static void log_and_throw_illegal_state_exception(TRAPS) { 1.218 + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); 1.219 + const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence."; 1.220 + if (true) { 1.221 + tty->print_cr("%s\n", illegal_state_msg); 1.222 + tty->print_cr("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE.\n"); 1.223 + tty->print_cr("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START.\n"); 1.224 } 1.225 - return true; 1.226 + JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD); 1.227 } 1.228 1.229 bool JfrJvmtiAgent::create() { 1.230 - assert(jfr_jvmti_env == NULL, "invariant"); 1.231 + assert(agent == NULL, "invariant"); 1.232 + JavaThread* const jt = current_java_thread(); 1.233 + if (!is_valid_jvmti_phase()) { 1.234 + log_and_throw_illegal_state_exception(jt); 1.235 + return false; 1.236 + } 1.237 agent = new JfrJvmtiAgent(); 1.238 if (agent == NULL) { 1.239 return false; 1.240 } 1.241 - if (!initialize()) { 1.242 + if (!initialize(jt)) { 1.243 delete agent; 1.244 agent = NULL; 1.245 return false; 1.246 @@ -275,4 +297,3 @@ 1.247 agent = NULL; 1.248 } 1.249 } 1.250 -