jdk/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp
Hao Sun 3103fa08bb 8373122: JFR build failure with CDS disabled due to -Werror=unused-function after JDK-8365400
Reviewed-by: fandreuzzi, jiefu
Backport-of: e1d81c0946364a266a006481a8fbbac24c7e6c6a
2026-01-07 01:06:03 +00:00

191 lines
7.3 KiB
C++

/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "cds/aotClassLocation.hpp"
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "jfr/instrumentation/jfrClassTransformer.hpp"
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
#include "jfr/support/jfrClassDefineEvent.hpp"
#include "jfr/support/jfrSymbolTable.hpp"
#include "jfrfiles/jfrEventClasses.hpp"
#include "oops/instanceKlass.hpp"
#include "runtime/javaThread.hpp"
/*
* Two cases for JDK modules as outlined by JEP 200: The Modular JDK.
*
* The modular structure of the JDK implements the following principles:
* 1. Standard modules, whose specifications are governed by the JCP, have names starting with the string "java.".
* 2. All other modules are merely part of the JDK, and have names starting with the string "jdk.".
* */
static inline bool is_jdk_module(const char* module_name) {
assert(module_name != nullptr, "invariant");
return strstr(module_name, "java.") == module_name || strstr(module_name, "jdk.") == module_name;
}
static inline bool is_unnamed_module(const ModuleEntry* module) {
return module == nullptr || !module->is_named();
}
static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) {
assert(jt != nullptr, "invariant");
if (is_unnamed_module(module)) {
return false;
}
const Symbol* const module_symbol = module->name();
assert(module_symbol != nullptr, "invariant");
return is_jdk_module(module_symbol->as_C_string());
}
static inline bool is_jdk_module(const InstanceKlass* ik, JavaThread* jt) {
assert(ik != nullptr, "invariant");
assert(jt != nullptr, "invariant");
return is_jdk_module(ik->module(), jt);
}
static traceid module_path(const InstanceKlass* ik, JavaThread* jt) {
assert(ik != nullptr, "invariant");
const ModuleEntry* const module_entry = ik->module();
if (is_unnamed_module(module_entry)) {
return 0;
}
const char* const module_name = module_entry->name()->as_C_string();
assert(module_name != nullptr, "invariant");
if (is_jdk_module(module_name)) {
const size_t module_name_len = strlen(module_name);
char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, module_name_len + 6); // "jrt:/"
jio_snprintf(path, module_name_len + 6, "%s%s", "jrt:/", module_name);
return JfrSymbolTable::add(path);
}
return 0;
}
static traceid caller_path(const InstanceKlass* ik, JavaThread* jt) {
assert(ik != nullptr, "invariant");
assert(jt != nullptr, "invariant");
assert(ik->class_loader_data()->is_the_null_class_loader_data(), "invariant");
const Klass* const caller = jt->security_get_caller_class(1);
// caller can be null, for example, during a JVMTI VM_Init hook
if (caller != nullptr) {
const char* caller_name = caller->external_name();
assert(caller_name != nullptr, "invariant");
const size_t caller_name_len = strlen(caller_name);
char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, caller_name_len + 13); // "instance of "
jio_snprintf(path, caller_name_len + 13, "%s%s", "instance of ", caller_name);
return JfrSymbolTable::add(path);
}
return 0;
}
static traceid class_loader_path(const InstanceKlass* ik, JavaThread* jt) {
assert(ik != nullptr, "invariant");
assert(jt != nullptr, "invariant");
assert(!ik->class_loader_data()->is_the_null_class_loader_data(), "invariant");
oop class_loader = ik->class_loader_data()->class_loader();
const char* class_loader_name = class_loader->klass()->external_name();
return class_loader_name != nullptr ? JfrSymbolTable::add(class_loader_name) : 0;
}
static inline bool is_not_retransforming(const InstanceKlass* ik, JavaThread* jt) {
return JfrClassTransformer::find_existing_klass(ik, jt) == nullptr;
}
static traceid get_source(const InstanceKlass* ik, JavaThread* jt) {
traceid source_id = 0;
if (is_jdk_module(ik, jt)) {
source_id = module_path(ik, jt);
} else if (ik->class_loader_data()->is_the_null_class_loader_data()) {
source_id = caller_path(ik, jt);
} else {
source_id = class_loader_path(ik, jt);
}
return source_id;
}
static inline void send_event(const InstanceKlass* ik, traceid source_id) {
EventClassDefine event;
event.set_definedClass(ik);
event.set_definingClassLoader(ik->class_loader_data());
event.set_source(source_id);
event.commit();
}
void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt) {
assert(ik != nullptr, "invariant");
assert(ik->trace_id() != 0, "invariant");
assert(!parser.is_internal(), "invariant");
assert(jt != nullptr, "invariant");
if (EventClassDefine::is_enabled() && is_not_retransforming(ik, jt)) {
ResourceMark rm(jt);
traceid source_id = 0;
const ClassFileStream& stream = parser.stream();
if (stream.source() != nullptr) {
if (stream.from_boot_loader_modules_image()) {
assert(is_jdk_module(ik, jt), "invariant");
source_id = module_path(ik, jt);
} else {
source_id = JfrSymbolTable::add(stream.source());
}
} else {
source_id = get_source(ik, jt);
}
send_event(ik, source_id);
}
}
#if INCLUDE_CDS
static traceid get_source(const AOTClassLocation* cl, JavaThread* jt) {
assert(cl != nullptr, "invariant");
assert(!cl->is_modules_image(), "invariant");
const char* const path = cl->path();
assert(path != nullptr, "invariant");
size_t len = strlen(path);
const char* file_type = cl->file_type_string();
assert(file_type != nullptr, "invariant");
len += strlen(file_type) + 3; // ":/" + null
char* const url = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, len);
jio_snprintf(url, len, "%s%s%s", file_type, ":/", path);
return JfrSymbolTable::add(url);
}
void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) {
assert(ik != nullptr, "invariant");
assert(ik->trace_id() != 0, "invariant");
assert(jt != nullptr, "invariant");
if (EventClassDefine::is_enabled()) {
ResourceMark rm(jt);
assert(is_not_retransforming(ik, jt), "invariant");
const int index = ik->shared_classpath_index();
assert(index >= 0, "invariant");
const AOTClassLocation* const cl = AOTClassLocationConfig::runtime()->class_location_at(index);
assert(cl != nullptr, "invariant");
send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt));
}
}
#endif