Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/jni/jfrGetAllEventClasses.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 "classfile/javaClasses.hpp"26#include "classfile/symbolTable.hpp"27#include "jfr/jni/jfrGetAllEventClasses.hpp"28#include "jfr/jni/jfrJavaSupport.hpp"29#include "jfr/support/jfrEventClass.hpp"30#include "oops/instanceKlass.hpp"31#include "memory/allocation.inline.hpp"32#include "memory/resourceArea.hpp"33#include "runtime/handles.inline.hpp"34#include "runtime/mutexLocker.hpp"35#include "runtime/safepoint.hpp"36#include "runtime/thread.inline.hpp"37#include "utilities/growableArray.hpp"38#include "utilities/stack.inline.hpp"3940// incremented during class unloading (safepoint) for each unloaded event class41static jlong unloaded_event_classes = 0;4243jlong JfrEventClasses::unloaded_event_classes_count() {44return unloaded_event_classes;45}4647void JfrEventClasses::increment_unloaded_event_class() {48// incremented during class unloading (safepoint) for each unloaded event class49assert(SafepointSynchronize::is_at_safepoint(), "invariant");50++unloaded_event_classes;51}5253static jobject empty_java_util_arraylist = NULL;5455static oop new_java_util_arraylist(TRAPS) {56DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));57JavaValue result(T_OBJECT);58JfrJavaArguments args(&result, "java/util/ArrayList", "<init>", "()V", CHECK_NULL);59JfrJavaSupport::new_object(&args, CHECK_NULL);60return (oop)result.get_jobject();61}6263static bool initialize(TRAPS) {64static bool initialized = false;65if (!initialized) {66unloaded_event_classes = 0;67assert(NULL == empty_java_util_arraylist, "invariant");68const oop array_list = new_java_util_arraylist(CHECK_false);69empty_java_util_arraylist = JfrJavaSupport::global_jni_handle(array_list, THREAD);70initialized = empty_java_util_arraylist != NULL;71}72return initialized;73}7475/*76* Abstract klasses are filtered out unconditionally.77* If a klass is not yet initialized, i.e yet to run its <clinit>78* it is also filtered out so we don't accidentally79* trigger initialization.80*/81static bool is_whitelisted(const Klass* k) {82assert(k != NULL, "invariant");83return !(k->is_abstract() || k->should_be_initialized());84}8586static void fill_klasses(GrowableArray<const void*>& event_subklasses, const Klass* event_klass, Thread* thread) {87assert(event_subklasses.length() == 0, "invariant");88assert(event_klass != NULL, "invariant");89DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));9091Stack<const Klass*, mtTracing> mark_stack;92MutexLocker ml(Compile_lock, thread);93mark_stack.push(event_klass->subklass());9495while (!mark_stack.is_empty()) {96const Klass* const current = mark_stack.pop();97assert(current != NULL, "null element in stack!");9899if (is_whitelisted(current)) {100event_subklasses.append(current);101}102103// subclass (depth)104const Klass* next_klass = current->subklass();105if (next_klass != NULL) {106mark_stack.push(next_klass);107}108109// siblings (breadth)110next_klass = current->next_sibling();111if (next_klass != NULL) {112mark_stack.push(next_klass);113}114}115assert(mark_stack.is_empty(), "invariant");116}117118static void transform_klasses_to_local_jni_handles(GrowableArray<const void*>& event_subklasses, Thread* thread) {119assert(event_subklasses.is_nonempty(), "invariant");120DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));121122for (int i = 0; i < event_subklasses.length(); ++i) {123const InstanceKlass* k = static_cast<const InstanceKlass*>(event_subklasses.at(i));124assert(is_whitelisted(k), "invariant");125event_subklasses.at_put(i, JfrJavaSupport::local_jni_handle(k->java_mirror(), thread));126}127}128129static const int initial_size_growable_array = 64;130131jobject JfrEventClasses::get_all_event_classes(TRAPS) {132DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));133initialize(THREAD);134assert(empty_java_util_arraylist != NULL, "should have been setup already!");135static const char jdk_jfr_event_name[] = "jdk/jfr/Event";136unsigned int unused_hash = 0;137Symbol* const event_klass_name = SymbolTable::lookup_only(jdk_jfr_event_name, sizeof jdk_jfr_event_name - 1, unused_hash);138139if (NULL == event_klass_name) {140// not loaded yet141return empty_java_util_arraylist;142}143144const Klass* const klass = SystemDictionary::resolve_or_null(event_klass_name, THREAD);145assert(klass != NULL, "invariant");146assert(JdkJfrEvent::is(klass), "invariant");147148if (klass->subklass() == NULL) {149return empty_java_util_arraylist;150}151152ResourceMark rm(THREAD);153GrowableArray<const void*> event_subklasses(THREAD, initial_size_growable_array);154fill_klasses(event_subklasses, klass, THREAD);155156if (event_subklasses.is_empty()) {157return empty_java_util_arraylist;158}159160transform_klasses_to_local_jni_handles(event_subklasses, THREAD);161162Handle h_array_list(THREAD, new_java_util_arraylist(THREAD));163assert(h_array_list.not_null(), "invariant");164165static const char add_method_name[] = "add";166static const char add_method_signature[] = "(Ljava/lang/Object;)Z";167const Klass* const array_list_klass = JfrJavaSupport::klass(empty_java_util_arraylist);168assert(array_list_klass != NULL, "invariant");169170const Symbol* const add_method_sym = SymbolTable::lookup(add_method_name, sizeof add_method_name - 1, THREAD);171assert(add_method_sym != NULL, "invariant");172173const Symbol* const add_method_sig_sym = SymbolTable::lookup(add_method_signature, sizeof add_method_signature - 1, THREAD);174assert(add_method_signature != NULL, "invariant");175176JavaValue result(T_BOOLEAN);177for (int i = 0; i < event_subklasses.length(); ++i) {178const jclass clazz = (const jclass)event_subklasses.at(i);179assert(JdkJfrEvent::is_subklass(clazz), "invariant");180JfrJavaArguments args(&result, array_list_klass, add_method_sym, add_method_sig_sym);181args.set_receiver(h_array_list());182args.push_jobject(clazz);183JfrJavaSupport::call_virtual(&args, THREAD);184if (HAS_PENDING_EXCEPTION || JNI_FALSE == result.get_jboolean()) {185return empty_java_util_arraylist;186}187}188return JfrJavaSupport::local_jni_handle(h_array_list(), THREAD);189}190191192