Fri, 12 Jun 2020 02:59:56 +0100
8233197: Invert JvmtiExport::post_vm_initialized() and Jfr:on_vm_start() start-up order for correct option parsing
8246703: [TESTBUG] Add test for JDK-8233197
Reviewed-by: aph, adinn, neugens
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 -
2.1 --- a/src/share/vm/jfr/jfr.cpp Sun Jun 07 18:57:54 2020 +0100 2.2 +++ b/src/share/vm/jfr/jfr.cpp Fri Jun 12 02:59:56 2020 +0100 2.3 @@ -32,6 +32,7 @@ 2.4 #include "jfr/recorder/service/jfrOptionSet.hpp" 2.5 #include "jfr/support/jfrThreadLocal.hpp" 2.6 #include "runtime/java.hpp" 2.7 +#include "utilities/defaultStream.hpp" 2.8 2.9 bool Jfr::is_enabled() { 2.10 return JfrRecorder::is_enabled(); 2.11 @@ -45,15 +46,21 @@ 2.12 return JfrRecorder::is_recording(); 2.13 } 2.14 2.15 -void Jfr::on_vm_init() { 2.16 - if (!JfrRecorder::on_vm_init()) { 2.17 - vm_exit_during_initialization("Failure when starting JFR on_vm_init"); 2.18 +void Jfr::on_create_vm_1() { 2.19 + if (!JfrRecorder::on_create_vm_1()) { 2.20 + vm_exit_during_initialization("Failure when starting JFR on_create_vm_1"); 2.21 } 2.22 } 2.23 2.24 -void Jfr::on_vm_start() { 2.25 - if (!JfrRecorder::on_vm_start()) { 2.26 - vm_exit_during_initialization("Failure when starting JFR on_vm_start"); 2.27 +void Jfr::on_create_vm_2() { 2.28 + if (!JfrRecorder::on_create_vm_2()) { 2.29 + vm_exit_during_initialization("Failure when starting JFR on_create_vm_2"); 2.30 + } 2.31 +} 2.32 + 2.33 +void Jfr::on_create_vm_3() { 2.34 + if (!JfrRecorder::on_create_vm_3()) { 2.35 + vm_exit_during_initialization("Failure when starting JFR on_create_vm_3"); 2.36 } 2.37 } 2.38
3.1 --- a/src/share/vm/jfr/jfr.hpp Sun Jun 07 18:57:54 2020 +0100 3.2 +++ b/src/share/vm/jfr/jfr.hpp Fri Jun 12 02:59:56 2020 +0100 3.3 @@ -43,8 +43,9 @@ 3.4 static bool is_enabled(); 3.5 static bool is_disabled(); 3.6 static bool is_recording(); 3.7 - static void on_vm_init(); 3.8 - static void on_vm_start(); 3.9 + static void on_create_vm_1(); 3.10 + static void on_create_vm_2(); 3.11 + static void on_create_vm_3(); 3.12 static void on_unloading_classes(); 3.13 static void on_thread_start(Thread* thread); 3.14 static void on_thread_exit(Thread* thread);
4.1 --- a/src/share/vm/jfr/jni/jfrJavaSupport.cpp Sun Jun 07 18:57:54 2020 +0100 4.2 +++ b/src/share/vm/jfr/jni/jfrJavaSupport.cpp Fri Jun 12 02:59:56 2020 +0100 4.3 @@ -515,6 +515,10 @@ 4.4 create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD); 4.5 } 4.6 4.7 +void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) { 4.8 + create_and_throw(vmSymbols::java_lang_RuntimeException(), message, THREAD); 4.9 +} 4.10 + 4.11 void JfrJavaSupport::abort(jstring errorMsg, Thread* t) { 4.12 DEBUG_ONLY(check_java_thread_in_vm(t)); 4.13
5.1 --- a/src/share/vm/jfr/jni/jfrJavaSupport.hpp Sun Jun 07 18:57:54 2020 +0100 5.2 +++ b/src/share/vm/jfr/jni/jfrJavaSupport.hpp Fri Jun 12 02:59:56 2020 +0100 5.3 @@ -81,6 +81,7 @@ 5.4 static void throw_internal_error(const char* message, TRAPS); 5.5 static void throw_out_of_memory_error(const char* message, TRAPS); 5.6 static void throw_class_format_error(const char* message, TRAPS); 5.7 + static void throw_runtime_exception(const char* message, TRAPS); 5.8 5.9 static jlong jfr_thread_id(jobject target_thread); 5.10
6.1 --- a/src/share/vm/jfr/jni/jfrJniMethod.cpp Sun Jun 07 18:57:54 2020 +0100 6.2 +++ b/src/share/vm/jfr/jni/jfrJniMethod.cpp Fri Jun 12 02:59:56 2020 +0100 6.3 @@ -191,7 +191,9 @@ 6.4 return JNI_TRUE; 6.5 } 6.6 if (!JfrRecorder::create(simulate_failure == JNI_TRUE)) { 6.7 - JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); 6.8 + if (!thread->has_pending_exception()) { 6.9 + JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); 6.10 + } 6.11 return JNI_FALSE; 6.12 } 6.13 return JNI_TRUE;
7.1 --- a/src/share/vm/jfr/recorder/jfrRecorder.cpp Sun Jun 07 18:57:54 2020 +0100 7.2 +++ b/src/share/vm/jfr/recorder/jfrRecorder.cpp Fri Jun 12 02:59:56 2020 +0100 7.3 @@ -44,6 +44,9 @@ 7.4 #include "runtime/handles.inline.hpp" 7.5 #include "runtime/globals_extension.hpp" 7.6 #include "utilities/growableArray.hpp" 7.7 +#ifdef ASSERT 7.8 +#include "prims/jvmtiEnvBase.hpp" 7.9 +#endif 7.10 7.11 bool JfrRecorder::_shutting_down = false; 7.12 7.13 @@ -57,7 +60,9 @@ 7.14 7.15 static bool enable() { 7.16 assert(!_enabled, "invariant"); 7.17 - FLAG_SET_MGMT(bool, FlightRecorder, true); 7.18 + if (!FlightRecorder) { 7.19 + FLAG_SET_MGMT(bool, FlightRecorder, true); 7.20 + } 7.21 _enabled = FlightRecorder; 7.22 assert(_enabled, "invariant"); 7.23 return _enabled; 7.24 @@ -67,7 +72,7 @@ 7.25 return _enabled; 7.26 } 7.27 7.28 -bool JfrRecorder::on_vm_init() { 7.29 +bool JfrRecorder::on_create_vm_1() { 7.30 if (!is_disabled()) { 7.31 if (FlightRecorder || StartFlightRecording != NULL) { 7.32 enable(); 7.33 @@ -92,7 +97,7 @@ 7.34 7.35 static void teardown_startup_support() { 7.36 release_recordings(); 7.37 - JfrOptionSet::release_startup_recording_options(); 7.38 + JfrOptionSet::release_start_flight_recording_options(); 7.39 } 7.40 7.41 // Parsing options here to detect errors as soon as possible 7.42 @@ -110,7 +115,7 @@ 7.43 } 7.44 7.45 static bool validate_recording_options(TRAPS) { 7.46 - const GrowableArray<const char*>* options = JfrOptionSet::startup_recording_options(); 7.47 + const GrowableArray<const char*>* options = JfrOptionSet::start_flight_recording_options(); 7.48 if (options == NULL) { 7.49 return true; 7.50 } 7.51 @@ -143,7 +148,7 @@ 7.52 return true; 7.53 } 7.54 7.55 -static bool launch_recordings(TRAPS) { 7.56 +static bool launch_command_line_recordings(TRAPS) { 7.57 bool result = true; 7.58 if (dcmd_recordings_array != NULL) { 7.59 const int length = dcmd_recordings_array->length(); 7.60 @@ -161,7 +166,7 @@ 7.61 7.62 static bool is_cds_dump_requested() { 7.63 // we will not be able to launch recordings if a cds dump is being requested 7.64 - if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) { 7.65 + if (DumpSharedSpaces && (JfrOptionSet::start_flight_recording_options() != NULL)) { 7.66 warning("JFR will be disabled during CDS dumping"); 7.67 teardown_startup_support(); 7.68 return true; 7.69 @@ -169,7 +174,7 @@ 7.70 return false; 7.71 } 7.72 7.73 -bool JfrRecorder::on_vm_start() { 7.74 +bool JfrRecorder::on_create_vm_2() { 7.75 if (is_cds_dump_requested()) { 7.76 return true; 7.77 } 7.78 @@ -196,9 +201,13 @@ 7.79 if (!is_enabled()) { 7.80 return true; 7.81 } 7.82 + return true; 7.83 +} 7.84 7.85 - return launch_recordings(thread); 7.86 -} 7.87 +bool JfrRecorder::on_create_vm_3() { 7.88 + assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); 7.89 + return launch_command_line_recordings(Thread::current()); 7.90 + } 7.91 7.92 static bool _created = false; 7.93 7.94 @@ -266,7 +275,6 @@ 7.95 } 7.96 7.97 // subsystems 7.98 -static JfrJvmtiAgent* _jvmti_agent = NULL; 7.99 static JfrPostBox* _post_box = NULL; 7.100 static JfrStorage* _storage = NULL; 7.101 static JfrCheckpointManager* _checkpoint_manager = NULL;
8.1 --- a/src/share/vm/jfr/recorder/jfrRecorder.hpp Sun Jun 07 18:57:54 2020 +0100 8.2 +++ b/src/share/vm/jfr/recorder/jfrRecorder.hpp Fri Jun 12 02:59:56 2020 +0100 8.3 @@ -40,6 +40,9 @@ 8.4 private: 8.5 static bool _shutting_down; 8.6 8.7 + static bool on_create_vm_1(); 8.8 + static bool on_create_vm_2(); 8.9 + static bool on_create_vm_3(); 8.10 static bool create_checkpoint_manager(); 8.11 static bool create_chunk_repository(); 8.12 static bool create_java_event_writer(); 8.13 @@ -54,8 +57,6 @@ 8.14 static bool create_components(); 8.15 static void destroy_components(); 8.16 static void on_recorder_thread_exit(); 8.17 - static bool on_vm_start(); 8.18 - static bool on_vm_init(); 8.19 8.20 public: 8.21 static bool is_enabled();
9.1 --- a/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp Sun Jun 07 18:57:54 2020 +0100 9.2 +++ b/src/share/vm/jfr/recorder/service/jfrOptionSet.cpp Fri Jun 12 02:59:56 2020 +0100 9.3 @@ -679,7 +679,7 @@ 9.4 return false; 9.5 } 9.6 9.7 -static GrowableArray<const char*>* startup_recording_options_array = NULL; 9.8 +static GrowableArray<const char*>* start_flight_recording_options_array = NULL; 9.9 9.10 bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { 9.11 assert(option != NULL, "invariant"); 9.12 @@ -702,28 +702,28 @@ 9.13 assert(value != NULL, "invariant"); 9.14 const size_t value_length = strlen(value); 9.15 9.16 - if (startup_recording_options_array == NULL) { 9.17 - startup_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<const char*>(8, true, mtTracing); 9.18 + if (start_flight_recording_options_array == NULL) { 9.19 + start_flight_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<const char*>(8, true, mtTracing); 9.20 } 9.21 - assert(startup_recording_options_array != NULL, "invariant"); 9.22 + assert(start_flight_recording_options_array != NULL, "invariant"); 9.23 char* const startup_value = NEW_C_HEAP_ARRAY(char, value_length + 1, mtTracing); 9.24 strncpy(startup_value, value, value_length + 1); 9.25 assert(strncmp(startup_value, value, value_length) == 0, "invariant"); 9.26 - startup_recording_options_array->append(startup_value); 9.27 + start_flight_recording_options_array->append(startup_value); 9.28 return false; 9.29 } 9.30 9.31 -const GrowableArray<const char*>* JfrOptionSet::startup_recording_options() { 9.32 - return startup_recording_options_array; 9.33 +const GrowableArray<const char*>* JfrOptionSet::start_flight_recording_options() { 9.34 + return start_flight_recording_options_array; 9.35 } 9.36 9.37 -void JfrOptionSet::release_startup_recording_options() { 9.38 - if (startup_recording_options_array != NULL) { 9.39 - const int length = startup_recording_options_array->length(); 9.40 +void JfrOptionSet::release_start_flight_recording_options() { 9.41 + if (start_flight_recording_options_array != NULL) { 9.42 + const int length = start_flight_recording_options_array->length(); 9.43 for (int i = 0; i < length; ++i) { 9.44 - FREE_C_HEAP_ARRAY(char, startup_recording_options_array->at(i), mtTracing); 9.45 + FREE_C_HEAP_ARRAY(char, start_flight_recording_options_array->at(i), mtTracing); 9.46 } 9.47 - delete startup_recording_options_array; 9.48 - startup_recording_options_array = NULL; 9.49 + delete start_flight_recording_options_array; 9.50 + start_flight_recording_options_array = NULL; 9.51 } 9.52 }
10.1 --- a/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp Sun Jun 07 18:57:54 2020 +0100 10.2 +++ b/src/share/vm/jfr/recorder/service/jfrOptionSet.hpp Fri Jun 12 02:59:56 2020 +0100 10.3 @@ -80,8 +80,8 @@ 10.4 10.5 static bool parse_flight_recorder_option(const JavaVMOption** option, char* delimiter); 10.6 static bool parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter); 10.7 - static const GrowableArray<const char*>* startup_recording_options(); 10.8 - static void release_startup_recording_options(); 10.9 + static const GrowableArray<const char*>* start_flight_recording_options(); 10.10 + static void release_start_flight_recording_options(); 10.11 }; 10.12 10.13 #endif // SHARE_VM_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP
11.1 --- a/src/share/vm/runtime/thread.cpp Sun Jun 07 18:57:54 2020 +0100 11.2 +++ b/src/share/vm/runtime/thread.cpp Fri Jun 12 02:59:56 2020 +0100 11.3 @@ -3440,7 +3440,7 @@ 11.4 return status; 11.5 } 11.6 11.7 - JFR_ONLY(Jfr::on_vm_init();) 11.8 + JFR_ONLY(Jfr::on_create_vm_1();) 11.9 11.10 // Should be done after the heap is fully created 11.11 main_thread->cache_global_variables(); 11.12 @@ -3491,12 +3491,16 @@ 11.13 ShouldNotReachHere(); 11.14 } 11.15 11.16 +#if !INCLUDE_JFR 11.17 + // if JFR is not enabled at the build time keep the original JvmtiExport location 11.18 + 11.19 // Always call even when there are not JVMTI environments yet, since environments 11.20 // may be attached late and JVMTI must track phases of VM execution 11.21 JvmtiExport::enter_start_phase(); 11.22 11.23 // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. 11.24 JvmtiExport::post_vm_start(); 11.25 +#endif 11.26 11.27 { 11.28 TraceTime timer("Initialize java.lang classes", TraceStartupTime); 11.29 @@ -3543,6 +3547,19 @@ 11.30 initialize_class(vmSymbols::java_lang_IllegalArgumentException(), CHECK_0); 11.31 } 11.32 11.33 + JFR_ONLY( 11.34 + Jfr::on_create_vm_2(); 11.35 + 11.36 + // if JFR is enabled at build time the JVMTI needs to be handled only after on_create_vm_2() call 11.37 + 11.38 + // Always call even when there are not JVMTI environments yet, since environments 11.39 + // may be attached late and JVMTI must track phases of VM execution 11.40 + JvmtiExport::enter_start_phase(); 11.41 + 11.42 + // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. 11.43 + JvmtiExport::post_vm_start(); 11.44 + ) 11.45 + 11.46 // See : bugid 4211085. 11.47 // Background : the static initializer of java.lang.Compiler tries to read 11.48 // property"java.compiler" and read & write property "java.vm.info". 11.49 @@ -3637,7 +3654,7 @@ 11.50 // Notify JVMTI agents that VM initialization is complete - nop if no agents. 11.51 JvmtiExport::post_vm_initialized(); 11.52 11.53 - JFR_ONLY(Jfr::on_vm_start();) 11.54 + JFR_ONLY(Jfr::on_create_vm_3();) 11.55 11.56 if (CleanChunkPoolAsync) { 11.57 Chunk::start_chunk_pool_cleaner_task();
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/runtime/8233197/T.java Fri Jun 12 02:59:56 2020 +0100 12.3 @@ -0,0 +1,11 @@ 12.4 +public class T 12.5 +{ 12.6 + public static void main(String[] args) throws Exception 12.7 + { 12.8 + for (int i = 0; i < 50; i++) { 12.9 + System.out.print("+"); 12.10 + Thread.sleep(1); 12.11 + } 12.12 + System.out.println(); 12.13 + } 12.14 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/runtime/8233197/Test8233197.sh Fri Jun 12 02:59:56 2020 +0100 13.3 @@ -0,0 +1,153 @@ 13.4 +#!/bin/sh 13.5 + 13.6 +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 13.7 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 13.8 +# 13.9 +# This code is free software; you can redistribute it and/or modify it 13.10 +# under the terms of the GNU General Public License version 2 only, as 13.11 +# published by the Free Software Foundation. 13.12 +# 13.13 +# This code is distributed in the hope that it will be useful, but WITHOUT 13.14 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13.15 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13.16 +# version 2 for more details (a copy is included in the LICENSE file that 13.17 +# accompanied this code). 13.18 +# 13.19 +# You should have received a copy of the GNU General Public License version 13.20 +# 2 along with this work; if not, write to the Free Software Foundation, 13.21 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 13.22 +# 13.23 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 13.24 +# or visit www.oracle.com if you need additional information or have any 13.25 +# questions. 13.26 + 13.27 +## 13.28 +## @test Test8233197.sh 13.29 +## @bug 8233197 13.30 +## @summary Check that JFR subsystem can be initialized from VMStart JVMTI event 13.31 +## @compile T.java 13.32 +## @run shell Test8233197.sh 13.33 +## 13.34 + 13.35 +set -x 13.36 +if [ "${TESTSRC}" = "" ] 13.37 +then 13.38 + TESTSRC=${PWD} 13.39 + echo "TESTSRC not set. Using "${TESTSRC}" as default" 13.40 +fi 13.41 +echo "TESTSRC=${TESTSRC}" 13.42 +## Adding common setup Variables for running shell tests. 13.43 +. ${TESTSRC}/../../test_env.sh 13.44 + 13.45 +# set platform-dependent variables 13.46 +OS=`uname -s` 13.47 +case "$OS" in 13.48 + Linux) 13.49 + gcc_cmd=`which gcc` 13.50 + if [ "x$gcc_cmd" == "x" ]; then 13.51 + echo "WARNING: gcc not found. Cannot execute test." 2>&1 13.52 + exit 0; 13.53 + fi 13.54 + NULL=/dev/null 13.55 + PS=":" 13.56 + FS="/" 13.57 + ;; 13.58 + * ) 13.59 + echo "Test passed; only valid for Linux" 13.60 + exit 0; 13.61 + ;; 13.62 +esac 13.63 + 13.64 +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Xinternalversion > vm_version.out 2>&1 13.65 + 13.66 +# Bitness: 13.67 +# Cannot simply look at TESTVMOPTS as -d64 is not 13.68 +# passed if there is only a 64-bit JVM available. 13.69 + 13.70 +grep "64-Bit" vm_version.out > ${NULL} 13.71 +if [ "$?" = "0" ] 13.72 +then 13.73 + COMP_FLAG="-m64" 13.74 +else 13.75 + COMP_FLAG="-m32" 13.76 +fi 13.77 + 13.78 + 13.79 +# Architecture: 13.80 +# Translate uname output to JVM directory name, but permit testing 13.81 +# 32-bit x86 on an x64 platform. 13.82 +ARCH=`uname -m` 13.83 +case "$ARCH" in 13.84 + x86_64) 13.85 + if [ "$COMP_FLAG" = "-m32" ]; then 13.86 + ARCH=i386 13.87 + else 13.88 + ARCH=amd64 13.89 + fi 13.90 + ;; 13.91 + ppc64) 13.92 + if [ "$COMP_FLAG" = "-m32" ]; then 13.93 + ARCH=ppc 13.94 + else 13.95 + ARCH=ppc64 13.96 + fi 13.97 + ;; 13.98 + sparc64) 13.99 + if [ "$COMP_FLAG" = "-m32" ]; then 13.100 + ARCH=sparc 13.101 + else 13.102 + ARCH=sparc64 13.103 + fi 13.104 + ;; 13.105 + arm*) 13.106 + # 32-bit ARM machine: compiler may not recognise -m32 13.107 + COMP_FLAG="" 13.108 + ARCH=arm 13.109 + ;; 13.110 + aarch64) 13.111 + # 64-bit arm machine, could be testing 32 or 64-bit: 13.112 + if [ "$COMP_FLAG" = "-m32" ]; then 13.113 + ARCH=arm 13.114 + else 13.115 + ARCH=aarch64 13.116 + fi 13.117 + ;; 13.118 + i586) 13.119 + ARCH=i386 13.120 + ;; 13.121 + i686) 13.122 + ARCH=i386 13.123 + ;; 13.124 + # Assuming other ARCH values need no translation 13.125 +esac 13.126 + 13.127 + 13.128 +# VM type: need to know server or client 13.129 +VMTYPE=client 13.130 +grep Server vm_version.out > ${NULL} 13.131 +if [ "$?" = "0" ] 13.132 +then 13.133 + VMTYPE=server 13.134 +fi 13.135 + 13.136 + 13.137 +LD_LIBRARY_PATH=.:${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE}:/usr/lib:$LD_LIBRARY_PATH 13.138 +export LD_LIBRARY_PATH 13.139 + 13.140 +cp ${TESTSRC}${FS}libJvmtiAgent.c . 13.141 + 13.142 +# Copy the result of our @compile action: 13.143 +cp ${TESTCLASSES}${FS}T.class . 13.144 + 13.145 +echo "Architecture: ${ARCH}" 13.146 +echo "Compilation flag: ${COMP_FLAG}" 13.147 +echo "VM type: ${VMTYPE}" 13.148 + 13.149 +$gcc_cmd -DLINUX ${COMP_FLAG} -Wl, -g -fno-strict-aliasing -fPIC -fno-omit-frame-pointer -W -Wall -Wno-unused -Wno-parentheses -c -o libJvmtiAgent.o \ 13.150 + -I${COMPILEJAVA}/include -I${COMPILEJAVA}/include/linux \ 13.151 + -L${COMPILEJAVA}/jre/lib/${ARCH}/${VMTYPE} \ 13.152 + libJvmtiAgent.c 13.153 +$gcc_cmd -shared -o libJvmtiAgent.so libJvmtiAgent.o 13.154 + 13.155 +"$TESTJAVA/bin/java" $TESTVMOPTS -agentlib:JvmtiAgent -cp $(pwd) T > T.out 13.156 +exit $? 13.157 \ No newline at end of file
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/test/runtime/8233197/libJvmtiAgent.c Fri Jun 12 02:59:56 2020 +0100 14.3 @@ -0,0 +1,124 @@ 14.4 +/* 14.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. 14.11 + * 14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.15 + * version 2 for more details (a copy is included in the LICENSE file that 14.16 + * accompanied this code). 14.17 + * 14.18 + * You should have received a copy of the GNU General Public License version 14.19 + * 2 along with this work; if not, write to the Free Software Foundation, 14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.21 + * 14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.23 + * or visit www.oracle.com if you need additional information or have any 14.24 + * questions. 14.25 + */ 14.26 + 14.27 +#include <stdio.h> 14.28 +#include <stdlib.h> 14.29 +#include <string.h> 14.30 +#include "jvmti.h" 14.31 + 14.32 +#ifdef __cplusplus 14.33 +extern "C" { 14.34 +#endif 14.35 + 14.36 +#ifndef JNI_ENV_ARG 14.37 + 14.38 +#ifdef __cplusplus 14.39 +#define JNI_ENV_ARG(x, y) y 14.40 +#define JNI_ENV_PTR(x) x 14.41 +#else 14.42 +#define JNI_ENV_ARG(x,y) x, y 14.43 +#define JNI_ENV_PTR(x) (*x) 14.44 +#endif 14.45 + 14.46 +#endif 14.47 + 14.48 +#define TranslateError(err) "JVMTI error" 14.49 + 14.50 +static jvmtiEnv *jvmti = NULL; 14.51 + 14.52 +static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 14.53 + 14.54 +JNIEXPORT 14.55 +jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 14.56 + return Agent_Initialize(jvm, options, reserved); 14.57 +} 14.58 + 14.59 +JNIEXPORT 14.60 +jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 14.61 + return Agent_Initialize(jvm, options, reserved); 14.62 +} 14.63 + 14.64 +JNIEXPORT 14.65 +jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 14.66 + return JNI_VERSION_1_8; 14.67 +} 14.68 + 14.69 +static void JNICALL 14.70 +Callback_VMStart(jvmtiEnv *jvmti_env, JNIEnv *env) { 14.71 + printf("Localizing jdk.jfr.FlightRecorder\n"); 14.72 + // without fix for 8233197 the process will crash at the following line 14.73 + jclass cls = (*env)->FindClass(env, "jdk/jfr/FlightRecorder"); 14.74 + jmethodID mid = (*env)->GetStaticMethodID(env, cls, "getFlightRecorder", "()Ljdk/jfr/FlightRecorder;"); 14.75 + if (mid == 0) { 14.76 + printf("Unable to localize jdk.jfr.FlightRecorder#getFlightRecorder() method\n"); 14.77 + // crash the tested JVM to make the test fail 14.78 + exit(-1); 14.79 + } 14.80 + printf("Going to initialize JFR subsystem ...\n"); 14.81 + jobject jfr = (*env)->CallStaticObjectMethod(env, cls, mid); 14.82 + 14.83 + if (!(*env)->ExceptionCheck(env)) { 14.84 + // crash the tested JVM to make the test fail 14.85 + printf("JFR subsystem is wrongly initialized too early\n"); 14.86 + exit(-2); 14.87 + } 14.88 + // exit VM 14.89 + exit(0); 14.90 +} 14.91 + 14.92 +static 14.93 +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 14.94 + jint res, size; 14.95 + jvmtiCapabilities caps; 14.96 + jvmtiEventCallbacks callbacks; 14.97 + jvmtiError err; 14.98 + 14.99 + res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 14.100 + JVMTI_VERSION_1_2); 14.101 + if (res != JNI_OK || jvmti == NULL) { 14.102 + printf(" Error: wrong result of a valid call to GetEnv!\n"); 14.103 + return JNI_ERR; 14.104 + } 14.105 + 14.106 + size = (jint)sizeof(callbacks); 14.107 + 14.108 + memset(&callbacks, 0, sizeof(callbacks)); 14.109 + callbacks.VMStart = Callback_VMStart; 14.110 + 14.111 + err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); 14.112 + if (err != JVMTI_ERROR_NONE) { 14.113 + printf(" Error in SetEventCallbacks: %s (%d)\n", TranslateError(err), err); 14.114 + return JNI_ERR; 14.115 + } 14.116 + 14.117 + err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, (jthread)NULL); 14.118 + if (err != JVMTI_ERROR_NONE) { 14.119 + printf(" Error in SetEventNotificationMode: %s (%d)\n", TranslateError(err), err); 14.120 + return JNI_ERR; 14.121 + } 14.122 + return JNI_OK; 14.123 +} 14.124 + 14.125 +#ifdef __cplusplus 14.126 +} 14.127 +#endif