Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp
38920 views
/*1* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm.h"26#include "jfr/instrumentation/jfrJvmtiAgent.hpp"27#include "jfr/jni/jfrJavaSupport.hpp"28#include "jfr/jni/jfrUpcalls.hpp"29#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"30#include "jfr/recorder/service/jfrOptionSet.hpp"31#include "jfr/support/jfrEventClass.hpp"32#include "memory/resourceArea.hpp"33#include "prims/jvmtiExport.hpp"34#include "runtime/interfaceSupport.hpp"35#include "runtime/thread.inline.hpp"36#include "utilities/exceptions.hpp"3738static const size_t ERROR_MSG_BUFFER_SIZE = 256;39static JfrJvmtiAgent* agent = NULL;40static jvmtiEnv* jfr_jvmti_env = NULL;4142static void check_jvmti_error(jvmtiEnv* jvmti, jvmtiError errnum, const char* str) {43if (errnum != JVMTI_ERROR_NONE) {44char* errnum_str = NULL;45jvmti->GetErrorName(errnum, &errnum_str);46if (true) tty->print_cr("ERROR: JfrJvmtiAgent: " INT32_FORMAT " (%s): %s\n",47errnum,48NULL == errnum_str ? "Unknown" : errnum_str,49NULL == str ? "" : str);50}51}5253static jvmtiError set_event_notification_mode(jvmtiEventMode mode,54jvmtiEvent event,55jthread event_thread,56...) {57if (jfr_jvmti_env == NULL) {58return JVMTI_ERROR_NONE;59}60const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread);61check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode");62return jvmti_ret_code;63}6465static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) {66return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);67}6869static JavaThread* current_java_thread() {70Thread* this_thread = Thread::current();71assert(this_thread != NULL && this_thread->is_Java_thread(), "invariant");72return static_cast<JavaThread*>(this_thread);73}7475// jvmti event callbacks require C linkage76extern "C" void JNICALL jfr_on_class_file_load_hook(jvmtiEnv *jvmti_env,77JNIEnv* jni_env,78jclass class_being_redefined,79jobject loader,80const char* name,81jobject protection_domain,82jint class_data_len,83const unsigned char* class_data,84jint* new_class_data_len,85unsigned char** new_class_data) {86if (class_being_redefined == NULL) {87return;88}89JavaThread* jt = JavaThread::thread_from_jni_environment(jni_env);90DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));;91ThreadInVMfromNative tvmfn(jt);92JfrUpcalls::on_retransform(JfrTraceId::get(class_being_redefined),93class_being_redefined,94class_data_len,95class_data,96new_class_data_len,97new_class_data,98jt);99}100101// caller needs ResourceMark102static jclass* create_classes_array(jint classes_count, TRAPS) {103assert(classes_count > 0, "invariant");104DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));105ThreadInVMfromNative tvmfn((JavaThread*)THREAD);106jclass* const classes = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jclass, classes_count);107if (NULL == classes) {108char error_buffer[ERROR_MSG_BUFFER_SIZE];109jio_snprintf(error_buffer, ERROR_MSG_BUFFER_SIZE,110"Thread local allocation (native) of " SIZE_FORMAT " bytes failed "111"in retransform classes", sizeof(jclass) * classes_count);112if (true) tty->print_cr("%s", error_buffer);113JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL);114}115return classes;116}117118static void log_and_throw(TRAPS) {119if (!HAS_PENDING_EXCEPTION) {120DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));121ThreadInVMfromNative tvmfn((JavaThread*)THREAD);122if (true) tty->print_cr("JfrJvmtiAgent::retransformClasses failed");123JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD);124}125}126127static void check_exception_and_log(JNIEnv* env, TRAPS) {128assert(env != NULL, "invariant");129if (env->ExceptionOccurred()) {130// array index out of bound131DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));132ThreadInVMfromNative tvmfn((JavaThread*)THREAD);133if (true) tty->print_cr("GetObjectArrayElement threw an exception");134return;135}136}137138void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) {139assert(env != NULL, "invariant");140DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));141if (classes_array == NULL) {142return;143}144const jint classes_count = env->GetArrayLength(classes_array);145if (classes_count <= 0) {146return;147}148ResourceMark rm(THREAD);149jclass* const classes = create_classes_array(classes_count, CHECK);150assert(classes != NULL, "invariant");151for (jint i = 0; i < classes_count; i++) {152jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i);153check_exception_and_log(env, THREAD);154155// inspecting the oop/klass requires a thread transition156{157ThreadInVMfromNative transition((JavaThread*)THREAD);158if (JdkJfrEvent::is_a(clz)) {159// should have been tagged already160assert(JdkJfrEvent::is_subklass(clz), "invariant");161} else {162// outside the event hierarchy163JdkJfrEvent::tag_as_host(clz);164}165}166167classes[i] = clz;168}169if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) {170log_and_throw(THREAD);171}172}173174static jvmtiError register_callbacks(JavaThread* jt) {175assert(jfr_jvmti_env != NULL, "invariant");176DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));177jvmtiEventCallbacks callbacks;178/* Set callbacks */179memset(&callbacks, 0, sizeof(callbacks));180callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;181const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));182check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");183return jvmti_ret_code;184}185186static jvmtiError register_capabilities(JavaThread* jt) {187assert(jfr_jvmti_env != NULL, "invariant");188DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));189jvmtiCapabilities capabilities;190/* Add JVMTI capabilities */191(void)memset(&capabilities, 0, sizeof(capabilities));192capabilities.can_retransform_classes = 1;193capabilities.can_retransform_any_class = 1;194const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities);195check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities");196return jvmti_ret_code;197}198199static jint create_jvmti_env(JavaThread* jt) {200assert(jfr_jvmti_env == NULL, "invariant");201DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));202extern struct JavaVM_ main_vm;203JavaVM* vm = &main_vm;204return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION);205}206207static jvmtiError unregister_callbacks(JavaThread* jt) {208if (jfr_jvmti_env == NULL) {209return JVMTI_ERROR_NONE;210}211jvmtiEventCallbacks callbacks;212/* Set empty callbacks */213memset(&callbacks, 0, sizeof(callbacks));214const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));215check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");216return jvmti_ret_code;217}218219JfrJvmtiAgent::JfrJvmtiAgent() {}220221JfrJvmtiAgent::~JfrJvmtiAgent() {222JavaThread* jt = current_java_thread();223DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));224ThreadToNativeFromVM transition(jt);225update_class_file_load_hook_event(JVMTI_DISABLE);226unregister_callbacks(jt);227if (jfr_jvmti_env != NULL) {228jfr_jvmti_env->DisposeEnvironment();229jfr_jvmti_env = NULL;230}231agent = NULL;232}233234static bool initialize() {235JavaThread* const jt = current_java_thread();236assert(jt != NULL, "invariant");237assert(jt->thread_state() == _thread_in_vm, "invariant");238DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));239ThreadToNativeFromVM transition(jt);240if (create_jvmti_env(jt) != JNI_OK) {241assert(jfr_jvmti_env == NULL, "invariant");242return false;243}244assert(jfr_jvmti_env != NULL, "invariant");245if (register_capabilities(jt) != JVMTI_ERROR_NONE) {246return false;247}248if (register_callbacks(jt) != JVMTI_ERROR_NONE) {249return false;250}251if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) {252return false;253}254return true;255}256257bool JfrJvmtiAgent::create() {258assert(jfr_jvmti_env == NULL, "invariant");259agent = new JfrJvmtiAgent();260if (agent == NULL) {261return false;262}263if (!initialize()) {264delete agent;265agent = NULL;266return false;267}268return true;269}270271void JfrJvmtiAgent::destroy() {272if (agent != NULL) {273delete agent;274agent = NULL;275}276}277278279280