diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp index 3f644102d32..2947c1082d3 100644 --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp @@ -1890,13 +1890,17 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na address code_begin, address code_end) { // register the stub with the current dynamic code event collector - JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current()); - // state can only be NULL if the current thread is exiting which - // should not happen since we're trying to post an event - guarantee(state != NULL, "attempt to register stub via an exiting thread"); - JvmtiDynamicCodeEventCollector* collector = state->get_dynamic_code_event_collector(); - guarantee(collector != NULL, "attempt to register stub without event collector"); - collector->register_stub(name, code_begin, code_end); + // Cannot take safepoint here so do not use state_for to get + // jvmti thread state. + // The collector and/or state might be NULL if JvmtiDynamicCodeEventCollector + // has been initialized while JVMTI_EVENT_DYNAMIC_CODE_GENERATED was disabled. + JvmtiThreadState* state = JavaThread::current()->jvmti_thread_state(); + if (state != NULL) { + JvmtiDynamicCodeEventCollector *collector = state->get_dynamic_code_event_collector(); + if (collector != NULL) { + collector->register_stub(name, code_begin, code_end); + } + } } // Collect all the vm internally allocated objects which are visible to java world diff --git a/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGenerated.java b/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGenerated.java new file mode 100644 index 00000000000..a5a970ea121 --- /dev/null +++ b/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGenerated.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, 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. + */ + +public class DynamicCodeGenerated { + static { + System.loadLibrary("DynamicCodeGenerated"); + } + public static native void changeEventNotificationMode(); + + public static void main(String[] args) { + // Try to enable DynamicCodeGenerated event while it is posted + // using JvmtiDynamicCodeEventCollector from VtableStubs::find_stub + Thread t = new Thread(() -> { + changeEventNotificationMode(); + }); + t.setDaemon(true); + t.start(); + + for (int i = 0; i < 2000; i++) { + new Thread(() -> { + String result = "string" + System.currentTimeMillis(); + + // Keep a reference to result + if (result.hashCode() == System.currentTimeMillis()) { + // Shouldn't happen + return; + } + }).start(); + } + } +} diff --git a/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.sh b/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.sh new file mode 100644 index 00000000000..4017d3e7044 --- /dev/null +++ b/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +# Copyright (c) 2012, 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. + +# @test DynamicCodeGeneratedTest.sh +# @bug 8212155 +# @summary Test concurrent enabling and posting of DynamicCodeGenerated events. +# @run shell DynamicCodeGeneratedTest.sh + +if [ "$TESTSRC" = "" ] +then TESTSRC=. +fi + +if [ "$TESTJAVA" = "" ] +then + PARENT=$(dirname $(which java)) + TESTJAVA=$(dirname $PARENT) + echo "TESTJAVA not set, selecting " $TESTJAVA + echo "If this is incorrect, try setting the variable manually." +fi + +# set platform-dependent variables +OS=$(uname -s) +case "$OS" in + Linux ) + ARCHFLAG= + $TESTJAVA/bin/java -version 2>&1 | grep '64-Bit' > /dev/null + if [ $? -eq '0' ] + then + ARCH="amd64" + else + ARCH="i386" + ARCHFLAG="-m32 -march=i386" + fi + ;; + * ) + echo "Test passed, unrecognized system." + exit 0; + ;; +esac + +echo "OS-ARCH is" linux-$ARCH +$TESTJAVA/jre/bin/java -fullversion 2>&1 + +which gcc >/dev/null 2>&1 +if [ "$?" -ne '0' ] +then + echo "No C compiler found. Test passed." + exit 0 +fi + +JAVA=$TESTJAVA/jre/bin/java +JAVAC=$TESTJAVA/bin/javac +JAVAH=$TESTJAVA/bin/javah + +$JAVAC -d . $TESTSRC/DynamicCodeGenerated.java +$JAVAH -jni -classpath . -d . DynamicCodeGenerated + +gcc --shared $ARCHFLAG -fPIC -O -I$TESTJAVA/include -I$TESTJAVA/include/linux -I. -o libDynamicCodeGenerated.so $TESTSRC/libDynamicCodeGenerated.cpp + +LD_LIBRARY_PATH=. $JAVA -classpath . -agentlib:DynamicCodeGenerated DynamicCodeGenerated + +exit $? diff --git a/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp b/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp new file mode 100644 index 00000000000..7cef753c02c --- /dev/null +++ b/hotspot/test/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, 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 +#include + +static jvmtiEnv* jvmti = NULL; + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT +void JNICALL Java_DynamicCodeGenerated_changeEventNotificationMode(JNIEnv* jni, jclass cls) { + while (true) { + jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL); + jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL); + } +} + +#ifdef __cplusplus +} +#endif + +void JNICALL DynamicCodeGenerated(jvmtiEnv* jvmti, const char* name, const void* address, jint length) { + +} + +jint Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { + vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0); + jvmtiEventCallbacks callbacks; + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.DynamicCodeGenerated = DynamicCodeGenerated; + jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); + + return 0; +}