Path: blob/master/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
41149 views
/*1* Copyright (c) 2016, 2021, 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}488489// caller needs ResourceMark490const char* JfrJavaSupport::c_str(oop string, JavaThread* t) {491DEBUG_ONLY(check_java_thread_in_vm(t));492char* resource_copy = NULL;493const typeArrayOop value = java_lang_String::value(string);494if (value != NULL) {495const int length = java_lang_String::utf8_length(string, value);496resource_copy = NEW_RESOURCE_ARRAY_IN_THREAD(t, char, (length + 1));497if (resource_copy == NULL) {498JfrJavaSupport::throw_out_of_memory_error("Unable to allocate thread local native memory", t);499return NULL;500}501assert(resource_copy != NULL, "invariant");502java_lang_String::as_utf8_string(string, value, resource_copy, length + 1);503}504return resource_copy;505}506507// caller needs ResourceMark508const char* JfrJavaSupport::c_str(jstring string, JavaThread* t) {509DEBUG_ONLY(check_java_thread_in_vm(t));510return string != NULL ? c_str(resolve_non_null(string), t) : NULL;511}512513/*514* Exceptions and errors515*/516static void create_and_throw(Symbol* name, const char* message, TRAPS) {517assert(name != NULL, "invariant");518DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));519assert(!HAS_PENDING_EXCEPTION, "invariant");520THROW_MSG(name, message);521}522523void JfrJavaSupport::throw_illegal_state_exception(const char* message, TRAPS) {524create_and_throw(vmSymbols::java_lang_IllegalStateException(), message, THREAD);525}526527void JfrJavaSupport::throw_internal_error(const char* message, TRAPS) {528create_and_throw(vmSymbols::java_lang_InternalError(), message, THREAD);529}530531void JfrJavaSupport::throw_illegal_argument_exception(const char* message, TRAPS) {532create_and_throw(vmSymbols::java_lang_IllegalArgumentException(), message, THREAD);533}534535void JfrJavaSupport::throw_out_of_memory_error(const char* message, TRAPS) {536create_and_throw(vmSymbols::java_lang_OutOfMemoryError(), message, THREAD);537}538539void JfrJavaSupport::throw_class_format_error(const char* message, TRAPS) {540create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD);541}542543void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) {544create_and_throw(vmSymbols::java_lang_RuntimeException(), message, THREAD);545}546547void JfrJavaSupport::abort(jstring errorMsg, JavaThread* t) {548DEBUG_ONLY(check_java_thread_in_vm(t));549550ResourceMark rm(t);551const char* const error_msg = c_str(errorMsg, t);552if (error_msg != NULL) {553log_error(jfr, system)("%s",error_msg);554}555log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM...");556vm_abort();557}558559JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR;560void JfrJavaSupport::set_cause(jthrowable throwable, JavaThread* t) {561DEBUG_ONLY(check_java_thread_in_vm(t));562563HandleMark hm(t);564Handle ex(t, JNIHandles::resolve_external_guard(throwable));565566if (ex.is_null()) {567return;568}569570if (ex->is_a(vmClasses::OutOfMemoryError_klass())) {571_cause = OUT_OF_MEMORY;572return;573}574if (ex->is_a(vmClasses::StackOverflowError_klass())) {575_cause = STACK_OVERFLOW;576return;577}578if (ex->is_a(vmClasses::Error_klass())) {579_cause = VM_ERROR;580return;581}582if (ex->is_a(vmClasses::RuntimeException_klass())) {583_cause = RUNTIME_EXCEPTION;584return;585}586if (ex->is_a(vmClasses::Exception_klass())) {587_cause = UNKNOWN;588return;589}590}591592void JfrJavaSupport::uncaught_exception(jthrowable throwable, JavaThread* t) {593DEBUG_ONLY(check_java_thread_in_vm(t));594assert(throwable != NULL, "invariant");595set_cause(throwable, t);596}597598JfrJavaSupport::CAUSE JfrJavaSupport::cause() {599return _cause;600}601602const char* const JDK_JFR_MODULE_NAME = "jdk.jfr";603const char* const JDK_JFR_PACKAGE_NAME = "jdk/jfr";604605static bool is_jdk_jfr_module_in_readability_graph() {606// take one of the packages in the module to be located and query for its definition.607TempNewSymbol pkg_sym = SymbolTable::new_symbol(JDK_JFR_PACKAGE_NAME);608return Modules::is_package_defined(pkg_sym, Handle());609}610611static void print_module_resolution_error(outputStream* stream) {612assert(stream != NULL, "invariant");613stream->print_cr("Module %s not found.", JDK_JFR_MODULE_NAME);614stream->print_cr("Flight Recorder can not be enabled.");615}616617bool JfrJavaSupport::is_jdk_jfr_module_available() {618return is_jdk_jfr_module_in_readability_graph();619}620621bool JfrJavaSupport::is_jdk_jfr_module_available(outputStream* stream, TRAPS) {622if (!JfrJavaSupport::is_jdk_jfr_module_available()) {623if (stream != NULL) {624print_module_resolution_error(stream);625}626return false;627}628return true;629}630631class ThreadExclusionListAccess : public StackObj {632private:633static Semaphore _mutex_semaphore;634public:635ThreadExclusionListAccess() { _mutex_semaphore.wait(); }636~ThreadExclusionListAccess() { _mutex_semaphore.signal(); }637};638639Semaphore ThreadExclusionListAccess::_mutex_semaphore(1);640static GrowableArray<jweak>* exclusion_list = NULL;641642static bool equals(const jweak excluded_thread, Handle target_thread) {643return JfrJavaSupport::resolve_non_null(excluded_thread) == target_thread();644}645646static int find_exclusion_thread_idx(Handle thread) {647if (exclusion_list != NULL) {648for (int i = 0; i < exclusion_list->length(); ++i) {649if (equals(exclusion_list->at(i), thread)) {650return i;651}652}653}654return -1;655}656657static Handle as_handle(jobject thread) {658return Handle(Thread::current(), JfrJavaSupport::resolve_non_null(thread));659}660661static bool thread_is_not_excluded(Handle thread) {662return -1 == find_exclusion_thread_idx(thread);663}664665static bool thread_is_not_excluded(jobject thread) {666return thread_is_not_excluded(as_handle(thread));667}668669static bool is_thread_excluded(jobject thread) {670return !thread_is_not_excluded(thread);671}672673#ifdef ASSERT674static bool is_thread_excluded(Handle thread) {675return !thread_is_not_excluded(thread);676}677#endif // ASSERT678679static int add_thread_to_exclusion_list(jobject thread) {680ThreadExclusionListAccess lock;681if (exclusion_list == NULL) {682exclusion_list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<jweak>(10, mtTracing);683}684assert(exclusion_list != NULL, "invariant");685assert(thread_is_not_excluded(thread), "invariant");686jweak ref = JfrJavaSupport::global_weak_jni_handle(thread, JavaThread::current());687const int idx = exclusion_list->append(ref);688assert(is_thread_excluded(thread), "invariant");689return idx;690}691692static void remove_thread_from_exclusion_list(Handle thread) {693assert(exclusion_list != NULL, "invariant");694assert(is_thread_excluded(thread), "invariant");695assert(exclusion_list != NULL, "invariant");696const int idx = find_exclusion_thread_idx(thread);697assert(idx >= 0, "invariant");698assert(idx < exclusion_list->length(), "invariant");699JfrJavaSupport::destroy_global_weak_jni_handle(exclusion_list->at(idx));700exclusion_list->delete_at(idx);701assert(thread_is_not_excluded(thread), "invariant");702if (0 == exclusion_list->length()) {703delete exclusion_list;704exclusion_list = NULL;705}706}707708static void remove_thread_from_exclusion_list(jobject thread) {709ThreadExclusionListAccess lock;710remove_thread_from_exclusion_list(as_handle(thread));711}712713// includes removal714static bool check_exclusion_state_on_thread_start(JavaThread* jt) {715Handle h_obj(jt, jt->threadObj());716ThreadExclusionListAccess lock;717if (thread_is_not_excluded(h_obj)) {718return false;719}720remove_thread_from_exclusion_list(h_obj);721return true;722}723724static JavaThread* get_native(jobject thread) {725ThreadsListHandle tlh;726JavaThread* native_thread = NULL;727(void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL);728return native_thread;729}730731jlong JfrJavaSupport::jfr_thread_id(jobject thread) {732JavaThread* native_thread = get_native(thread);733return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;734}735736void JfrJavaSupport::exclude(jobject thread) {737JavaThread* native_thread = get_native(thread);738if (native_thread != NULL) {739JfrThreadLocal::exclude(native_thread);740} else {741// not started yet, track the thread oop742add_thread_to_exclusion_list(thread);743}744}745746void JfrJavaSupport::include(jobject thread) {747JavaThread* native_thread = get_native(thread);748if (native_thread != NULL) {749JfrThreadLocal::include(native_thread);750} else {751// not started yet, untrack the thread oop752remove_thread_from_exclusion_list(thread);753}754}755756bool JfrJavaSupport::is_excluded(jobject thread) {757JavaThread* native_thread = get_native(thread);758return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread);759}760761jobject JfrJavaSupport::get_handler(jobject clazz, TRAPS) {762DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));763const oop klass_oop = JNIHandles::resolve(clazz);764assert(klass_oop != NULL, "invariant");765Klass* klass = java_lang_Class::as_Klass(klass_oop);766HandleMark hm(THREAD);767Handle h_klass_oop(Handle(THREAD, klass->java_mirror()));768InstanceKlass* const instance_klass = static_cast<InstanceKlass*>(klass);769klass->initialize(CHECK_NULL);770771fieldDescriptor event_handler_field;772Klass* f = instance_klass->find_field(773vmSymbols::eventHandler_name(),774vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(),775true, &event_handler_field);776if (f != NULL) {777oop ret = h_klass_oop->obj_field(event_handler_field.offset());778return ret != NULL ? JfrJavaSupport::local_jni_handle(ret, THREAD) : NULL;779}780781fieldDescriptor object_field;782Klass* g = instance_klass->find_field(783vmSymbols::eventHandler_name(),784vmSymbols::object_signature(),785true, &object_field);786if (g != NULL) {787oop ret = h_klass_oop->obj_field(object_field.offset());788return ret != NULL ? JfrJavaSupport::local_jni_handle(ret, THREAD) : NULL;789}790assert(f == NULL && g == NULL, "no handler field for class");791return NULL;792}793794bool JfrJavaSupport::set_handler(jobject clazz, jobject handler, TRAPS) {795DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));796const oop klass_oop = JNIHandles::resolve(clazz);797assert(klass_oop != NULL, "invariant");798const oop handler_oop = JNIHandles::resolve(handler);799assert(handler_oop != NULL, "invariant");800Klass* klass = java_lang_Class::as_Klass(klass_oop);801HandleMark hm(THREAD);802Handle h_klass_oop(Handle(THREAD, klass->java_mirror()));803InstanceKlass* const instance_klass = static_cast<InstanceKlass*>(klass);804klass->initialize(CHECK_false);805806fieldDescriptor event_handler_field;807Klass* f = instance_klass->find_field(808vmSymbols::eventHandler_name(),809vmSymbols::jdk_jfr_internal_handlers_EventHandler_signature(),810true, &event_handler_field);811if (f != NULL) {812h_klass_oop->obj_field_put(event_handler_field.offset(), handler_oop);813return true;814}815816fieldDescriptor object_handler_field;817Klass* g = instance_klass->find_field(818vmSymbols::eventHandler_name(),819vmSymbols::object_signature(),820true, &object_handler_field);821if (g != NULL) {822h_klass_oop->obj_field_put(object_handler_field.offset(), handler_oop);823return true;824}825assert(f == NULL && g == NULL, "no handler field for class");826return false;827}828829void JfrJavaSupport::on_thread_start(Thread* t) {830assert(t != NULL, "invariant");831assert(Thread::current() == t, "invariant");832if (!t->is_Java_thread()) {833return;834}835DEBUG_ONLY(check_new_unstarted_java_thread(t->as_Java_thread());)836HandleMark hm(t);837if (check_exclusion_state_on_thread_start(t->as_Java_thread())) {838JfrThreadLocal::exclude(t);839}840}841842843