8233197: Invert JvmtiExport::post_vm_initialized() and Jfr:on_vm_start() start-up order for correct option parsing

Fri, 12 Jun 2020 02:59:56 +0100

author
jbachorik
date
Fri, 12 Jun 2020 02:59:56 +0100
changeset 9925
30fb8c8cceb9
parent 9924
89fb452b3688
child 9926
d20a5f399218

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

src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/jfr.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/jfr.hpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/jni/jfrJavaSupport.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/jni/jfrJavaSupport.hpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/jni/jfrJniMethod.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/jfrRecorder.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/jfrRecorder.hpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/service/jfrOptionSet.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/service/jfrOptionSet.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/thread.cpp file | annotate | diff | comparison | revisions
test/runtime/8233197/T.java file | annotate | diff | comparison | revisions
test/runtime/8233197/Test8233197.sh file | annotate | diff | comparison | revisions
test/runtime/8233197/libJvmtiAgent.c file | annotate | diff | comparison | revisions
     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

mercurial