src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp

changeset 9925
30fb8c8cceb9
parent 9858
b985cbb00e68
child 9986
85e682d8ab91
     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 -

mercurial