Path: blob/master/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
66644 views
/*1* Copyright (c) 2016, 2022, 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 "classfile/javaClasses.inline.hpp"26#include "classfile/modules.hpp"27#include "classfile/symbolTable.hpp"28#include "classfile/vmClasses.hpp"29#include "classfile/vmSymbols.hpp"30#include "jfr/jni/jfrJavaCall.hpp"31#include "jfr/jni/jfrJavaSupport.hpp"32#include "jfr/support/jfrThreadId.hpp"33#include "logging/log.hpp"34#include "memory/resourceArea.hpp"35#include "oops/instanceOop.hpp"36#include "oops/klass.inline.hpp"37#include "oops/oop.inline.hpp"38#include "oops/objArrayKlass.hpp"39#include "oops/objArrayOop.inline.hpp"40#include "runtime/handles.inline.hpp"41#include "runtime/fieldDescriptor.inline.hpp"42#include "runtime/java.hpp"43#include "runtime/jniHandles.inline.hpp"44#include "runtime/semaphore.inline.hpp"45#include "runtime/synchronizer.hpp"46#include "runtime/thread.inline.hpp"47#include "runtime/threadSMR.hpp"48#include "utilities/growableArray.hpp"49#include "classfile/vmSymbols.hpp"5051#ifdef ASSERT52void JfrJavaSupport::check_java_thread_in_vm(JavaThread* t) {53assert(t != NULL, "invariant");54assert(t->thread_state() == _thread_in_vm, "invariant");55}5657void JfrJavaSupport::check_java_thread_in_native(JavaThread* t) {58assert(t != NULL, "invariant");59assert(t->thread_state() == _thread_in_native, "invariant");60}6162static void check_new_unstarted_java_thread(JavaThread* t) {63assert(t != NULL, "invariant");64assert(t->thread_state() == _thread_new, "invariant");65}66#endif6768/*69* Handles and references70*/71jobject JfrJavaSupport::local_jni_handle(const oop obj, JavaThread* t) {72DEBUG_ONLY(check_java_thread_in_vm(t));73return t->active_handles()->allocate_handle(obj);74}7576jobject JfrJavaSupport::local_jni_handle(const jobject handle, JavaThread* t) {77DEBUG_ONLY(check_java_thread_in_vm(t));78const oop obj = JNIHandles::resolve(handle);79return obj == NULL ? NULL : local_jni_handle(obj, t);80}8182void JfrJavaSupport::destroy_local_jni_handle(jobject handle) {83JNIHandles::destroy_local(handle);84}8586jobject JfrJavaSupport::global_jni_handle(const oop obj, JavaThread* t) {87DEBUG_ONLY(check_java_thread_in_vm(t));88HandleMark hm(t);89return JNIHandles::make_global(Handle(t, obj));90}9192jobject JfrJavaSupport::global_jni_handle(const jobject handle, JavaThread* t) {93const oop obj = JNIHandles::resolve(handle);94return obj == NULL ? NULL : global_jni_handle(obj, t);95}9697void JfrJavaSupport::destroy_global_jni_handle(jobject handle) {98JNIHandles::destroy_global(handle);99}100101jweak JfrJavaSupport::global_weak_jni_handle(const oop obj, JavaThread* t) {102DEBUG_ONLY(check_java_thread_in_vm(t));103HandleMark hm(t);104return JNIHandles::make_weak_global(Handle(t, obj));105}106107jweak JfrJavaSupport::global_weak_jni_handle(const jobject handle, JavaThread* t) {108const oop obj = JNIHandles::resolve(handle);109return obj == NULL ? NULL : global_weak_jni_handle(obj, t);110}111112void JfrJavaSupport::destroy_global_weak_jni_handle(jweak handle) {113JNIHandles::destroy_weak_global(handle);114}115116oop JfrJavaSupport::resolve_non_null(jobject obj) {117return JNIHandles::resolve_non_null(obj);118}119120/*121* Method invocation122*/123void JfrJavaSupport::call_static(JfrJavaArguments* args, TRAPS) {124JfrJavaCall::call_static(args, THREAD);125}126127void JfrJavaSupport::call_special(JfrJavaArguments* args, TRAPS) {128JfrJavaCall::call_special(args, THREAD);129}130131void JfrJavaSupport::call_virtual(JfrJavaArguments* args, TRAPS) {132JfrJavaCall::call_virtual(args, THREAD);133}134135void JfrJavaSupport::notify_all(jobject object, TRAPS) {136assert(object != NULL, "invariant");137DEBUG_ONLY(check_java_thread_in_vm(THREAD));138HandleMark hm(THREAD);139Handle h_obj(THREAD, resolve_non_null(object));140assert(h_obj.not_null(), "invariant");141ObjectSynchronizer::jni_enter(h_obj, THREAD);142ObjectSynchronizer::notifyall(h_obj, THREAD);143ObjectSynchronizer::jni_exit(h_obj(), THREAD);144DEBUG_ONLY(check_java_thread_in_vm(THREAD));145}146147/*148* Object construction149*/150static void object_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, TRAPS) {151assert(args != NULL, "invariant");152assert(result != NULL, "invariant");153assert(klass != NULL, "invariant");154assert(klass->is_initialized(), "invariant");155156HandleMark hm(THREAD);157instanceOop obj = klass->allocate_instance(CHECK);158instanceHandle h_obj(THREAD, obj);159assert(h_obj.not_null(), "invariant");160args->set_receiver(h_obj);161result->set_type(T_VOID); // constructor result type162JfrJavaSupport::call_special(args, CHECK);163result->set_type(T_OBJECT); // set back to original result type164result->set_oop(h_obj());165}166167static void array_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, int array_length, TRAPS) {168assert(args != NULL, "invariant");169assert(result != NULL, "invariant");170assert(klass != NULL, "invariant");171assert(klass->is_initialized(), "invariant");172173Klass* const ak = klass->array_klass(THREAD);174ObjArrayKlass::cast(ak)->initialize(THREAD);175HandleMark hm(THREAD);176objArrayOop arr = ObjArrayKlass::cast(ak)->allocate(array_length, CHECK);177result->set_oop(arr);178}179180static void create_object(JfrJavaArguments* args, JavaValue* result, TRAPS) {181assert(args != NULL, "invariant");182assert(result != NULL, "invariant");183assert(result->get_type() == T_OBJECT, "invariant");184DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));185186InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());187klass->initialize(CHECK);188189const int array_length = args->array_length();190191if (array_length >= 0) {192array_construction(args, result, klass, array_length, CHECK);193} else {194object_construction(args, result, klass, THREAD);195}196}197198static void handle_result(JavaValue* result, bool global_ref, JavaThread* t) {199assert(result != NULL, "invariant");200DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));201const oop result_oop = result->get_oop();202if (result_oop == NULL) {203return;204}205result->set_jobject(global_ref ?206JfrJavaSupport::global_jni_handle(result_oop, t) :207JfrJavaSupport::local_jni_handle(result_oop, t));208}209210void JfrJavaSupport::new_object(JfrJavaArguments* args, TRAPS) {211assert(args != NULL, "invariant");212DEBUG_ONLY(check_java_thread_in_vm(THREAD));213create_object(args, args->result(), THREAD);214}215216void JfrJavaSupport::new_object_local_ref(JfrJavaArguments* args, TRAPS) {217assert(args != NULL, "invariant");218DEBUG_ONLY(check_java_thread_in_vm(THREAD));219JavaValue* const result = args->result();220assert(result != NULL, "invariant");221create_object(args, result, CHECK);222handle_result(result, false, THREAD);223}224225void JfrJavaSupport::new_object_global_ref(JfrJavaArguments* args, TRAPS) {226assert(args != NULL, "invariant");227DEBUG_ONLY(check_java_thread_in_vm(THREAD));228JavaValue* const result = args->result();229assert(result != NULL, "invariant");230create_object(args, result, CHECK);231handle_result(result, true, THREAD);232}233234jstring JfrJavaSupport::new_string(const char* c_str, TRAPS) {235assert(c_str != NULL, "invariant");236DEBUG_ONLY(check_java_thread_in_vm(THREAD));237const oop result = java_lang_String::create_oop_from_str(c_str, THREAD);238return (jstring)local_jni_handle(result, THREAD);239}240241jobjectArray JfrJavaSupport::new_string_array(int length, TRAPS) {242DEBUG_ONLY(check_java_thread_in_vm(THREAD));243JavaValue result(T_OBJECT);244JfrJavaArguments args(&result, "java/lang/String", "<init>", "()V", CHECK_NULL);245args.set_array_length(length);246new_object_local_ref(&args, THREAD);247return (jobjectArray)args.result()->get_jobject();248}249250jobject JfrJavaSupport::new_java_lang_Boolean(bool value, TRAPS) {251DEBUG_ONLY(check_java_thread_in_vm(THREAD));252JavaValue result(T_OBJECT);253JfrJavaArguments args(&result, "java/lang/Boolean", "<init>", "(Z)V", CHECK_NULL);254args.push_int(value ? (jint)JNI_TRUE : (jint)JNI_FALSE);255new_object_local_ref(&args, THREAD);256return args.result()->get_jobject();257}258259jobject JfrJavaSupport::new_java_lang_Integer(jint value, TRAPS) {260DEBUG_ONLY(check_java_thread_in_vm(THREAD));261JavaValue result(T_OBJECT);262JfrJavaArguments args(&result, "java/lang/Integer", "<init>", "(I)V", CHECK_NULL);263args.push_int(value);264new_object_local_ref(&args, THREAD);265return args.result()->get_jobject();266}267268jobject JfrJavaSupport::new_java_lang_Long(jlong value, TRAPS) {269DEBUG_ONLY(check_java_thread_in_vm(THREAD));270JavaValue result(T_OBJECT);271JfrJavaArguments args(&result, "java/lang/Long", "<init>", "(J)V", CHECK_NULL);272args.push_long(value);273new_object_local_ref(&args, THREAD);274return args.result()->get_jobject();275}276277void JfrJavaSupport::set_array_element(jobjectArray arr, jobject element, int index, JavaThread* t) {278assert(arr != NULL, "invariant");279DEBUG_ONLY(check_java_thread_in_vm(t));280HandleMark hm(t);281objArrayHandle a(t, (objArrayOop)resolve_non_null(arr));282a->obj_at_put(index, resolve_non_null(element));283}284285/*286* Field access287*/288static void write_int_field(const Handle& h_oop, fieldDescriptor* fd, jint value) {289assert(h_oop.not_null(), "invariant");290assert(fd != NULL, "invariant");291h_oop->int_field_put(fd->offset(), value);292}293294static void write_float_field(const Handle& h_oop, fieldDescriptor* fd, jfloat value) {295assert(h_oop.not_null(), "invariant");296assert(fd != NULL, "invariant");297h_oop->float_field_put(fd->offset(), value);298}299300static void write_double_field(const Handle& h_oop, fieldDescriptor* fd, jdouble value) {301assert(h_oop.not_null(), "invariant");302assert(fd != NULL, "invariant");303h_oop->double_field_put(fd->offset(), value);304}305306static void write_long_field(const Handle& h_oop, fieldDescriptor* fd, jlong value) {307assert(h_oop.not_null(), "invariant");308assert(fd != NULL, "invariant");309h_oop->long_field_put(fd->offset(), value);310}311312static void write_oop_field(const Handle& h_oop, fieldDescriptor* fd, const oop value) {313assert(h_oop.not_null(), "invariant");314assert(fd != NULL, "invariant");315h_oop->obj_field_put(fd->offset(), value);316}317318static void write_specialized_field(JfrJavaArguments* args, const Handle& h_oop, fieldDescriptor* fd, bool static_field) {319assert(args != NULL, "invariant");320assert(h_oop.not_null(), "invariant");321assert(fd != NULL, "invariant");322assert(fd->offset() > 0, "invariant");323assert(args->length() >= 1, "invariant");324325// attempt must set a real value326assert(args->param(1).get_type() != T_VOID, "invariant");327328switch(fd->field_type()) {329case T_BOOLEAN:330case T_CHAR:331case T_SHORT:332case T_INT:333write_int_field(h_oop, fd, args->param(1).get_jint());334break;335case T_FLOAT:336write_float_field(h_oop, fd, args->param(1).get_jfloat());337break;338case T_DOUBLE:339write_double_field(h_oop, fd, args->param(1).get_jdouble());340break;341case T_LONG:342write_long_field(h_oop, fd, args->param(1).get_jlong());343break;344case T_OBJECT:345write_oop_field(h_oop, fd, args->param(1).get_oop());346break;347case T_ADDRESS:348write_oop_field(h_oop, fd, JfrJavaSupport::resolve_non_null(args->param(1).get_jobject()));349break;350default:351ShouldNotReachHere();352}353}354355static void read_specialized_field(JavaValue* result, const Handle& h_oop, fieldDescriptor* fd) {356assert(result != NULL, "invariant");357assert(h_oop.not_null(), "invariant");358assert(fd != NULL, "invariant");359assert(fd->offset() > 0, "invariant");360361switch(fd->field_type()) {362case T_BOOLEAN:363case T_CHAR:364case T_SHORT:365case T_INT:366result->set_jint(h_oop->int_field(fd->offset()));367break;368case T_FLOAT:369result->set_jfloat(h_oop->float_field(fd->offset()));370break;371case T_DOUBLE:372result->set_jdouble(h_oop->double_field(fd->offset()));373break;374case T_LONG:375result->set_jlong(h_oop->long_field(fd->offset()));376break;377case T_OBJECT:378result->set_oop(h_oop->obj_field(fd->offset()));379break;380default:381ShouldNotReachHere();382}383}384385static bool find_field(InstanceKlass* ik,386Symbol* name_symbol,387Symbol* signature_symbol,388fieldDescriptor* fd,389bool is_static = false,390bool allow_super = false) {391if (allow_super || is_static) {392return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL;393}394return ik->find_local_field(name_symbol, signature_symbol, fd);395}396397static void lookup_field(JfrJavaArguments* args, InstanceKlass* klass, fieldDescriptor* fd, bool static_field) {398assert(args != NULL, "invariant");399assert(klass != NULL, "invariant");400assert(klass->is_initialized(), "invariant");401assert(fd != NULL, "invariant");402find_field(klass, args->name(), args->signature(), fd, static_field, true);403}404405static void read_field(JfrJavaArguments* args, JavaValue* result, TRAPS) {406assert(args != NULL, "invariant");407assert(result != NULL, "invariant");408DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));409410InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());411klass->initialize(CHECK);412const bool static_field = !args->has_receiver();413fieldDescriptor fd;414lookup_field(args, klass, &fd, static_field);415assert(fd.offset() > 0, "invariant");416417HandleMark hm(THREAD);418Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver()));419read_specialized_field(result, h_oop, &fd);420}421422static void write_field(JfrJavaArguments* args, JavaValue* result, TRAPS) {423assert(args != NULL, "invariant");424assert(result != NULL, "invariant");425DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));426427InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());428klass->initialize(CHECK);429430const bool static_field = !args->has_receiver();431fieldDescriptor fd;432lookup_field(args, klass, &fd, static_field);433assert(fd.offset() > 0, "invariant");434435HandleMark hm(THREAD);436Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver()));437write_specialized_field(args, h_oop, &fd, static_field);438}439440void JfrJavaSupport::set_field(JfrJavaArguments* args, TRAPS) {441assert(args != NULL, "invariant");442write_field(args, args->result(), THREAD);443}444445void JfrJavaSupport::get_field(JfrJavaArguments* args, TRAPS) {446assert(args != NULL, "invariant");447read_field(args, args->result(), THREAD);448}449450void JfrJavaSupport::get_field_local_ref(JfrJavaArguments* args, TRAPS) {451assert(args != NULL, "invariant");452DEBUG_ONLY(check_java_thread_in_vm(THREAD));453454JavaValue* const result = args->result();455assert(result != NULL, "invariant");456assert(result->get_type() == T_OBJECT, "invariant");457458read_field(args, result, CHECK);459const oop obj = result->get_oop();460461if (obj != NULL) {462result->set_jobject(local_jni_handle(obj, THREAD));463}464}465466void JfrJavaSupport::get_field_global_ref(JfrJavaArguments* args, TRAPS) {467assert(args != NULL, "invariant");468DEBUG_ONLY(check_java_thread_in_vm(THREAD));469470JavaValue* const result = args->result();471assert(result != NULL, "invariant");472assert(result->get_type() == T_OBJECT, "invariant");473read_field(args, result, CHECK);474const oop obj = result->get_oop();475if (obj != NULL) {476result->set_jobject(global_jni_handle(obj, THREAD));477}478}479480/*481* Misc482*/483Klass* JfrJavaSupport::klass(const jobject handle) {484const oop obj = resolve_non_null(handle);485assert(obj != NULL, "invariant");486return obj->klass();487}488489static char* allocate_string(bool c_heap, int length, JavaThread* jt) {490return c_heap ? NEW_C_HEAP_ARRAY(char, length, mtTracing) :491NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, length);492}493494const char* JfrJavaSupport::c_str(oop string, JavaThread* t, bool c_heap /* false */) {495DEBUG_ONLY(check_java_thread_in_vm(t));496char* str = NULL;497const typeArrayOop value = java_lang_String::value(string);498if (value != NULL) {499const int length = java_lang_String::utf8_length(string, value);500str = allocate_string(c_heap, length + 1, t);501if (str == NULL) {502JfrJavaSupport::throw_out_of_memory_error("Unable to allocate native memory", t);503return NULL;504}505java_lang_String::as_utf8_string(string, value, str, length + 1);506}507return str;508}509510const char* JfrJavaSupport::c_str(jstring string, JavaThread* t, bool c_heap /* false */) {511DEBUG_ONLY(check_java_thread_in_vm(t));512return string != NULL ? c_str(resolve_non_null(string), t, c_heap) : NULL;513}514515/*516* Exceptions and errors517*/518static void create_and_throw(Symbol* name, const char* message, TRAPS) {519assert(name != NULL, "invariant");520DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));521assert(!HAS_PENDING_EXCEPTION, "invariant");522THROW_MSG(name, message);523}524525void JfrJavaSupport::throw_illegal_state_exception(const char* message, TRAPS) {526create_and_throw(vmSymbols::java_lang_IllegalStateException(), message, THREAD);527}528529void JfrJavaSupport::throw_internal_error(const char* message, TRAPS) {530create_and_throw(vmSymbols::java_lang_InternalError(), message, THREAD);531}532533void JfrJavaSupport::throw_illegal_argument_exception(const char* message, TRAPS) {534create_and_throw(vmSymbols::java_lang_IllegalArgumentException(), message, THREAD);535}536537void JfrJavaSupport::throw_out_of_memory_error(const char* message, TRAPS) {538create_and_throw(vmSymbols::java_lang_OutOfMemoryError(), message, THREAD);539}540541void JfrJavaSupport::throw_class_format_error(const char* message, TRAPS) {542create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD);543}544545void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) {546create_and_throw(vmSymbols::java_lang_RuntimeException(), message, THREAD);547}548549void JfrJavaSupport::abort(jstring errorMsg, JavaThread* t) {550DEBUG_ONLY(check_java_thread_in_vm(t));551ResourceMark rm(t);552abort(c_str(errorMsg, t));553}554555void JfrJavaSupport::abort(const char* error_msg, bool dump_core /* true */) {556if (error_msg != nullptr) {557log_error(jfr, system)("%s", error_msg);558}559log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM...");560vm_abort(dump_core);561}562563JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR;564void JfrJavaSupport::set_cause(jthrowable throwable, JavaThread* t) {565DEBUG_ONLY(check_java_thread_in_vm(t));566567HandleMark hm(t);568Handle ex(t, JNIHandles::resolve_external_guard(throwable));569570if (ex.is_null()) {571return;572}573574if (ex->is_a(vmClasses::OutOfMemoryError_klass())) {575_cause = OUT_OF_MEMORY;576return;577}578if (ex->is_a(vmClasses::StackOverflowError_klass())) {579_cause = STACK_OVERFLOW;580return;581}582if (ex->is_a(vmClasses::Error_klass())) {583_cause = VM_ERROR;584return;585}586if (ex->is_a(vmClasses::RuntimeException_klass())) {587_cause = RUNTIME_EXCEPTION;588return;589}590if (ex->is_a(vmClasses::Exception_klass())) {591_cause = UNKNOWN;592return;593}594}595596void JfrJavaSupport::uncaught_exception(jthrowable throwable, JavaThread* t) {597DEBUG_ONLY(check_java_thread_in_vm(t));598assert(throwable != NULL, "invariant");599set_cause(throwable, t);600}601602JfrJavaSupport::CAUSE JfrJavaSupport::cause() {603return _cause;604}605606const char* const JDK_JFR_MODULE_NAME = "jdk.jfr";607const char* const JDK_JFR_PACKAGE_NAME = "jdk/jfr";608609static bool is_jdk_jfr_module_in_readability_graph() {610// take one of the packages in the module to be located and query for its definition.611TempNewSymbol pkg_sym = SymbolTable::new_symbol(JDK_JFR_PACKAGE_NAME);612return Modules::is_package_defined(pkg_sym, Handle());613}614615static void print_module_resolution_error(outputStream* stream) {616assert(stream != NULL, "invariant");617stream->print_cr("Module %s not found.", JDK_JFR_MODULE_NAME);618stream->print_cr("Flight Recorder can not be enabled.");619}620621bool JfrJavaSupport::is_jdk_jfr_module_available() {622return is_jdk_jfr_module_in_readability_graph();623}624625bool JfrJavaSupport::is_jdk_jfr_module_available(outputStream* stream, TRAPS) {626if (!JfrJavaSupport::is_jdk_jfr_module_available()) {627if (stream != NULL) {628print_module_resolution_error(stream);629}630return false;631}632return true;633}634635class ThreadExclusionListAccess : public StackObj {636private:637static Semaphore _mutex_semaphore;638public:639ThreadExclusionListAccess() { _mutex_semaphore.wait(); }640~ThreadExclusionListAccess() { _mutex_semaphore.signal(); }641};642643Semaphore ThreadExclusionListAccess::_mutex_semaphore(1);644static GrowableArray<jweak>* exclusion_list = NULL;645646static bool equals(const jweak excluded_thread, Handle target_thread) {647return JfrJavaSupport::resolve_non_null(excluded_thread) == target_thread();648}649650static int find_exclusion_thread_idx(Handle thread) {651if (exclusion_list != NULL) {652for (int i = 0; i < exclusion_list->length(); ++i) {653if (equals(exclusion_list->at(i), thread)) {654return i;655}656}657}658return -1;659}660661static Handle as_handle(jobject thread) {662return Handle(Thread::current(), JfrJavaSupport::resolve_non_null(thread));663}664665static bool thread_is_not_excluded(Handle thread) {666return -1 == find_exclusion_thread_idx(thread);667}668669static bool thread_is_not_excluded(jobject thread) {670return thread_is_not_excluded(as_handle(thread));671}672673static bool is_thread_excluded(jobject thread) {674return !thread_is_not_excluded(thread);675}676677#ifdef ASSERT678static bool is_thread_excluded(Handle thread) {679return !thread_is_not_excluded(thread);680}681#endif // ASSERT682683static int add_thread_to_exclusion_list(jobject thread) {684ThreadExclusionListAccess lock;685if (exclusion_list == NULL) {686exclusion_list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<jweak>(10, mtTracing);687}688assert(exclusion_list != NULL, "invariant");689assert(thread_is_not_excluded(thread), "invariant");690jweak ref = JfrJavaSupport::global_weak_jni_handle(thread, JavaThread::current());691const int idx = exclusion_list->append(ref);692assert(is_thread_excluded(thread), "invariant");693return idx;694}695696static void remove_thread_from_exclusion_list(Handle thread) {697assert(exclusion_list != NULL, "invariant");698assert(is_thread_excluded(thread), "invariant");699assert(exclusion_list != NULL, "invariant");700const int idx = find_exclusion_thread_idx(thread);701assert(idx >= 0, "invariant");702assert(idx < exclusion_list->length(), "invariant");703JfrJavaSupport::destroy_global_weak_jni_handle(exclusion_list->at(idx));704exclusion_list->delete_at(idx);705assert(thread_is_not_excluded(thread), "invariant");706if (0 == exclusion_list->length()) {707delete exclusion_list;708exclusion_list = NULL;709}710}711712static void remove_thread_from_exclusion_list(jobject thread) {713ThreadExclusionListAccess lock;714remove_thread_from_exclusion_list(as_handle(thread));715}716717// includes removal718static bool check_exclusion_state_on_thread_start(JavaThread* jt) {719Handle h_obj(jt, jt->threadObj());720ThreadExclusionListAccess lock;721if (thread_is_not_excluded(h_obj)) {722return false;723}724remove_thread_from_exclusion_list(h_obj);725return true;726}727728static JavaThread* get_native(jobject thread) {729ThreadsListHandle tlh;730JavaThread* native_thread = NULL;731(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);732return native_thread;733}734735jlong JfrJavaSupport::jfr_thread_id(jobject thread) {736JavaThread* native_thread = get_native(thread);737return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;738}739740void JfrJavaSupport::exclude(jobject thread) {741JavaThread* native_thread = get_native(thread);742if (native_thread != NULL) {743JfrThreadLocal::exclude(native_thread);744} else {745// not started yet, track the thread oop746add_thread_to_exclusion_list(thread);747}748}749750void JfrJavaSupport::include(jobject thread) {751JavaThread* native_thread = get_native(thread);752if (native_thread != NULL) {753JfrThreadLocal::include(native_thread);754} else {755// not started yet, untrack the thread oop756remove_thread_from_exclusion_list(thread);757}758}759760bool JfrJavaSupport::is_excluded(jobject thread) {761JavaThread* native_thread = get_native(thread);762return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);763}764765static const Klass* get_handler_field_descriptor(const Handle& h_mirror, fieldDescriptor* descriptor, TRAPS) {766assert(h_mirror.not_null(), "invariant");767assert(descriptor != NULL, "invariant");768Klass* const k = java_lang_Class::as_Klass(h_mirror());769assert(k->is_instance_klass(), "invariant");770InstanceKlass* const ik = InstanceKlass::cast(k);771if (ik->is_not_initialized()) {772ik->initialize(CHECK_NULL);773}774assert(ik->is_being_initialized() || ik->is_initialized(), "invariant");775const Klass* const typed_field_holder = ik->find_field(vmSymbols::eventHandler_name(),776vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(),777true,778descriptor);779return typed_field_holder != NULL ? typed_field_holder : ik->find_field(vmSymbols::eventHandler_name(),780vmSymbols::object_signature(), // untyped781true,782descriptor);783}784785jobject JfrJavaSupport::get_handler(jobject clazz, TRAPS) {786DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));787HandleMark hm(THREAD);788const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz)));789assert(h_mirror.not_null(), "invariant");790fieldDescriptor handler_field_descriptor;791const Klass* const field_holder = get_handler_field_descriptor(h_mirror, &handler_field_descriptor, THREAD);792if (field_holder == NULL) {793// The only reason should be that klass initialization failed.794return NULL;795}796assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant");797oop handler_oop = h_mirror->obj_field(handler_field_descriptor.offset());798return handler_oop != NULL ? JfrJavaSupport::local_jni_handle(handler_oop, THREAD) : NULL;799}800801bool JfrJavaSupport::set_handler(jobject clazz, jobject handler, TRAPS) {802DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));803HandleMark hm(THREAD);804const Handle h_mirror(Handle(THREAD, JNIHandles::resolve(clazz)));805assert(h_mirror.not_null(), "invariant");806fieldDescriptor handler_field_descriptor;807const Klass* const field_holder = get_handler_field_descriptor(h_mirror, &handler_field_descriptor, THREAD);808if (field_holder == NULL) {809// The only reason should be that klass initialization failed.810return false;811}812assert(java_lang_Class::as_Klass(h_mirror()) == field_holder, "invariant");813const oop handler_oop = JNIHandles::resolve(handler);814assert(handler_oop != NULL, "invariant");815h_mirror->obj_field_put(handler_field_descriptor.offset(), handler_oop);816return true;817}818819void JfrJavaSupport::on_thread_start(Thread* t) {820assert(t != NULL, "invariant");821assert(Thread::current() == t, "invariant");822if (!t->is_Java_thread()) {823return;824}825DEBUG_ONLY(check_new_unstarted_java_thread(t->as_Java_thread());)826HandleMark hm(t);827if (check_exclusion_state_on_thread_start(t->as_Java_thread())) {828JfrThreadLocal::exclude(t);829}830}831832833