From ebb1d4b7450c9cb7f02c3ea77f4bc9d82e68d31f Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 24 May 2023 17:46:46 +0200 Subject: [PATCH 1/3] Basic JVMTI infrastructure. --- .../com/oracle/svm/core/SubstrateOptions.java | 13 + .../graal/snippets/CEntryPointSnippets.java | 10 + .../jni/functions/JNIInvocationInterface.java | 20 +- .../core/jni/headers/JNIFieldIdPointer.java | 32 + .../jni/headers/JNIFieldIdPointerPointer.java | 32 + .../core/jni/headers/JNIMethodIdPointer.java | 32 + .../headers/JNIMethodIdPointerPointer.java | 32 + .../headers/JNINativeInterfacePointer.java | 32 + .../oracle/svm/core/jvmti/JvmtiAgents.java | 181 +++ .../svm/core/jvmti/JvmtiCapabilitiesUtil.java | 60 + .../com/oracle/svm/core/jvmti/JvmtiEnv.java | 57 + .../oracle/svm/core/jvmti/JvmtiEnvUtil.java | 229 +++ .../svm/core/jvmti/JvmtiFunctionTable.java | 88 ++ .../oracle/svm/core/jvmti/JvmtiFunctions.java | 1356 +++++++++++++++++ .../oracle/svm/core/jvmti/headers/JClass.java | 30 + .../svm/core/jvmti/headers/JClassPointer.java | 30 + .../jvmti/headers/JClassPointerPointer.java | 30 + .../jvmti/headers/JNIObjectHandlePointer.java | 30 + .../JNIObjectHandlePointerPointer.java | 30 + .../svm/core/jvmti/headers/JRawMonitorId.java | 34 + .../jvmti/headers/JRawMonitorIdPointer.java | 32 + .../svm/core/jvmti/headers/JThread.java | 30 + .../svm/core/jvmti/headers/JThreadGroup.java | 30 + .../jvmti/headers/JThreadGroupPointer.java | 30 + .../core/jvmti/headers/JThreadPointer.java | 30 + .../jvmti/headers/JThreadPointerPointer.java | 30 + .../core/jvmti/headers/JvmtiCapabilities.java | 304 ++++ .../jvmti/headers/JvmtiClassDefinition.java | 34 + .../core/jvmti/headers/JvmtiDirectives.java | 56 + .../svm/core/jvmti/headers/JvmtiError.java | 99 ++ .../core/jvmti/headers/JvmtiErrorPointer.java | 30 + .../svm/core/jvmti/headers/JvmtiEvent.java | 91 ++ .../jvmti/headers/JvmtiEventCallbacks.java | 174 +++ .../core/jvmti/headers/JvmtiEventMode.java | 37 + .../headers/JvmtiExtensionFunctionInfo.java | 34 + .../JvmtiExtensionFunctionInfoPointer.java | 32 + .../core/jvmti/headers/JvmtiExternalEnv.java | 40 + .../core/jvmti/headers/JvmtiFrameInfo.java | 34 + .../jvmti/headers/JvmtiHeapCallbacks.java | 34 + .../headers/JvmtiHeapObjectCallback.java | 35 + .../jvmti/headers/JvmtiHeapObjectFilter.java | 40 + .../jvmti/headers/JvmtiHeapRootCallback.java | 35 + .../core/jvmti/headers/JvmtiHeapRootKind.java | 52 + .../core/jvmti/headers/JvmtiInterface.java | 954 ++++++++++++ .../jvmti/headers/JvmtiIterationControl.java | 40 + .../jvmti/headers/JvmtiLineNumberEntry.java | 34 + .../headers/JvmtiLineNumberEntryPointer.java | 32 + .../headers/JvmtiLocalVariableEntry.java | 34 + .../JvmtiLocalVariableEntryPointer.java | 32 + .../headers/JvmtiMonitorStackDepthInfo.java | 34 + .../JvmtiMonitorStackDepthInfoPointer.java | 32 + .../core/jvmti/headers/JvmtiMonitorUsage.java | 34 + .../headers/JvmtiObjectReferenceCallback.java | 35 + .../headers/JvmtiObjectReferenceKind.java | 58 + .../svm/core/jvmti/headers/JvmtiPhase.java | 46 + .../core/jvmti/headers/JvmtiStackInfo.java | 34 + .../jvmti/headers/JvmtiStackInfoPointer.java | 32 + .../headers/JvmtiStackReferenceCallback.java | 37 + .../headers/JvmtiStartFunctionPointer.java | 36 + .../jvmti/headers/JvmtiThreadGroupInfo.java | 34 + .../core/jvmti/headers/JvmtiThreadInfo.java | 34 + .../core/jvmti/headers/JvmtiTimerInfo.java | 34 + .../core/jvmti/headers/JvmtiVerboseFlag.java | 43 + .../svm/core/jvmti/headers/JvmtiVersion.java | 87 ++ .../UninterruptibleAnnotationChecker.java | 3 +- .../oracle/svm/hosted/jvmti/JvmtiFeature.java | 133 ++ 66 files changed, 5565 insertions(+), 8 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClass.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorId.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThread.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroup.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiCapabilities.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiClassDefinition.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiErrorPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExternalEnv.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapCallbacks.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectCallback.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootCallback.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiInterface.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntry.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntry.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorUsage.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceCallback.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackReferenceCallback.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStartFunctionPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiTimerInfo.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVersion.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index b1f9188e7127..53134aa8b445 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -631,6 +631,19 @@ public static void updateMaxJavaStackTraceDepth(EconomicMap, Object @Option(help = "JNI functions will return more specific error codes.", type = OptionType.User)// public static final HostedOptionKey JNIEnhancedErrorCodes = new HostedOptionKey<>(false); + @Option(help = "Enable JVM Tool Interface (JVMTI) support.", type = OptionType.User)// + public static final HostedOptionKey JVMTI = new HostedOptionKey<>(false); + + // TEMP (chaeubl): we need to support multiple values + @Option(help = "Loads the specified native agent library specified by the absolute path name. " + + "After the library path, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// + public static final RuntimeOptionKey AgentPath = new RuntimeOptionKey<>(null); + + // TEMP (chaeubl): we need to support multiple values + @Option(help = "Loads the specified native agent library. " + + "After the library name, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// + public static final RuntimeOptionKey AgentLib = new RuntimeOptionKey<>(null); + @Option(help = "Alignment of AOT and JIT compiled code in bytes.")// public static final HostedOptionKey CodeAlignment = new HostedOptionKey<>(16); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 7a8e3873251c..36d1b21669d5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -77,6 +77,7 @@ import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; import com.oracle.svm.core.jdk.RuntimeSupport; +import com.oracle.svm.core.jvmti.JvmtiAgents; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionParser; import com.oracle.svm.core.os.CommittedMemoryProvider; @@ -396,6 +397,10 @@ private static int initializeIsolateInterruptibly1(CEntryPointCreateIsolateParam /* Adjust stack overflow boundary of main thread. */ StackOverflowCheck.singleton().updateStackOverflowBoundary(); + if (SubstrateOptions.JVMTI.getValue()) { + JvmtiAgents.singleton().load(); + } + assert !isolateInitialized; isolateInitialized = true; @@ -626,6 +631,11 @@ private static boolean initiateTearDownIsolateInterruptibly() { } VMThreads.singleton().threadExit(); + + if (SubstrateOptions.JVMTI.getValue()) { + JvmtiAgents.singleton().unload(); + } + return true; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java index 34c9edf3a595..6bd7e7553097 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java @@ -68,6 +68,8 @@ import com.oracle.svm.core.jni.headers.JNIJavaVMOption; import com.oracle.svm.core.jni.headers.JNIJavaVMPointer; import com.oracle.svm.core.jni.headers.JNIVersion; +import com.oracle.svm.core.jvmti.JvmtiEnvUtil; +import com.oracle.svm.core.jvmti.headers.JvmtiVersion; import com.oracle.svm.core.log.FunctionPointerLogHandler; import com.oracle.svm.core.memory.UntrackedNullableNativeMemory; import com.oracle.svm.core.monitor.MonitorInflationCause; @@ -291,8 +293,16 @@ static int DestroyJavaVM(JNIJavaVM vm) { @CEntryPointOptions(prologue = JNIGetEnvPrologue.class) @SuppressWarnings("unused") static int GetEnv(JNIJavaVM vm, WordPointer env, int version) { - env.write(JNIThreadLocalEnvironment.getAddress()); - return JNIErrors.JNI_OK(); + if (SubstrateOptions.JVMTI.getValue() && JvmtiVersion.isSupported(version)) { + env.write(JvmtiEnvUtil.allocate()); + return JNIErrors.JNI_OK(); + } else if (JNIVersion.isSupported(version, false)) { + env.write(JNIThreadLocalEnvironment.getAddress()); + return JNIErrors.JNI_OK(); + } else { + env.write(WordFactory.nullPointer()); + return JNIErrors.JNI_EVERSION(); + } } // Checkstyle: resume @@ -308,14 +318,10 @@ static class Support { static class JNIGetEnvPrologue implements CEntryPointOptions.Prologue { @Uninterruptible(reason = "prologue") - static int enter(JNIJavaVM vm, WordPointer env, int version) { + static int enter(JNIJavaVM vm, WordPointer env) { if (vm.isNull() || env.isNull()) { return JNIErrors.JNI_ERR(); } - if (!JNIVersion.isSupported(version, false)) { - env.write(WordFactory.nullPointer()); - return JNIErrors.JNI_EVERSION(); - } if (!CEntryPointActions.isCurrentThreadAttachedTo(vm.getFunctions().getIsolate())) { env.write(WordFactory.nullPointer()); return JNIErrors.JNI_EDETACHED(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java new file mode 100644 index 000000000000..4ed4746e9c83 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jni.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JNIFieldId.class) +public interface JNIFieldIdPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java new file mode 100644 index 000000000000..1a7207ae89da --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jni.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JNIFieldIdPointer.class) +public interface JNIFieldIdPointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java new file mode 100644 index 000000000000..075753c6f1a1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jni.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JNIMethodId.class) +public interface JNIMethodIdPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java new file mode 100644 index 000000000000..cff446f527bb --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jni.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JNIMethodIdPointer.class) +public interface JNIMethodIdPointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java new file mode 100644 index 000000000000..7835ca8b4230 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jni.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JNINativeInterface.class) +public interface JNINativeInterfacePointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java new file mode 100644 index 000000000000..d265451b2436 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import java.io.File; +import java.io.IOException; +import java.io.Serial; +import java.util.ArrayList; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.CTypeConversion; +import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.jdk.NativeLibrarySupport; +import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; +import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport.NativeLibrary; +import com.oracle.svm.core.jni.functions.JNIFunctionTables; +import com.oracle.svm.core.jni.headers.JNIJavaVM; +import com.oracle.svm.core.log.Log; +import com.oracle.svm.util.StringUtil; + +public class JvmtiAgents { + private static final String AGENT_ON_LOAD = "Agent_OnLoad"; + private static final String AGENT_ON_UNLOAD = "Agent_OnUnload"; + + private final ArrayList agents = new ArrayList<>(); + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiAgents() { + } + + @Fold + public static JvmtiAgents singleton() { + return ImageSingletons.lookup(JvmtiAgents.class); + } + + // TEMP (chaeubl): we could call `Agent_OnAttach` instead - would be closer in terms of the + // semantics. + public void load() { + String agentLib = SubstrateOptions.AgentLib.getValue(); + if (agentLib != null) { + loadAgent(agentLib, true); + } + + String agentPath = SubstrateOptions.AgentPath.getValue(); + if (agentPath != null) { + loadAgent(agentPath, false); + } + } + + public void unload() { + for (NativeLibrary lib : agents) { + PointerBase function = lib.findSymbol(AGENT_ON_UNLOAD); + if (function.isNonNull()) { + callOnUnLoadFunction(function); + } + } + agents.clear(); + } + + private void loadAgent(String agentAndOptions, boolean relative) { + try { + loadAgent0(agentAndOptions, relative); + } catch (AgentInitException e) { + Log.log().string(e.getMessage()).newline(); + if (!SubstrateOptions.SharedLibrary.getValue()) { + System.exit(1); + } + } + } + + private void loadAgent0(String agentAndOptions, boolean relative) { + String[] values = StringUtil.split(agentAndOptions, "=", 2); + String agent = values[0]; + String options = values.length > 1 ? values[1] : null; + + String agentFile = getAgentFile(agent, relative); + NativeLibrary lib = PlatformNativeLibrarySupport.singleton().createLibrary(agentFile, false); + if (!lib.load()) { + throw new AgentInitException("Could not load agent library '" + agentFile + "'."); + } + + PointerBase function = lib.findSymbol(AGENT_ON_LOAD); + if (function.isNull()) { + throw new AgentInitException("Could not find Agent_OnLoad function in agent library '" + agentFile + "'."); + } + + if (!callOnLoadFunction(function, options)) { + throw new AgentInitException("Initialization of agent library '" + agentFile + "' failed."); + } + agents.add(lib); + } + + private static String getAgentFile(String agent, boolean relative) { + File file; + if (relative) { + String sysPath = NativeLibrarySupport.getImageDirectory(); + String libname = System.mapLibraryName(agent); + file = new File(sysPath, libname); + if (!file.exists()) { + // TEMP (chaeubl): is this really accurate? What if someone uses a custom + // LD_LIBRARY_PATH? + throw new AgentInitException("Could not find agent library '" + agent + "' on the library path."); + } + } else { + file = new File(agent); + if (!file.exists()) { + throw new AgentInitException("Could not find agent library '" + agent + "'."); + } + } + + try { + return file.getCanonicalPath(); + } catch (IOException e) { + throw new AgentInitException("Path of agent library '" + agent + "' is invalid: " + e.getMessage()); + } + } + + private static boolean callOnLoadFunction(PointerBase function, String options) { + JvmtiOnLoadFunctionPointer onLoad = (JvmtiOnLoadFunctionPointer) function; + try (CTypeConversion.CCharPointerHolder holder = CTypeConversion.toCString(options)) { + int result = onLoad.invoke(JNIFunctionTables.singleton().getGlobalJavaVM(), holder.get(), WordFactory.nullPointer()); + /* Any value other than 0 is an error. */ + return result == 0; + } + } + + private static void callOnUnLoadFunction(PointerBase function) { + JvmtiOnUnLoadFunctionPointer onLoad = (JvmtiOnUnLoadFunctionPointer) function; + onLoad.invoke(JNIFunctionTables.singleton().getGlobalJavaVM(), WordFactory.nullPointer()); + } + + private static class AgentInitException extends RuntimeException { + @Serial private static final long serialVersionUID = 3111979452718981714L; + + AgentInitException(String message) { + super(message); + } + } +} + +interface JvmtiOnLoadFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JNIJavaVM vm, CCharPointer options, VoidPointer reserved); +} + +interface JvmtiOnUnLoadFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + void invoke(JNIJavaVM vm, VoidPointer reserved); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java new file mode 100644 index 000000000000..feedc76632cc --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.word.Pointer; + +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.jvmti.headers.JvmtiCapabilities; + +public final class JvmtiCapabilitiesUtil { + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiCapabilitiesUtil() { + } + + public static boolean hasAny(JvmtiCapabilities capabilities) { + assert capabilities.isNonNull(); + + Pointer rawData = (Pointer) capabilities; + for (int i = 0; i < SizeOf.get(JvmtiCapabilities.class); i++) { + if (rawData.readByte(i) != 0) { + return true; + } + } + return false; + } + + public static void clear(JvmtiCapabilities capabilities) { + assert capabilities.isNonNull(); + UnmanagedMemoryUtil.fill((Pointer) capabilities, SizeOf.unsigned(JvmtiCapabilities.class), (byte) 0); + } + + public static void copy(JvmtiCapabilities src, JvmtiCapabilities dst) { + UnmanagedMemoryUtil.copyForward((Pointer) src, (Pointer) dst, SizeOf.unsigned(JvmtiCapabilities.class)); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java new file mode 100644 index 000000000000..a2669fa33176 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.Isolate; +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.word.PointerBase; + +@RawStructure +public interface JvmtiEnv extends PointerBase { + @RawField + Isolate getIsolate(); + + @RawField + void setIsolate(Isolate value); + + @RawField + int getMagic(); + + @RawField + void setMagic(int value); + + // The annotation-based fields above are incomplete because we directly embed other structures + // into this raw struct, see below: + // + // Internal data + // ------------- + // JvmtiCapabilities capabilities; + // JvmtiEventCallbacks callbacks; + // + // Externally visible data (must be at the end of this struct) + // ----------------------------------------------------------- + // JvmtiExternalEnv externalEnv; +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java new file mode 100644 index 000000000000..c1b683d12bc0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NONE; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NOT_AVAILABLE; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.nativeimage.CurrentIsolate; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Isolate; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.jvmti.headers.JvmtiCapabilities; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiEvent; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; +import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; +import com.oracle.svm.core.jvmti.headers.JvmtiInterface; + +public final class JvmtiEnvUtil { + private static final int VALID_ENV_MAGIC = 0x71EE; + private static final int DISPOSED_ENV_MAGIC = 0xDEFC; + + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiEnvUtil() { + } + + public static JvmtiExternalEnv allocate() { + JvmtiInterface functionTable = JvmtiFunctionTable.allocateFunctionTable(); + if (functionTable.isNull()) { + return WordFactory.nullPointer(); + } + + JvmtiEnv env = ImageSingletons.lookup(UnmanagedMemorySupport.class).calloc(WordFactory.unsigned(internalEnvSize())); + if (env.isNull()) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(functionTable); + return WordFactory.nullPointer(); + } + + env.setIsolate(CurrentIsolate.getIsolate()); + env.setMagic(VALID_ENV_MAGIC); + + JvmtiExternalEnv externalEnv = toExternal(env); + externalEnv.setFunctions(functionTable); + return externalEnv; + } + + /* + * Note that HotSpot doesn't necessarily free the environment right away to prevent certain + * races. Depending on the functionality that we are going to add to our JVMTI implementation, + * we might need the same approach. + */ + public static void free(JvmtiEnv env) { + env.setMagic(DISPOSED_ENV_MAGIC); + + JvmtiCapabilities capabilities = getCapabilities(env); + relinquishCapabilities(env, capabilities); + + JvmtiExternalEnv externalEnv = toExternal(env); + JvmtiFunctionTable.freeFunctionTable(externalEnv.getFunctions()); + externalEnv.setFunctions(WordFactory.nullPointer()); + + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(env); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static JvmtiEnv toInternal(JvmtiExternalEnv externalEnv) { + assert externalEnv.isNonNull(); + return (JvmtiEnv) ((Pointer) externalEnv).subtract(externalEnvOffset()); + } + + private static JvmtiExternalEnv toExternal(JvmtiEnv env) { + assert env.isNonNull(); + return (JvmtiExternalEnv) ((Pointer) env).add(externalEnvOffset()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static boolean isValid(JvmtiEnv env) { + assert env.isNonNull(); + return env.getMagic() == VALID_ENV_MAGIC; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static Isolate getIsolate(JvmtiEnv env) { + assert isValid(env); + return env.getIsolate(); + } + + public static JvmtiCapabilities getCapabilities(JvmtiEnv env) { + assert isValid(env); + return addOffset(env, capabilitiesOffset()); + } + + public static JvmtiError addCapabilities(JvmtiEnv env, JvmtiCapabilities capabilities) { + assert capabilities.isNonNull(); + /* We don't support any capabilities at the moment. */ + if (JvmtiCapabilitiesUtil.hasAny(capabilities)) { + return JVMTI_ERROR_NOT_AVAILABLE; + } + return JVMTI_ERROR_NONE; + } + + public static JvmtiError relinquishCapabilities(JvmtiEnv env, JvmtiCapabilities capabilities) { + assert capabilities.isNonNull(); + /* Nothing to do because we don't support any capabilities at the moment. */ + return JVMTI_ERROR_NONE; + } + + public static JvmtiEventCallbacks getEventCallbacks(JvmtiEnv env) { + assert isValid(env); + return addOffset(env, eventCallbacksOffset()); + } + + public static void setEventCallbacks(JvmtiEnv env, JvmtiEventCallbacks newCallbacks, int sizeOfCallbacks) { + /* + * int internalStructSize = SizeOf.get(JvmtiEventCallbacks.class); // Clear the whole struct + * (including gaps). JvmtiEventCallbacks envEventCallbacks = getEventCallbacks(env); + * UnmanagedMemoryUtil.fill((Pointer) envEventCallbacks, + * WordFactory.unsigned(internalStructSize), (byte) 0); + * + * if (newCallbacks.isNonNull()) { int bytesToCopy = + * UninterruptibleUtils.Math.min(internalStructSize, sizeOfCallbacks); + * UnmanagedMemoryUtil.copy((Pointer) newCallbacks, (Pointer) envEventCallbacks, + * WordFactory.unsigned(bytesToCopy)); } + * + * jlong enabled_bits = env->env_event_enable()->_event_callback_enabled.get_bits(); for + * (int ei = JVMTI_MIN_EVENT_TYPE_VAL; ei <= JVMTI_MAX_EVENT_TYPE_VAL; ++ei) { jvmtiEvent + * evt_t = (jvmtiEvent)ei; jlong bit_for = JvmtiEventEnabled::bit_for(evt_t); if + * (env->has_callback(evt_t)) { enabled_bits |= bit_for; } else { enabled_bits &= ~bit_for; + * } } env->env_event_enable()->_event_callback_enabled.set_bits(enabled_bits); + * recomputeEnabled(); + */ + } + + /* + * Compute truly enabled events - meaning if the event can and could be sent. + * + * An event is truly enabled if it is user enabled on the thread or globally user enabled, but + * only if there is a callback or event hook for it and, for field watch and frame pop, one has + * been set. Compute if truly enabled, per thread, per environment, per combination (thread x + * environment), and overall. These merges are true if any is true. True per thread if some + * environment has callback set and the event is globally enabled or enabled for this thread. + * True per environment if the callback is set and the event is globally enabled in this + * environment or enabled for any thread in this environment. True per combination if the + * environment has the callback set and the event is globally enabled in this environment or the + * event is enabled for this thread and environment. + * + * All states transitions dependent on these transitions are also handled here. + */ + private static void recomputeEnabled() { + + } + + @SuppressWarnings("unchecked") + private static T addOffset(JvmtiEnv env, int offset) { + return (T) ((Pointer) env).add(offset); + } + + public static boolean hasEventCapability(JvmtiEnv env, JvmtiEvent eventInfo) { + /* At the moment, we only support events that don't need any specific capabilities. */ + return true; + } + + @Fold + static int capabilitiesOffset() { + return NumUtil.roundUp(SizeOf.get(JvmtiEnv.class), ConfigurationValues.getTarget().wordSize); + } + + @Fold + static int eventCallbacksOffset() { + return NumUtil.roundUp(capabilitiesOffset() + SizeOf.get(JvmtiCapabilities.class), ConfigurationValues.getTarget().wordSize); + } + + @Fold + static int externalEnvOffset() { + return NumUtil.roundUp(eventCallbacksOffset() + SizeOf.get(JvmtiEventCallbacks.class), ConfigurationValues.getTarget().wordSize); + } + + @Fold + static int internalEnvSize() { + return externalEnvOffset() + SizeOf.get(JvmtiExternalEnv.class); + } + + public static void setEventUserEnabled(JvmtiEnv env, Thread javaEventThread, JvmtiEvent eventType, boolean value) { + // TEMP (chaeubl): implement + /* + * if (thread == null && thread_oop_h() == nullptr) { // Null thread and null thread_oop now + * indicate setting globally instead of setting thread specific since null thread by itself + * means an unmounted virtual thread. env->env_event_enable()->set_user_enabled(event_type, + * enabled); } else { // create the thread state (if it didn't exist before) + * JvmtiThreadState *state = JvmtiThreadState::state_for_while_locked(thread, + * thread_oop_h()); if (state != nullptr) { + * state->env_thread_state(env)->event_enable()->set_user_enabled(event_type, enabled); } } + * recompute_enabled(); + */ + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java new file mode 100644 index 000000000000..a9470d02f7d7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.c.NonmovableArray; +import com.oracle.svm.core.c.NonmovableArrays; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.jvmti.headers.JvmtiInterface; + +public final class JvmtiFunctionTable { + private final CFunctionPointer[] readOnlyFunctionTable; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiFunctionTable() { + int length = bytesToWords(SizeOf.get(JvmtiInterface.class)); + readOnlyFunctionTable = new CFunctionPointer[length]; + } + + @Fold + public static JvmtiFunctionTable singleton() { + return ImageSingletons.lookup(JvmtiFunctionTable.class); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public void init(int offsetInBytes, CFunctionPointer functionPointer) { + int index = bytesToWords(offsetInBytes); + readOnlyFunctionTable[index] = functionPointer; + } + + @Platforms(Platform.HOSTED_ONLY.class) + private static int bytesToWords(int bytes) { + assert bytes % ConfigurationValues.getTarget().wordSize == 0; + return bytes / ConfigurationValues.getTarget().wordSize; + } + + @Platforms(Platform.HOSTED_ONLY.class) + public CFunctionPointer[] getReadOnlyFunctionTable() { + return readOnlyFunctionTable; + } + + public static JvmtiInterface allocateFunctionTable() { + UnsignedWord size = SizeOf.unsigned(JvmtiInterface.class); + JvmtiInterface result = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(size); + if (result.isNonNull()) { + NonmovableArray readOnlyData = NonmovableArrays.fromImageHeap(singleton().readOnlyFunctionTable); + assert size.equal(NonmovableArrays.lengthOf(readOnlyData) * ConfigurationValues.getTarget().wordSize); + UnmanagedMemoryUtil.copyForward(NonmovableArrays.getArrayBase(readOnlyData), (Pointer) result, size); + } + return result; + } + + public static void freeFunctionTable(JvmtiInterface table) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(table); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java new file mode 100644 index 000000000000..56ecb40f3ebd --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java @@ -0,0 +1,1356 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_ACCESS_DENIED; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_ILLEGAL_ARGUMENT; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_INTERNAL; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_INVALID_ENVIRONMENT; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_INVALID_EVENT_TYPE; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_MUST_POSSESS_CAPABILITY; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NONE; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NULL_POINTER; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_UNATTACHED_THREAD; + +import java.nio.charset.StandardCharsets; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.CCharPointerPointer; +import org.graalvm.nativeimage.c.type.CConst; +import org.graalvm.nativeimage.c.type.CDoublePointer; +import org.graalvm.nativeimage.c.type.CFloatPointer; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.nativeimage.c.type.CTypeConversion; +import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.PointerBase; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.function.CEntryPointActions; +import com.oracle.svm.core.c.function.CEntryPointErrors; +import com.oracle.svm.core.c.function.CEntryPointOptions; +import com.oracle.svm.core.heap.GCCause; +import com.oracle.svm.core.heap.Heap; +import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.headers.JNIFieldId; +import com.oracle.svm.core.jni.headers.JNIFieldIdPointerPointer; +import com.oracle.svm.core.jni.headers.JNIMethodId; +import com.oracle.svm.core.jni.headers.JNIMethodIdPointer; +import com.oracle.svm.core.jni.headers.JNIMethodIdPointerPointer; +import com.oracle.svm.core.jni.headers.JNINativeInterface; +import com.oracle.svm.core.jni.headers.JNINativeInterfacePointer; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.JClass; +import com.oracle.svm.core.jvmti.headers.JClassPointer; +import com.oracle.svm.core.jvmti.headers.JClassPointerPointer; +import com.oracle.svm.core.jvmti.headers.JNIObjectHandlePointer; +import com.oracle.svm.core.jvmti.headers.JNIObjectHandlePointerPointer; +import com.oracle.svm.core.jvmti.headers.JRawMonitorId; +import com.oracle.svm.core.jvmti.headers.JRawMonitorIdPointer; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JThreadGroup; +import com.oracle.svm.core.jvmti.headers.JThreadGroupPointer; +import com.oracle.svm.core.jvmti.headers.JThreadPointer; +import com.oracle.svm.core.jvmti.headers.JThreadPointerPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiCapabilities; +import com.oracle.svm.core.jvmti.headers.JvmtiClassDefinition; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiErrorPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiEvent; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; +import com.oracle.svm.core.jvmti.headers.JvmtiEventMode; +import com.oracle.svm.core.jvmti.headers.JvmtiExtensionFunctionInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiHeapCallbacks; +import com.oracle.svm.core.jvmti.headers.JvmtiHeapObjectCallback; +import com.oracle.svm.core.jvmti.headers.JvmtiHeapRootCallback; +import com.oracle.svm.core.jvmti.headers.JvmtiLineNumberEntryPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiLocalVariableEntryPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiMonitorStackDepthInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiMonitorUsage; +import com.oracle.svm.core.jvmti.headers.JvmtiObjectReferenceCallback; +import com.oracle.svm.core.jvmti.headers.JvmtiPhase; +import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiStackReferenceCallback; +import com.oracle.svm.core.jvmti.headers.JvmtiStartFunctionPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiThreadGroupInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiThreadInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiTimerInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiVersion; + +/** + * Defines all JVMTI functions. This class may only contain methods that are annotated with + * {@link CEntryPoint}. + * + * JVMTI functions are annotated with {@link RestrictHeapAccess} because they must not execute any + * code that could trigger JVMTI events (could result in endless recursion). + *
    + *
  • they must not trigger (potentially recursive) JVMTI events
  • + *
  • they may be called from certain JVMTI event callbacks where we can't execute normal Java code + * (e.g., out of Java heap memory)
  • + *
+ */ + +// TEMP (chaeubl): +// - Do we need to be uninterruptible? No, because some operations may cause a safepoint. +// - Can we allocate Java heap memory? No, because some operations are called from places where +// allocations are disallowed (e.g., JVMTI_EVENT_RESOURCE_EXHAUSTED). +// - Is Java synchronization allow? No. + +// TEMP (chaeubl): this still doesn't work... +// - JVMTI_EVENT_EXCEPTION and JVMTI_EVENT_EXCEPTION_CATCH - eventually, this code would have to be +// uninterruptible so that exceptions don't break uninterruptible code. But we can't trigger events +// from uninterruptible code... -> we would need to know if uninterruptible code is currently +// running and only trigger the JVMTI event in certain cases? Or we would need to exclude +// SVM-internal code? +// - JVMTI_EVENT_RESOURCE_EXHAUSTED: a lot of JVMTI/JNI code can be triggered, which is problematic +// because we must not allocate any Java heap memory. +public final class JvmtiFunctions { + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiFunctions() { + } + + // Checkstyle: stop: MethodName + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int Allocate(JvmtiExternalEnv externalEnv, long size, CCharPointerPointer memPtr) { + if (size < 0) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + if (size == 0) { + memPtr.write(WordFactory.nullPointer()); + } else { + CCharPointer mem = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(size)); + memPtr.write(mem); + if (mem.isNull()) { + return JVMTI_ERROR_OUT_OF_MEMORY.getCValue(); + } + } + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int Deallocate(JvmtiExternalEnv externalEnv, CCharPointer mem) { + if (mem.isNonNull()) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(mem); + } + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadState(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer threadStatePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetCurrentThread(JvmtiExternalEnv externalEnv, JThreadPointer threadPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetAllThreads(JvmtiExternalEnv externalEnv, CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SuspendThread(JvmtiExternalEnv externalEnv, JThread thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SuspendThreadList(JvmtiExternalEnv externalEnv, int requestCount, @CConst JThreadPointer requestList, JvmtiErrorPointer results) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SuspendAllVirtualThreads(JvmtiExternalEnv externalEnv, int exceptCount, @CConst JThreadPointer exceptList) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ResumeThread(JvmtiExternalEnv externalEnv, JThread thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ResumeThreadList(JvmtiExternalEnv externalEnv, int requestCount, @CConst JThreadPointer requestList, JvmtiErrorPointer results) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ResumeAllVirtualThreads(JvmtiExternalEnv externalEnv, int exceptCount, @CConst JThreadPointer exceptList) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int StopThread(JvmtiExternalEnv externalEnv, JThread thread, JNIObjectHandle exception) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int InterruptThread(JvmtiExternalEnv externalEnv, JThread thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadInfo(JvmtiExternalEnv externalEnv, JThread thread, JvmtiThreadInfo infoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetOwnedMonitorInfo(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer ownedMonitorCountPtr, JNIObjectHandlePointerPointer ownedMonitorsPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetOwnedMonitorStackDepthInfo(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer monitorInfoCountPtr, JvmtiMonitorStackDepthInfoPointer monitorInfoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetCurrentContendedMonitor(JvmtiExternalEnv externalEnv, JThread thread, JNIObjectHandlePointer monitorPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RunAgentThread(JvmtiExternalEnv externalEnv, JThread thread, JvmtiStartFunctionPointer proc, @CConst VoidPointer arg, int priority) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetThreadLocalStorage(JvmtiExternalEnv externalEnv, JThread thread, @CConst VoidPointer data) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadLocalStorage(JvmtiExternalEnv externalEnv, JThread thread, VoidPointerPointer dataPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetTopThreadGroups(JvmtiExternalEnv externalEnv, CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadGroupInfo(JvmtiExternalEnv externalEnv, JThreadGroup group, JvmtiThreadGroupInfo infoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadGroupChildren(JvmtiExternalEnv externalEnv, JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, CIntPointer groupCountPtr, + JThreadGroupPointer groupsPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetStackTrace(JvmtiExternalEnv externalEnv, JThread thread, int startDepth, int maxFrameCount, JvmtiFrameInfo frameBuffer, CIntPointer countPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetAllStackTraces(JvmtiExternalEnv externalEnv, int maxFrameCount, JvmtiStackInfoPointer stackInfoPtr, CIntPointer threadCountPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadListStackTraces(JvmtiExternalEnv externalEnv, int threadCount, @CConst JThreadPointer threadList, int maxFrameCount, JvmtiStackInfoPointer stackInfoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetFrameCount(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer countPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int PopFrame(JvmtiExternalEnv externalEnv, JThread thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetFrameLocation(JvmtiExternalEnv externalEnv, JThread thread, int depth, JNIMethodIdPointer methodPtr, CLongPointer locationPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int NotifyFramePop(JvmtiExternalEnv externalEnv, JThread thread, int depth) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceEarlyReturnObject(JvmtiExternalEnv externalEnv, JThread thread, JNIObjectHandle value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceEarlyReturnInt(JvmtiExternalEnv externalEnv, JThread thread, int value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceEarlyReturnLong(JvmtiExternalEnv externalEnv, JThread thread, long value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceEarlyReturnFloat(JvmtiExternalEnv externalEnv, JThread thread, float value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceEarlyReturnDouble(JvmtiExternalEnv externalEnv, JThread thread, double value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceEarlyReturnVoid(JvmtiExternalEnv externalEnv, JThread thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int FollowReferences(JvmtiExternalEnv externalEnv, int heapFilter, JClass klass, JNIObjectHandle initialObject, @CConst JvmtiHeapCallbacks callbacks, @CConst VoidPointer userData) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IterateThroughHeap(JvmtiExternalEnv externalEnv, int heapFilter, JClass klass, @CConst JvmtiHeapCallbacks callbacks, @CConst VoidPointer userData) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetTag(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CLongPointer tagPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetTag(JvmtiExternalEnv externalEnv, JNIObjectHandle object, long tag) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetObjectsWithTags(JvmtiExternalEnv externalEnv, int tagCount, @CConst CLongPointer tags, CIntPointer countPtr, JNIObjectHandlePointerPointer objectResultPtr, + CLongPointerPointer tagResultPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ForceGarbageCollection(JvmtiExternalEnv externalEnv) { + Heap.getHeap().getGC().collectCompletely(GCCause.JvmtiForceGC); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IterateOverObjectsReachableFromObject(JvmtiExternalEnv externalEnv, JNIObjectHandle object, JvmtiObjectReferenceCallback objectReferenceCallback, @CConst VoidPointer userData) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IterateOverReachableObjects(JvmtiExternalEnv externalEnv, JvmtiHeapRootCallback heapRootCallback, JvmtiStackReferenceCallback stackRefCallback, + JvmtiObjectReferenceCallback objectRefCallback, + @CConst VoidPointer userData) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IterateOverHeap(JvmtiExternalEnv externalEnv, int heapObjectFilter, JvmtiHeapObjectCallback heapObjectCallback, @CConst VoidPointer userData) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IterateOverInstancesOfClass(JvmtiExternalEnv externalEnv, JClass klass, int heapObjectFilter, JvmtiHeapObjectCallback heapObjectCallback, + @CConst VoidPointer userData) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalObject(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, JNIObjectHandlePointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalInstance(JvmtiExternalEnv externalEnv, JThread thread, int depth, JNIObjectHandlePointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalInt(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, CIntPointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalLong(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, CLongPointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalFloat(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, CFloatPointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalDouble(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, CDoublePointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetLocalObject(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, JNIObjectHandle value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetLocalInt(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, int value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetLocalLong(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, long value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetLocalFloat(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, float value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetLocalDouble(JvmtiExternalEnv externalEnv, JThread thread, int depth, int slot, double value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetBreakpoint(JvmtiExternalEnv externalEnv, JNIMethodId method, long location) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ClearBreakpoint(JvmtiExternalEnv externalEnv, JNIMethodId method, long location) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetFieldAccessWatch(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ClearFieldAccessWatch(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetFieldModificationWatch(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int ClearFieldModificationWatch(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetAllModules(JvmtiExternalEnv externalEnv, CIntPointer moduleCountPtr, JNIObjectHandlePointerPointer modulesPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetNamedModule(JvmtiExternalEnv externalEnv, JNIObjectHandle classLoader, @CConst CCharPointer packageName, JNIObjectHandlePointer modulePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddModuleReads(JvmtiExternalEnv externalEnv, JNIObjectHandle module, JNIObjectHandle toModule) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddModuleExports(JvmtiExternalEnv externalEnv, JNIObjectHandle module, @CConst CCharPointer pkgName, JNIObjectHandle toModule) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddModuleOpens(JvmtiExternalEnv externalEnv, JNIObjectHandle module, @CConst CCharPointer pkgName, JNIObjectHandle toModule) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddModuleUses(JvmtiExternalEnv externalEnv, JNIObjectHandle module, JClass service) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddModuleProvides(JvmtiExternalEnv externalEnv, JNIObjectHandle module, JClass service, JClass impl_class) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsModifiableModule(JvmtiExternalEnv externalEnv, JNIObjectHandle module, BooleanPointer isModifiableModulePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLoadedClasses(JvmtiExternalEnv externalEnv, CIntPointer classCountPtr, JClassPointerPointer classesPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassLoaderClasses(JvmtiExternalEnv externalEnv, JNIObjectHandle initiatingLoader, CIntPointer classCountPtr, JClassPointerPointer classesPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassSignature(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassStatus(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer statusPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetSourceFileName(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer sourceNamePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassModifiers(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer modifiersPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassMethods(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer methodCountPtr, JNIMethodIdPointerPointer methodsPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassFields(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer fieldCountPtr, JNIFieldIdPointerPointer fieldsPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetImplementedInterfaces(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer interfaceCountPtr, JClassPointerPointer interfacesPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassVersionNumbers(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer minorVersionPtr, CIntPointer majorVersionPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetConstantPool(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer constantPoolCountPtr, CIntPointer constantPoolByteCountPtr, CCharPointerPointer constantPoolBytesPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsInterface(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isInterfacePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsArrayClass(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isArrayClassPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsModifiableClass(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isModifiableClassPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetClassLoader(JvmtiExternalEnv externalEnv, JClass klass, JNIObjectHandlePointer classloaderPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetSourceDebugExtension(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer sourceDebugExtensionPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RetransformClasses(JvmtiExternalEnv externalEnv, int classCount, @CConst JClassPointer classes) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RedefineClasses(JvmtiExternalEnv externalEnv, int classCount, @CConst JvmtiClassDefinition classDefinitions) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetObjectSize(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CLongPointer sizePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetObjectHashCode(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CIntPointer hashCodePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetObjectMonitorUsage(JvmtiExternalEnv externalEnv, JNIObjectHandle object, JvmtiMonitorUsage infoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetFieldName(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetFieldDeclaringClass(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, JClassPointer declaringClassPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetFieldModifiers(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, CIntPointer modifiersPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsFieldSynthetic(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, BooleanPointer isSyntheticPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetMethodName(JvmtiExternalEnv externalEnv, JNIMethodId method, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetMethodDeclaringClass(JvmtiExternalEnv externalEnv, JNIMethodId method, JClassPointer declaringClassPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetMethodModifiers(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer modifiersPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetMaxLocals(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer maxPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetArgumentsSize(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer sizePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLineNumberTable(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer entryCountPtr, JvmtiLineNumberEntryPointer tablePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetMethodLocation(JvmtiExternalEnv externalEnv, JNIMethodId method, CLongPointer startLocationPtr, CLongPointer endLocationPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetLocalVariableTable(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer entryCountPtr, JvmtiLocalVariableEntryPointer tablePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetBytecodes(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer bytecodeCountPtr, CCharPointerPointer bytecodesPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsMethodNative(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isNativePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsMethodSynthetic(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isSyntheticPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int IsMethodObsolete(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isObsoletePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetNativeMethodPrefix(JvmtiExternalEnv externalEnv, @CConst CCharPointer prefix) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetNativeMethodPrefixes(JvmtiExternalEnv externalEnv, int prefixCount, CCharPointerPointer prefixes) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int CreateRawMonitor(JvmtiExternalEnv externalEnv, @CConst CCharPointer name, JRawMonitorIdPointer monitorPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int DestroyRawMonitor(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RawMonitorEnter(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RawMonitorExit(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RawMonitorWait(JvmtiExternalEnv externalEnv, JRawMonitorId monitor, long millis) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RawMonitorNotify(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RawMonitorNotifyAll(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetJNIFunctionTable(JvmtiExternalEnv externalEnv, @CConst JNINativeInterface functionTable) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetJNIFunctionTable(JvmtiExternalEnv externalEnv, JNINativeInterfacePointer functionTable) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetEventCallbacks(JvmtiExternalEnv externalEnv, @CConst JvmtiEventCallbacks callbacks, int sizeOfCallbacks) { + if (sizeOfCallbacks <= 0) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + JvmtiEnvUtil.setEventCallbacks(env, callbacks, sizeOfCallbacks); + + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetEventNotificationMode(JvmtiExternalEnv externalEnv, int eventMode, JvmtiEvent eventType, JThread eventThread) { + // TEMP (chaeubl): this method uses varargs... do we need a native wrapper to deal with + // that? seems that this is only reserved for future expansion but may still be tricky. + if (eventType == null) { + return JVMTI_ERROR_INVALID_EVENT_TYPE.getCValue(); + } else if (!eventType.isSupported()) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + /* Check that the needed capabilities are present. */ + boolean enable = (eventMode == JvmtiEventMode.JVMTI_ENABLE()); + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + if (enable && !JvmtiEnvUtil.hasEventCapability(env, eventType)) { + return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); + } + + Thread javaEventThread = JNIObjectHandles.getObject(eventThread); + if (javaEventThread == null) { + /* Change global event status. */ + JvmtiEnvUtil.setEventUserEnabled(env, null, eventType, enable); + } else { + /* Change thread-local event status. */ + if (eventType.isGlobal()) { + /* Global events cannot be controlled at thread level. */ + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + + /* At the moment, we don't support enabling events for specific threads. */ + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GenerateEvents(JvmtiExternalEnv externalEnv, int eventType) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetExtensionFunctions(JvmtiExternalEnv externalEnv, CIntPointer extensionCountPtr, JvmtiExtensionFunctionInfoPointer extensions) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetExtensionEvents(JvmtiExternalEnv externalEnv, CIntPointer extensionCountPtr, JvmtiExtensionFunctionInfoPointer extensions) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetExtensionEventCallback(JvmtiExternalEnv externalEnv, int extensionEventIndex, CFunctionPointer callback) { + /* The callback is a vararg callback that we can't model easily. */ + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetPotentialCapabilities(JvmtiExternalEnv externalEnv, JvmtiCapabilities result) { + if (result.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + + /* We don't support any capabilities at the moment. */ + JvmtiCapabilitiesUtil.clear(result); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetCapabilities(JvmtiExternalEnv externalEnv, JvmtiCapabilities result) { + if (result.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + JvmtiCapabilitiesUtil.copy(JvmtiEnvUtil.getCapabilities(env), result); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddCapabilities(JvmtiExternalEnv externalEnv, @CConst JvmtiCapabilities capabilities) { + if (capabilities.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + return JvmtiEnvUtil.addCapabilities(env, capabilities).getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int RelinquishCapabilities(JvmtiExternalEnv externalEnv, @CConst JvmtiCapabilities capabilities) { + if (capabilities.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + return JvmtiEnvUtil.relinquishCapabilities(env, capabilities).getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetCurrentThreadCpuTimerInfo(JvmtiExternalEnv externalEnv, JvmtiTimerInfo infoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetCurrentThreadCpuTime(JvmtiExternalEnv externalEnv, CLongPointer nanosPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadCpuTimerInfo(JvmtiExternalEnv externalEnv, JvmtiTimerInfo infoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetThreadCpuTime(JvmtiExternalEnv externalEnv, JThread thread, CLongPointer nanosPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetTimerInfo(JvmtiExternalEnv externalEnv, JvmtiTimerInfo infoPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetTime(JvmtiExternalEnv externalEnv, CLongPointer nanosPtr) { + if (nanosPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + nanosPtr.write(System.nanoTime()); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetAvailableProcessors(JvmtiExternalEnv externalEnv, CIntPointer processorCountPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddToBootstrapClassLoaderSearch(JvmtiExternalEnv externalEnv, @CConst CCharPointer segment) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int AddToSystemClassLoaderSearch(JvmtiExternalEnv externalEnv, @CConst CCharPointer segment) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetSystemProperties(JvmtiExternalEnv externalEnv, CIntPointer countPtr, CCharPointerPointerPointer propertyPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetSystemProperty(JvmtiExternalEnv externalEnv, @CConst CCharPointer property, CCharPointerPointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetSystemProperty(JvmtiExternalEnv externalEnv, @CConst CCharPointer property, @CConst CCharPointer valuePtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetPhase(JvmtiExternalEnv externalEnv, CIntPointer phasePtr) { + if (phasePtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + phasePtr.write(JvmtiPhase.JVMTI_PHASE_LIVE()); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int DisposeEnvironment(JvmtiExternalEnv externalEnv) { + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + JvmtiEnvUtil.free(env); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetEnvironmentLocalStorage(JvmtiExternalEnv externalEnv, @CConst VoidPointer data) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetEnvironmentLocalStorage(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetVersionNumber(JvmtiExternalEnv externalEnv, CIntPointer versionPtr) { + if (versionPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + versionPtr.write(JvmtiVersion.CURRENT_VERSION); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetErrorName(JvmtiExternalEnv externalEnv, JvmtiError jvmtiError, CCharPointerPointer namePtr) { + if (namePtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + + if (jvmtiError == null) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + + /* Convert name to ASCII. */ + String name = jvmtiError.name(); + UnsignedWord bufferSize = WordFactory.unsigned(name.length() + 1); + CCharPointer mem = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); + namePtr.write(mem); + if (mem.isNull()) { + return JVMTI_ERROR_OUT_OF_MEMORY.getCValue(); + } + + CTypeConversion.toCString(name, StandardCharsets.US_ASCII, mem, bufferSize); + return JVMTI_ERROR_NONE.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetVerboseFlag(JvmtiExternalEnv externalEnv, int verboseFlag, boolean value) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int GetJLocationFormat(JvmtiExternalEnv externalEnv, CIntPointer formatPtr) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) + @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) + static int SetHeapSamplingInterval(JvmtiExternalEnv externalEnv, int samplingInterval) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + } + + // Checkstyle: resume + + private static class JvmtiEnvEnterPrologue implements CEntryPointOptions.Prologue { + @Uninterruptible(reason = "prologue") + public static int enter(JvmtiExternalEnv externalEnv) { + // TEMP (chaeubl): we might need special logic again to avoid objects in the + // reference map before the heap base is set. Or, we make sure that the values are + // constant folded (via @Fold). + if (externalEnv.isNull()) { + return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); + } + + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + if (!JvmtiEnvUtil.isValid(env)) { + return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); + } + + int error = CEntryPointActions.enterByIsolate(JvmtiEnvUtil.getIsolate(env)); + if (error == CEntryPointErrors.UNATTACHED_THREAD) { + return JVMTI_ERROR_UNATTACHED_THREAD.getCValue(); + } else if (error != CEntryPointErrors.NO_ERROR) { + return JVMTI_ERROR_INTERNAL.getCValue(); + } + + return JVMTI_ERROR_NONE.getCValue(); + } + } + + @CPointerTo(VoidPointer.class) + private interface VoidPointerPointer extends PointerBase { + } + + @CPointerTo(CCharPointerPointer.class) + private interface CCharPointerPointerPointer extends PointerBase { + } + + @CPointerTo(CLongPointer.class) + private interface CLongPointerPointer extends PointerBase { + } + + // TEMP (chaeubl): should be uint_8 + @CPointerTo(nameOfCType = "char") + private interface BooleanPointer extends PointerBase { + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClass.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClass.java new file mode 100644 index 000000000000..ea239f55a117 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClass.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import com.oracle.svm.core.jni.headers.JNIObjectHandle; + +public interface JClass extends JNIObjectHandle { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointer.java new file mode 100644 index 000000000000..580136295105 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JClassPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointerPointer.java new file mode 100644 index 000000000000..22f322ab8bd0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JClassPointerPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JClassPointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointer.java new file mode 100644 index 000000000000..e6104f981771 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JNIObjectHandlePointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointerPointer.java new file mode 100644 index 000000000000..fc51a729ac3e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JNIObjectHandlePointerPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JNIObjectHandlePointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorId.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorId.java new file mode 100644 index 000000000000..8d771ad4cd02 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorId.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "_jrawMonitorID", addStructKeyword = true, isIncomplete = true) +public interface JRawMonitorId extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java new file mode 100644 index 000000000000..8f2e6c28ea9a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JRawMonitorId.class) +public interface JRawMonitorIdPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThread.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThread.java new file mode 100644 index 000000000000..328ac4fb64db --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThread.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import com.oracle.svm.core.jni.headers.JNIObjectHandle; + +public interface JThread extends JNIObjectHandle { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroup.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroup.java new file mode 100644 index 000000000000..8142b44819c1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroup.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import com.oracle.svm.core.jni.headers.JNIObjectHandle; + +public interface JThreadGroup extends JNIObjectHandle { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointer.java new file mode 100644 index 000000000000..8c0261d3db94 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JThreadGroupPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointer.java new file mode 100644 index 000000000000..3176d682e22f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JThreadPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointerPointer.java new file mode 100644 index 000000000000..72ac6b2a3339 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadPointerPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JThreadPointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiCapabilities.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiCapabilities.java new file mode 100644 index 000000000000..1b9a592f5194 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiCapabilities.java @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CBitfield; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiCapabilities") +public interface JvmtiCapabilities extends PointerBase { + @CBitfield("can_tag_objects") + void setCanTagObjects(boolean value); + + @CBitfield("can_tag_objects") + boolean getCanTagObjects(); + + @CBitfield("can_generate_field_modification_events") + void setCanGenerateFieldModificationEvents(boolean value); + + @CBitfield("can_generate_field_modification_events") + boolean getCanGenerateFieldModificationEvents(); + + @CBitfield("can_generate_field_access_events") + void setCanGenerateFieldAccessEvents(boolean value); + + @CBitfield("can_generate_field_access_events") + boolean getCanGenerateFieldAccessEvents(); + + @CBitfield("can_get_bytecodes") + void setCanGetBytecodes(boolean value); + + @CBitfield("can_get_bytecodes") + boolean getCanGetBytecodes(); + + @CBitfield("can_get_synthetic_attribute") + void setCanGetSyntheticAttribute(boolean value); + + @CBitfield("can_get_synthetic_attribute") + boolean getCanGetSyntheticAttribute(); + + @CBitfield("can_get_owned_monitor_info") + void setCanGetOwnedMonitorInfo(boolean value); + + @CBitfield("can_get_owned_monitor_info") + boolean getCanGetOwnedMonitorInfo(); + + @CBitfield("can_get_current_contended_monitor") + void setCanGetCurrentContendedMonitor(boolean value); + + @CBitfield("can_get_current_contended_monitor") + boolean getCanGetCurrentContendedMonitor(); + + @CBitfield("can_get_monitor_info") + void setCanGetMonitorInfo(boolean value); + + @CBitfield("can_get_monitor_info") + boolean getCanGetMonitorInfo(); + + @CBitfield("can_pop_frame") + void setCanPopFrame(boolean value); + + @CBitfield("can_pop_frame") + boolean getCanPopFrame(); + + @CBitfield("can_redefine_classes") + void setCanRedefineClasses(boolean value); + + @CBitfield("can_redefine_classes") + boolean getCanRedefineClasses(); + + @CBitfield("can_signal_thread") + void setCanSignalThread(boolean value); + + @CBitfield("can_signal_thread") + boolean getCanSignalThread(); + + @CBitfield("can_get_source_file_name") + void setCanGetSourceFileName(boolean value); + + @CBitfield("can_get_source_file_name") + boolean getCanGetSourceFileName(); + + @CBitfield("can_get_line_numbers") + void setCanGetLineNumbers(boolean value); + + @CBitfield("can_get_line_numbers") + boolean getCanGetLineNumbers(); + + @CBitfield("can_get_source_debug_extension") + void setCanGetSourceDebugExtension(boolean value); + + @CBitfield("can_get_source_debug_extension") + boolean getCanGetSourceDebugExtension(); + + @CBitfield("can_access_local_variables") + void setCanAccessLocalVariables(boolean value); + + @CBitfield("can_access_local_variables") + boolean getCanAccessLocalVariables(); + + @CBitfield("can_maintain_original_method_order") + void setCanMaintainOriginalMethodOrder(boolean value); + + @CBitfield("can_maintain_original_method_order") + boolean getCanMaintainOriginalMethodOrder(); + + @CBitfield("can_generate_single_step_events") + void setCanGenerateSingleStepEvents(boolean value); + + @CBitfield("can_generate_single_step_events") + boolean getCanGenerateSingleStepEvents(); + + @CBitfield("can_generate_exception_events") + void setCanGenerateExceptionEvents(boolean value); + + @CBitfield("can_generate_exception_events") + boolean getCanGenerateExceptionEvents(); + + @CBitfield("can_generate_frame_pop_events") + void setCanGenerateFramePopEvents(boolean value); + + @CBitfield("can_generate_frame_pop_events") + boolean getCanGenerateFramePopEvents(); + + @CBitfield("can_generate_breakpoint_events") + void setCanGenerateBreakpointEvents(boolean value); + + @CBitfield("can_generate_breakpoint_events") + boolean getCanGenerateBreakpointEvents(); + + @CBitfield("can_suspend") + void setCanSuspend(boolean value); + + @CBitfield("can_suspend") + boolean getCanSuspend(); + + @CBitfield("can_redefine_any_class") + void setCanRedefineAnyClass(boolean value); + + @CBitfield("can_redefine_any_class") + boolean getCanRedefineAnyClass(); + + @CBitfield("can_get_current_thread_cpu_time") + void setCanGetCurrentThreadCpuTime(boolean value); + + @CBitfield("can_get_current_thread_cpu_time") + boolean getCanGetCurrentThreadCpuTime(); + + @CBitfield("can_get_thread_cpu_time") + void setCanGetThreadCpuTime(boolean value); + + @CBitfield("can_get_thread_cpu_time") + boolean getCanGetThreadCpuTime(); + + @CBitfield("can_generate_method_entry_events") + void setCanGenerateMethodEntryEvents(boolean value); + + @CBitfield("can_generate_method_entry_events") + boolean getCanGenerateMethodEntryEvents(); + + @CBitfield("can_generate_method_exit_events") + void setCanGenerateMethodExitEvents(boolean value); + + @CBitfield("can_generate_method_exit_events") + boolean getCanGenerateMethodExitEvents(); + + @CBitfield("can_generate_all_class_hook_events") + void setCanGenerateAllClassHookEvents(boolean value); + + @CBitfield("can_generate_all_class_hook_events") + boolean getCanGenerateAllClassHookEvents(); + + @CBitfield("can_generate_compiled_method_load_events") + void setCanGenerateCompiledMethodLoadEvents(boolean value); + + @CBitfield("can_generate_compiled_method_load_events") + boolean getCanGenerateCompiledMethodLoadEvents(); + + @CBitfield("can_generate_monitor_events") + void setCanGenerateMonitorEvents(boolean value); + + @CBitfield("can_generate_monitor_events") + boolean getCanGenerateMonitorEvents(); + + @CBitfield("can_generate_vm_object_alloc_events") + void setCanGenerateVmObjectAllocEvents(boolean value); + + @CBitfield("can_generate_vm_object_alloc_events") + boolean getCanGenerateVmObjectAllocEvents(); + + @CBitfield("can_generate_native_method_bind_events") + void setCanGenerateNativeMethodBindEvents(boolean value); + + @CBitfield("can_generate_native_method_bind_events") + boolean getCanGenerateNativeMethodBindEvents(); + + @CBitfield("can_generate_garbage_collection_events") + void setCanGenerateGarbageCollectionEvents(boolean value); + + @CBitfield("can_generate_garbage_collection_events") + boolean getCanGenerateGarbageCollectionEvents(); + + @CBitfield("can_generate_object_free_events") + void setCanGenerateObjectFreeEvents(boolean value); + + @CBitfield("can_generate_object_free_events") + boolean getCanGenerateObjectFreeEvents(); + + @CBitfield("can_force_early_return") + void setCanForceEarlyReturn(boolean value); + + @CBitfield("can_force_early_return") + boolean getCanForceEarlyReturn(); + + @CBitfield("can_get_owned_monitor_stack_depth_info") + void setCanGetOwnedMonitorStackDepthInfo(boolean value); + + @CBitfield("can_get_owned_monitor_stack_depth_info") + boolean getCanGetOwnedMonitorStackDepthInfo(); + + @CBitfield("can_get_constant_pool") + void setCanGetConstantPool(boolean value); + + @CBitfield("can_get_constant_pool") + boolean getCanGetConstantPool(); + + @CBitfield("can_set_native_method_prefix") + void setCanSetNativeMethodPrefix(boolean value); + + @CBitfield("can_set_native_method_prefix") + boolean getCanSetNativeMethodPrefix(); + + @CBitfield("can_retransform_classes") + void setCanRetransformClasses(boolean value); + + @CBitfield("can_retransform_classes") + boolean getCanRetransformClasses(); + + @CBitfield("can_retransform_any_class") + void setCanRetransformAnyClass(boolean value); + + @CBitfield("can_retransform_any_class") + boolean getCanRetransformAnyClass(); + + @CBitfield("can_generate_resource_exhaustion_heap_events") + void setCanGenerateResourceExhaustionHeapEvents(boolean value); + + @CBitfield("can_generate_resource_exhaustion_heap_events") + boolean getCanGenerateResourceExhaustionHeapEvents(); + + @CBitfield("can_generate_resource_exhaustion_threads_events") + void setCanGenerateResourceExhaustionThreadsEvents(boolean value); + + @CBitfield("can_generate_resource_exhaustion_threads_events") + boolean getCanGenerateResourceExhaustionThreadsEvents(); + + @CBitfield("can_generate_early_vmstart") + void setCanGenerateEarlyVmstart(boolean value); + + @CBitfield("can_generate_early_vmstart") + boolean getCanGenerateEarlyVmstart(); + + @CBitfield("can_generate_early_class_hook_events") + void setCanGenerateEarlyClassHookEvents(boolean value); + + @CBitfield("can_generate_early_class_hook_events") + boolean getCanGenerateEarlyClassHookEvents(); + + @CBitfield("can_generate_sampled_object_alloc_events") + void setCanGenerateSampledObjectAllocEvents(boolean value); + + @CBitfield("can_generate_sampled_object_alloc_events") + boolean getCanGenerateSampledObjectAllocEvents(); + + @CBitfield("can_support_virtual_threads") + void setCanSupportVirtualThreads(boolean value); + + @CBitfield("can_support_virtual_threads") + boolean getCanSupportVirtualThreads(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiClassDefinition.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiClassDefinition.java new file mode 100644 index 000000000000..7f34b94477e6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiClassDefinition.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiClassDefinition") +public interface JvmtiClassDefinition extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java new file mode 100644 index 000000000000..cd162c4ad0a6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; + +import org.graalvm.nativeimage.c.CContext; + +import com.oracle.svm.core.OS; +import com.oracle.svm.core.SubstrateOptions; + +// TEMP (chaeubl): copied +class JvmtiDirectives implements CContext.Directives { + + private final Path jdkIncludeDir = Paths.get(System.getProperty("java.home")).resolve("include"); + + @Override + public boolean isInConfiguration() { + return SubstrateOptions.JVMTI.getValue(); + } + + @Override + public List getHeaderFiles() { + return Collections.singletonList("\"" + jdkIncludeDir.resolve("jvmti.h") + "\""); + } + + @Override + public List getOptions() { + return Collections.singletonList("-I" + jdkIncludeDir.resolve(OS.getCurrent() == OS.WINDOWS ? "win32" : OS.getCurrent().asPackageName())); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java new file mode 100644 index 000000000000..c92317882a01 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CEnum; +import org.graalvm.nativeimage.c.constant.CEnumLookup; +import org.graalvm.nativeimage.c.constant.CEnumValue; + +@CEnum("jvmtiError") +@CContext(JvmtiDirectives.class) +public enum JvmtiError { + /* Universal errors. */ + JVMTI_ERROR_NONE, + JVMTI_ERROR_NULL_POINTER, + JVMTI_ERROR_OUT_OF_MEMORY, + JVMTI_ERROR_ACCESS_DENIED, + JVMTI_ERROR_UNATTACHED_THREAD, + JVMTI_ERROR_INVALID_ENVIRONMENT, + JVMTI_ERROR_WRONG_PHASE, + JVMTI_ERROR_INTERNAL, + + /* Function specific errors. */ + JVMTI_ERROR_INVALID_PRIORITY, + JVMTI_ERROR_THREAD_NOT_SUSPENDED, + JVMTI_ERROR_THREAD_SUSPENDED, + JVMTI_ERROR_THREAD_NOT_ALIVE, + JVMTI_ERROR_CLASS_NOT_PREPARED, + JVMTI_ERROR_NO_MORE_FRAMES, + JVMTI_ERROR_OPAQUE_FRAME, + JVMTI_ERROR_DUPLICATE, + JVMTI_ERROR_NOT_FOUND, + JVMTI_ERROR_NOT_MONITOR_OWNER, + JVMTI_ERROR_INTERRUPT, + JVMTI_ERROR_UNMODIFIABLE_CLASS, + JVMTI_ERROR_UNMODIFIABLE_MODULE, + JVMTI_ERROR_NOT_AVAILABLE, + JVMTI_ERROR_ABSENT_INFORMATION, + JVMTI_ERROR_INVALID_EVENT_TYPE, + JVMTI_ERROR_NATIVE_METHOD, + JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED, + + /* Function specific agent errors. */ + JVMTI_ERROR_INVALID_THREAD, + JVMTI_ERROR_INVALID_FIELDID, + JVMTI_ERROR_INVALID_MODULE, + JVMTI_ERROR_INVALID_METHODID, + JVMTI_ERROR_INVALID_LOCATION, + JVMTI_ERROR_INVALID_OBJECT, + JVMTI_ERROR_INVALID_CLASS, + JVMTI_ERROR_TYPE_MISMATCH, + JVMTI_ERROR_INVALID_SLOT, + JVMTI_ERROR_MUST_POSSESS_CAPABILITY, + JVMTI_ERROR_INVALID_THREAD_GROUP, + JVMTI_ERROR_INVALID_MONITOR, + JVMTI_ERROR_ILLEGAL_ARGUMENT, + JVMTI_ERROR_INVALID_TYPESTATE, + JVMTI_ERROR_UNSUPPORTED_VERSION, + JVMTI_ERROR_INVALID_CLASS_FORMAT, + JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED, + JVMTI_ERROR_FAILS_VERIFICATION, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED, + JVMTI_ERROR_NAMES_DONT_MATCH, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED, + JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED, + JVMTI_ERROR_UNSUPPORTED_OPERATION; + + @CEnumValue + public native int getCValue(); + + @CEnumLookup + public static native JvmtiError fromValue(int value); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiErrorPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiErrorPointer.java new file mode 100644 index 000000000000..cfba40ecae96 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiErrorPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.type.CIntPointer; + +public interface JvmtiErrorPointer extends CIntPointer { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java new file mode 100644 index 000000000000..da8a02ed81e4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CEnum; +import org.graalvm.nativeimage.c.constant.CEnumLookup; +import org.graalvm.nativeimage.c.constant.CEnumValue; + +@CEnum("jvmtiEvent") +@CContext(JvmtiDirectives.class) +public enum JvmtiEvent { + JVMTI_EVENT_VM_INIT(true, true), + JVMTI_EVENT_VM_DEATH(true, true), + JVMTI_EVENT_THREAD_START(true, false), + JVMTI_EVENT_THREAD_END(false, false), + JVMTI_EVENT_CLASS_FILE_LOAD_HOOK(false, false), + JVMTI_EVENT_CLASS_LOAD(false, false), + JVMTI_EVENT_CLASS_PREPARE(false, false), + JVMTI_EVENT_VM_START(true, true), + JVMTI_EVENT_EXCEPTION(false, false), + JVMTI_EVENT_EXCEPTION_CATCH(false, false), + JVMTI_EVENT_SINGLE_STEP(false, false), + JVMTI_EVENT_FRAME_POP(false, false), + JVMTI_EVENT_BREAKPOINT(false, false), + JVMTI_EVENT_FIELD_ACCESS(false, false), + JVMTI_EVENT_FIELD_MODIFICATION(false, false), + JVMTI_EVENT_METHOD_ENTRY(false, false), + JVMTI_EVENT_METHOD_EXIT(false, false), + JVMTI_EVENT_NATIVE_METHOD_BIND(false, false), + JVMTI_EVENT_COMPILED_METHOD_LOAD(true, false), + JVMTI_EVENT_COMPILED_METHOD_UNLOAD(true, false), + JVMTI_EVENT_DYNAMIC_CODE_GENERATED(true, false), + JVMTI_EVENT_DATA_DUMP_REQUEST(true, false), + JVMTI_EVENT_MONITOR_WAIT(false, false), + JVMTI_EVENT_MONITOR_WAITED(false, false), + JVMTI_EVENT_MONITOR_CONTENDED_ENTER(false, false), + JVMTI_EVENT_MONITOR_CONTENDED_ENTERED(false, false), + JVMTI_EVENT_RESOURCE_EXHAUSTED(false, false), + JVMTI_EVENT_GARBAGE_COLLECTION_START(false, false), + JVMTI_EVENT_GARBAGE_COLLECTION_FINISH(false, false), + JVMTI_EVENT_OBJECT_FREE(false, false), + JVMTI_EVENT_VM_OBJECT_ALLOC(false, false), + JVMTI_EVENT_SAMPLED_OBJECT_ALLOC(false, false), + JVMTI_EVENT_VIRTUAL_THREAD_START(false, false), + JVMTI_EVENT_VIRTUAL_THREAD_END(false, false); + + private final boolean isSupported; + private final boolean isGlobal; + + JvmtiEvent(boolean isGlobal, boolean isSupported) { + this.isGlobal = isGlobal; + this.isSupported = isSupported; + } + + public boolean isSupported() { + return isSupported; + } + + public boolean isGlobal() { + return isGlobal; + } + + @CEnumValue + public native int getCValue(); + + @CEnumLookup + public static native JvmtiEvent fromValue(int value); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java new file mode 100644 index 000000000000..8208ba742924 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.struct.CField; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +import com.oracle.svm.core.jni.headers.JNIEnvironment; + +/** + * Only a small subset of the callbacks is supported at the moment. All unsupported callbacks use + * the type {@link CFunctionPointer}. + */ +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiEventCallbacks") +public interface JvmtiEventCallbacks extends PointerBase { + @CField + JvmtiEventVMInitFunctionPointer getVMInit(); + + @CField + JvmtiEventVMDeathFunctionPointer getVMDeath(); + + @CField + CFunctionPointer getThreadStart(); + + @CField + CFunctionPointer getThreadEnd(); + + @CField + CFunctionPointer getClassFileLoadHook(); + + @CField + CFunctionPointer getClassLoad(); + + @CField + CFunctionPointer getClassPrepare(); + + @CField + JvmtiEventVMStartFunctionPointer getVMStart(); + + @CField + CFunctionPointer getException(); + + @CField + CFunctionPointer getExceptionCatch(); + + @CField + CFunctionPointer getSingleStep(); + + @CField + CFunctionPointer getFramePop(); + + @CField + CFunctionPointer getBreakpoint(); + + @CField + CFunctionPointer getFieldAccess(); + + @CField + CFunctionPointer getFieldModification(); + + @CField + CFunctionPointer getMethodEntry(); + + @CField + CFunctionPointer getMethodExit(); + + @CField + CFunctionPointer getNativeMethodBind(); + + @CField + CFunctionPointer getCompiledMethodLoad(); + + @CField + CFunctionPointer getCompiledMethodUnload(); + + @CField + CFunctionPointer getDynamicCodeGenerated(); + + @CField + CFunctionPointer getDataDumpRequest(); + + @CField("reserved72") + CFunctionPointer getReserved72(); + + @CField + CFunctionPointer getMonitorWait(); + + @CField + CFunctionPointer getMonitorWaited(); + + @CField + CFunctionPointer getMonitorContendedEnter(); + + @CField + CFunctionPointer getMonitorContendedEntered(); + + @CField("reserved77") + CFunctionPointer getReserved77(); + + @CField("reserved78") + CFunctionPointer getReserved78(); + + @CField("reserved79") + CFunctionPointer getReserved79(); + + @CField + CFunctionPointer getResourceExhausted(); + + @CField + CFunctionPointer getGarbageCollectionStart(); + + @CField + CFunctionPointer getGarbageCollectionFinish(); + + @CField + CFunctionPointer getObjectFree(); + + @CField + CFunctionPointer getVMObjectAlloc(); + + @CField("reserved85") + CFunctionPointer getReserved85(); + + @CField + CFunctionPointer getSampledObjectAlloc(); + + @CField + CFunctionPointer getVirtualThreadStart(); + + @CField + CFunctionPointer getVirtualThreadEnd(); + + interface JvmtiEventVMInitFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread); + } + + interface JvmtiEventVMDeathFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); + } + + interface JvmtiEventVMStartFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java new file mode 100644 index 000000000000..af838468b647 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiEventMode { + @CConstant + public static native int JVMTI_ENABLE(); + + @CConstant + public static native int JVMTI_DISABLE(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfo.java new file mode 100644 index 000000000000..e0b9b3ae2d80 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "jvmtiExtensionFunctionInfo", addStructKeyword = true) +public interface JvmtiExtensionFunctionInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java new file mode 100644 index 000000000000..100123ee74dd --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JvmtiExtensionFunctionInfo.class) +public interface JvmtiExtensionFunctionInfoPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExternalEnv.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExternalEnv.java new file mode 100644 index 000000000000..cd9e2e063aff --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExternalEnv.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CField; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "_jvmtiEnv", addStructKeyword = true) +public interface JvmtiExternalEnv extends PointerBase { + @CField("functions") + JvmtiInterface getFunctions(); + + @CField("functions") + void setFunctions(JvmtiInterface table); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java new file mode 100644 index 000000000000..b5b58ebaad28 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiFrameInfo") +public interface JvmtiFrameInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapCallbacks.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapCallbacks.java new file mode 100644 index 000000000000..5787e49d9552 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapCallbacks.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiHeapCallbacks") +public interface JvmtiHeapCallbacks extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectCallback.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectCallback.java new file mode 100644 index 000000000000..eda2acac9549 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectCallback.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.nativeimage.c.type.VoidPointer; + +public interface JvmtiHeapObjectCallback extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(long classTag, long size, CLongPointer tagPtr, VoidPointer userData); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java new file mode 100644 index 000000000000..368eb3909c0d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiHeapObjectFilter { + @CConstant + public static native int JVMTI_HEAP_OBJECT_TAGGED(); + + @CConstant + public static native int JVMTI_HEAP_OBJECT_UNTAGGED(); + + @CConstant + public static native int JVMTI_HEAP_OBJECT_EITHER(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootCallback.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootCallback.java new file mode 100644 index 000000000000..cbfe2f956c5f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootCallback.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.nativeimage.c.type.VoidPointer; + +public interface JvmtiHeapRootCallback extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiHeapRootKind rootKind, long classTag, long size, CLongPointer tagPtr, VoidPointer userData); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java new file mode 100644 index 000000000000..66093d61609e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiHeapRootKind { + @CConstant + public static native int JVMTI_HEAP_ROOT_JNI_GLOBAL(); + + @CConstant + public static native int JVMTI_HEAP_ROOT_SYSTEM_CLASS(); + + @CConstant + public static native int JVMTI_HEAP_ROOT_MONITOR(); + + @CConstant + public static native int JVMTI_HEAP_ROOT_STACK_LOCAL(); + + @CConstant + public static native int JVMTI_HEAP_ROOT_JNI_LOCAL(); + + @CConstant + public static native int JVMTI_HEAP_ROOT_THREAD(); + + @CConstant + public static native int JVMTI_HEAP_ROOT_OTHER(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiInterface.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiInterface.java new file mode 100644 index 000000000000..c256e040bcc0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiInterface.java @@ -0,0 +1,954 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.struct.CField; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "jvmtiInterface_1_", addStructKeyword = true) +public interface JvmtiInterface extends PointerBase { + @CField + VoidPointer reserved1(); + + @CField + CFunctionPointer getSetEventNotificationMode(); + + @CField + void setSetEventNotificationMode(CFunctionPointer value); + + @CField + CFunctionPointer getGetAllModules(); + + @CField + void setGetAllModules(CFunctionPointer value); + + @CField + CFunctionPointer getGetAllThreads(); + + @CField + void setGetAllThreads(CFunctionPointer value); + + @CField + CFunctionPointer getSuspendThread(); + + @CField + void setSuspendThread(CFunctionPointer value); + + @CField + CFunctionPointer getResumeThread(); + + @CField + void setResumeThread(CFunctionPointer value); + + @CField + CFunctionPointer getStopThread(); + + @CField + void setStopThread(CFunctionPointer value); + + @CField + CFunctionPointer getInterruptThread(); + + @CField + void setInterruptThread(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadInfo(); + + @CField + void setGetThreadInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetOwnedMonitorInfo(); + + @CField + void setGetOwnedMonitorInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetCurrentContendedMonitor(); + + @CField + void setGetCurrentContendedMonitor(CFunctionPointer value); + + @CField + CFunctionPointer getRunAgentThread(); + + @CField + void setRunAgentThread(CFunctionPointer value); + + @CField + CFunctionPointer getGetTopThreadGroups(); + + @CField + void setGetTopThreadGroups(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadGroupInfo(); + + @CField + void setGetThreadGroupInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadGroupChildren(); + + @CField + void setGetThreadGroupChildren(CFunctionPointer value); + + @CField + CFunctionPointer getGetFrameCount(); + + @CField + void setGetFrameCount(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadState(); + + @CField + void setGetThreadState(CFunctionPointer value); + + @CField + CFunctionPointer getGetCurrentThread(); + + @CField + void setGetCurrentThread(CFunctionPointer value); + + @CField + CFunctionPointer getGetFrameLocation(); + + @CField + void setGetFrameLocation(CFunctionPointer value); + + @CField + CFunctionPointer getNotifyFramePop(); + + @CField + void setNotifyFramePop(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalObject(); + + @CField + void setGetLocalObject(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalInt(); + + @CField + void setGetLocalInt(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalLong(); + + @CField + void setGetLocalLong(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalFloat(); + + @CField + void setGetLocalFloat(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalDouble(); + + @CField + void setGetLocalDouble(CFunctionPointer value); + + @CField + CFunctionPointer getSetLocalObject(); + + @CField + void setSetLocalObject(CFunctionPointer value); + + @CField + CFunctionPointer getSetLocalInt(); + + @CField + void setSetLocalInt(CFunctionPointer value); + + @CField + CFunctionPointer getSetLocalLong(); + + @CField + void setSetLocalLong(CFunctionPointer value); + + @CField + CFunctionPointer getSetLocalFloat(); + + @CField + void setSetLocalFloat(CFunctionPointer value); + + @CField + CFunctionPointer getSetLocalDouble(); + + @CField + void setSetLocalDouble(CFunctionPointer value); + + @CField + CFunctionPointer getCreateRawMonitor(); + + @CField + void setCreateRawMonitor(CFunctionPointer value); + + @CField + CFunctionPointer getDestroyRawMonitor(); + + @CField + void setDestroyRawMonitor(CFunctionPointer value); + + @CField + CFunctionPointer getRawMonitorEnter(); + + @CField + void setRawMonitorEnter(CFunctionPointer value); + + @CField + CFunctionPointer getRawMonitorExit(); + + @CField + void setRawMonitorExit(CFunctionPointer value); + + @CField + CFunctionPointer getRawMonitorWait(); + + @CField + void setRawMonitorWait(CFunctionPointer value); + + @CField + CFunctionPointer getRawMonitorNotify(); + + @CField + void setRawMonitorNotify(CFunctionPointer value); + + @CField + CFunctionPointer getRawMonitorNotifyAll(); + + @CField + void setRawMonitorNotifyAll(CFunctionPointer value); + + @CField + CFunctionPointer getSetBreakpoint(); + + @CField + void setSetBreakpoint(CFunctionPointer value); + + @CField + CFunctionPointer getClearBreakpoint(); + + @CField + void setClearBreakpoint(CFunctionPointer value); + + @CField + CFunctionPointer getGetNamedModule(); + + @CField + void setGetNamedModule(CFunctionPointer value); + + @CField + CFunctionPointer getSetFieldAccessWatch(); + + @CField + void setSetFieldAccessWatch(CFunctionPointer value); + + @CField + CFunctionPointer getClearFieldAccessWatch(); + + @CField + void setClearFieldAccessWatch(CFunctionPointer value); + + @CField + CFunctionPointer getSetFieldModificationWatch(); + + @CField + void setSetFieldModificationWatch(CFunctionPointer value); + + @CField + CFunctionPointer getClearFieldModificationWatch(); + + @CField + void setClearFieldModificationWatch(CFunctionPointer value); + + @CField + CFunctionPointer getIsModifiableClass(); + + @CField + void setIsModifiableClass(CFunctionPointer value); + + @CField + CFunctionPointer getAllocate(); + + @CField + void setAllocate(CFunctionPointer value); + + @CField + CFunctionPointer getDeallocate(); + + @CField + void setDeallocate(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassSignature(); + + @CField + void setGetClassSignature(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassStatus(); + + @CField + void setGetClassStatus(CFunctionPointer value); + + @CField + CFunctionPointer getGetSourceFileName(); + + @CField + void setGetSourceFileName(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassModifiers(); + + @CField + void setGetClassModifiers(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassMethods(); + + @CField + void setGetClassMethods(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassFields(); + + @CField + void setGetClassFields(CFunctionPointer value); + + @CField + CFunctionPointer getGetImplementedInterfaces(); + + @CField + void setGetImplementedInterfaces(CFunctionPointer value); + + @CField + CFunctionPointer getIsInterface(); + + @CField + void setIsInterface(CFunctionPointer value); + + @CField + CFunctionPointer getIsArrayClass(); + + @CField + void setIsArrayClass(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassLoader(); + + @CField + void setGetClassLoader(CFunctionPointer value); + + @CField + CFunctionPointer getGetObjectHashCode(); + + @CField + void setGetObjectHashCode(CFunctionPointer value); + + @CField + CFunctionPointer getGetObjectMonitorUsage(); + + @CField + void setGetObjectMonitorUsage(CFunctionPointer value); + + @CField + CFunctionPointer getGetFieldName(); + + @CField + void setGetFieldName(CFunctionPointer value); + + @CField + CFunctionPointer getGetFieldDeclaringClass(); + + @CField + void setGetFieldDeclaringClass(CFunctionPointer value); + + @CField + CFunctionPointer getGetFieldModifiers(); + + @CField + void setGetFieldModifiers(CFunctionPointer value); + + @CField + CFunctionPointer getIsFieldSynthetic(); + + @CField + void setIsFieldSynthetic(CFunctionPointer value); + + @CField + CFunctionPointer getGetMethodName(); + + @CField + void setGetMethodName(CFunctionPointer value); + + @CField + CFunctionPointer getGetMethodDeclaringClass(); + + @CField + void setGetMethodDeclaringClass(CFunctionPointer value); + + @CField + CFunctionPointer getGetMethodModifiers(); + + @CField + void setGetMethodModifiers(CFunctionPointer value); + + @CField + CFunctionPointer reserved67(); + + @CField + CFunctionPointer getGetMaxLocals(); + + @CField + void setGetMaxLocals(CFunctionPointer value); + + @CField + CFunctionPointer getGetArgumentsSize(); + + @CField + void setGetArgumentsSize(CFunctionPointer value); + + @CField + CFunctionPointer getGetLineNumberTable(); + + @CField + void setGetLineNumberTable(CFunctionPointer value); + + @CField + CFunctionPointer getGetMethodLocation(); + + @CField + void setGetMethodLocation(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalVariableTable(); + + @CField + void setGetLocalVariableTable(CFunctionPointer value); + + @CField + CFunctionPointer getSetNativeMethodPrefix(); + + @CField + void setSetNativeMethodPrefix(CFunctionPointer value); + + @CField + CFunctionPointer getSetNativeMethodPrefixes(); + + @CField + void setSetNativeMethodPrefixes(CFunctionPointer value); + + @CField + CFunctionPointer getGetBytecodes(); + + @CField + void setGetBytecodes(CFunctionPointer value); + + @CField + CFunctionPointer getIsMethodNative(); + + @CField + void setIsMethodNative(CFunctionPointer value); + + @CField + CFunctionPointer getIsMethodSynthetic(); + + @CField + void setIsMethodSynthetic(CFunctionPointer value); + + @CField + CFunctionPointer getGetLoadedClasses(); + + @CField + void setGetLoadedClasses(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassLoaderClasses(); + + @CField + void setGetClassLoaderClasses(CFunctionPointer value); + + @CField + CFunctionPointer getPopFrame(); + + @CField + void setPopFrame(CFunctionPointer value); + + @CField + CFunctionPointer getForceEarlyReturnObject(); + + @CField + void setForceEarlyReturnObject(CFunctionPointer value); + + @CField + CFunctionPointer getForceEarlyReturnInt(); + + @CField + void setForceEarlyReturnInt(CFunctionPointer value); + + @CField + CFunctionPointer getForceEarlyReturnLong(); + + @CField + void setForceEarlyReturnLong(CFunctionPointer value); + + @CField + CFunctionPointer getForceEarlyReturnFloat(); + + @CField + void setForceEarlyReturnFloat(CFunctionPointer value); + + @CField + CFunctionPointer getForceEarlyReturnDouble(); + + @CField + void setForceEarlyReturnDouble(CFunctionPointer value); + + @CField + CFunctionPointer getForceEarlyReturnVoid(); + + @CField + void setForceEarlyReturnVoid(CFunctionPointer value); + + @CField + CFunctionPointer getRedefineClasses(); + + @CField + void setRedefineClasses(CFunctionPointer value); + + @CField + CFunctionPointer getGetVersionNumber(); + + @CField + void setGetVersionNumber(CFunctionPointer value); + + @CField + CFunctionPointer getGetCapabilities(); + + @CField + void setGetCapabilities(CFunctionPointer value); + + @CField + CFunctionPointer getGetSourceDebugExtension(); + + @CField + void setGetSourceDebugExtension(CFunctionPointer value); + + @CField + CFunctionPointer getIsMethodObsolete(); + + @CField + void setIsMethodObsolete(CFunctionPointer value); + + @CField + CFunctionPointer getSuspendThreadList(); + + @CField + void setSuspendThreadList(CFunctionPointer value); + + @CField + CFunctionPointer getResumeThreadList(); + + @CField + void setResumeThreadList(CFunctionPointer value); + + @CField + CFunctionPointer getAddModuleReads(); + + @CField + void setAddModuleReads(CFunctionPointer value); + + @CField + CFunctionPointer getAddModuleExports(); + + @CField + void setAddModuleExports(CFunctionPointer value); + + @CField + CFunctionPointer getAddModuleOpens(); + + @CField + void setAddModuleOpens(CFunctionPointer value); + + @CField + CFunctionPointer getAddModuleUses(); + + @CField + void setAddModuleUses(CFunctionPointer value); + + @CField + CFunctionPointer getAddModuleProvides(); + + @CField + void setAddModuleProvides(CFunctionPointer value); + + @CField + CFunctionPointer getIsModifiableModule(); + + @CField + void setIsModifiableModule(CFunctionPointer value); + + @CField + CFunctionPointer getGetAllStackTraces(); + + @CField + void setGetAllStackTraces(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadListStackTraces(); + + @CField + void setGetThreadListStackTraces(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadLocalStorage(); + + @CField + void setGetThreadLocalStorage(CFunctionPointer value); + + @CField + CFunctionPointer getSetThreadLocalStorage(); + + @CField + void setSetThreadLocalStorage(CFunctionPointer value); + + @CField + CFunctionPointer getGetStackTrace(); + + @CField + void setGetStackTrace(CFunctionPointer value); + + @CField + CFunctionPointer reserved105(); + + @CField + CFunctionPointer getGetTag(); + + @CField + void setGetTag(CFunctionPointer value); + + @CField + CFunctionPointer getSetTag(); + + @CField + void setSetTag(CFunctionPointer value); + + @CField + CFunctionPointer getForceGarbageCollection(); + + @CField + void setForceGarbageCollection(CFunctionPointer value); + + @CField + CFunctionPointer getIterateOverObjectsReachableFromObject(); + + @CField + void setIterateOverObjectsReachableFromObject(CFunctionPointer value); + + @CField + CFunctionPointer getIterateOverReachableObjects(); + + @CField + void setIterateOverReachableObjects(CFunctionPointer value); + + @CField + CFunctionPointer getIterateOverHeap(); + + @CField + void setIterateOverHeap(CFunctionPointer value); + + @CField + CFunctionPointer getIterateOverInstancesOfClass(); + + @CField + void setIterateOverInstancesOfClass(CFunctionPointer value); + + @CField + CFunctionPointer reserved113(); + + @CField + CFunctionPointer getGetObjectsWithTags(); + + @CField + void setGetObjectsWithTags(CFunctionPointer value); + + @CField + CFunctionPointer getFollowReferences(); + + @CField + void setFollowReferences(CFunctionPointer value); + + @CField + CFunctionPointer getIterateThroughHeap(); + + @CField + void setIterateThroughHeap(CFunctionPointer value); + + @CField + CFunctionPointer reserved117(); + + @CField + CFunctionPointer getSuspendAllVirtualThreads(); + + @CField + void setSuspendAllVirtualThreads(CFunctionPointer value); + + @CField + CFunctionPointer getResumeAllVirtualThreads(); + + @CField + void setResumeAllVirtualThreads(CFunctionPointer value); + + @CField + CFunctionPointer getSetJNIFunctionTable(); + + @CField + void setSetJNIFunctionTable(CFunctionPointer value); + + @CField + CFunctionPointer getGetJNIFunctionTable(); + + @CField + void setGetJNIFunctionTable(CFunctionPointer value); + + @CField + CFunctionPointer getSetEventCallbacks(); + + @CField + void setSetEventCallbacks(CFunctionPointer value); + + @CField + CFunctionPointer getGenerateEvents(); + + @CField + void setGenerateEvents(CFunctionPointer value); + + @CField + CFunctionPointer getGetExtensionFunctions(); + + @CField + void setGetExtensionFunctions(CFunctionPointer value); + + @CField + CFunctionPointer getGetExtensionEvents(); + + @CField + void setGetExtensionEvents(CFunctionPointer value); + + @CField + CFunctionPointer getSetExtensionEventCallback(); + + @CField + void setSetExtensionEventCallback(CFunctionPointer value); + + @CField + CFunctionPointer getDisposeEnvironment(); + + @CField + void setDisposeEnvironment(CFunctionPointer value); + + @CField + CFunctionPointer getGetErrorName(); + + @CField + void setGetErrorName(CFunctionPointer value); + + @CField + CFunctionPointer getGetJLocationFormat(); + + @CField + void setGetJLocationFormat(CFunctionPointer value); + + @CField + CFunctionPointer getGetSystemProperties(); + + @CField + void setGetSystemProperties(CFunctionPointer value); + + @CField + CFunctionPointer getGetSystemProperty(); + + @CField + void setGetSystemProperty(CFunctionPointer value); + + @CField + CFunctionPointer getSetSystemProperty(); + + @CField + void setSetSystemProperty(CFunctionPointer value); + + @CField + CFunctionPointer getGetPhase(); + + @CField + void setGetPhase(CFunctionPointer value); + + @CField + CFunctionPointer getGetCurrentThreadCpuTimerInfo(); + + @CField + void setGetCurrentThreadCpuTimerInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetCurrentThreadCpuTime(); + + @CField + void setGetCurrentThreadCpuTime(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadCpuTimerInfo(); + + @CField + void setGetThreadCpuTimerInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetThreadCpuTime(); + + @CField + void setGetThreadCpuTime(CFunctionPointer value); + + @CField + CFunctionPointer getGetTimerInfo(); + + @CField + void setGetTimerInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetTime(); + + @CField + void setGetTime(CFunctionPointer value); + + @CField + CFunctionPointer getGetPotentialCapabilities(); + + @CField + void setGetPotentialCapabilities(CFunctionPointer value); + + @CField + CFunctionPointer reserved141(); + + @CField + CFunctionPointer getAddCapabilities(); + + @CField + void setAddCapabilities(CFunctionPointer value); + + @CField + CFunctionPointer getRelinquishCapabilities(); + + @CField + void setRelinquishCapabilities(CFunctionPointer value); + + @CField + CFunctionPointer getGetAvailableProcessors(); + + @CField + void setGetAvailableProcessors(CFunctionPointer value); + + @CField + CFunctionPointer getGetClassVersionNumbers(); + + @CField + void setGetClassVersionNumbers(CFunctionPointer value); + + @CField + CFunctionPointer getGetConstantPool(); + + @CField + void setGetConstantPool(CFunctionPointer value); + + @CField + CFunctionPointer getGetEnvironmentLocalStorage(); + + @CField + void setGetEnvironmentLocalStorage(CFunctionPointer value); + + @CField + CFunctionPointer getSetEnvironmentLocalStorage(); + + @CField + void setSetEnvironmentLocalStorage(CFunctionPointer value); + + @CField + CFunctionPointer getAddToBootstrapClassLoaderSearch(); + + @CField + void setAddToBootstrapClassLoaderSearch(CFunctionPointer value); + + @CField + CFunctionPointer getSetVerboseFlag(); + + @CField + void setSetVerboseFlag(CFunctionPointer value); + + @CField + CFunctionPointer getAddToSystemClassLoaderSearch(); + + @CField + void setAddToSystemClassLoaderSearch(CFunctionPointer value); + + @CField + CFunctionPointer getRetransformClasses(); + + @CField + void setRetransformClasses(CFunctionPointer value); + + @CField + CFunctionPointer getGetOwnedMonitorStackDepthInfo(); + + @CField + void setGetOwnedMonitorStackDepthInfo(CFunctionPointer value); + + @CField + CFunctionPointer getGetObjectSize(); + + @CField + void setGetObjectSize(CFunctionPointer value); + + @CField + CFunctionPointer getGetLocalInstance(); + + @CField + void setGetLocalInstance(CFunctionPointer value); + + @CField + CFunctionPointer getSetHeapSamplingInterval(); + + @CField + void setSetHeapSamplingInterval(CFunctionPointer value); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java new file mode 100644 index 000000000000..ed4f59e09f51 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiIterationControl { + @CConstant + public static native int JVMTI_ITERATION_CONTINUE(); + + @CConstant + public static native int JVMTI_ITERATION_IGNORE(); + + @CConstant + public static native int JVMTI_ITERATION_ABORT(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntry.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntry.java new file mode 100644 index 000000000000..e96c2c7c05e7 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntry.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "jvmtiLineNumberEntry", addStructKeyword = true) +public interface JvmtiLineNumberEntry extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java new file mode 100644 index 000000000000..9f6cba611ffc --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JvmtiLineNumberEntry.class) +public interface JvmtiLineNumberEntryPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntry.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntry.java new file mode 100644 index 000000000000..bb89e0c9a4b8 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntry.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "jvmtiLocalVariableEntry", addStructKeyword = true) +public interface JvmtiLocalVariableEntry extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java new file mode 100644 index 000000000000..1b73cc288526 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JvmtiLocalVariableEntry.class) +public interface JvmtiLocalVariableEntryPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfo.java new file mode 100644 index 000000000000..872a280c4cf1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "jvmtiMonitorStackDepthInfo", addStructKeyword = true) +public interface JvmtiMonitorStackDepthInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java new file mode 100644 index 000000000000..32e261e02259 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JvmtiMonitorStackDepthInfo.class) +public interface JvmtiMonitorStackDepthInfoPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorUsage.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorUsage.java new file mode 100644 index 000000000000..2598f0d8fc54 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorUsage.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiMonitorUsage") +public interface JvmtiMonitorUsage extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceCallback.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceCallback.java new file mode 100644 index 000000000000..b4938dd61146 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceCallback.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.nativeimage.c.type.VoidPointer; + +public interface JvmtiObjectReferenceCallback extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(int objectReferenceKind, long classTag, long size, CLongPointer tagPtr, long referrerTag, int referrerIndex, VoidPointer userData); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java new file mode 100644 index 000000000000..4fe89a2771e9 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiObjectReferenceKind { + @CConstant + public static native int JVMTI_REFERENCE_CLASS(); + + @CConstant + public static native int JVMTI_REFERENCE_FIELD(); + + @CConstant + public static native int JVMTI_REFERENCE_ARRAY_ELEMENT(); + + @CConstant + public static native int JVMTI_REFERENCE_CLASS_LOADER(); + + @CConstant + public static native int JVMTI_REFERENCE_SIGNERS(); + + @CConstant + public static native int JVMTI_REFERENCE_PROTECTION_DOMAIN(); + + @CConstant + public static native int JVMTI_REFERENCE_INTERFACE(); + + @CConstant + public static native int JVMTI_REFERENCE_STATIC_FIELD(); + + @CConstant + public static native int JVMTI_REFERENCE_CONSTANT_POOL(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java new file mode 100644 index 000000000000..11dbdaef775f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiPhase { + @CConstant + public static native int JVMTI_PHASE_ONLOAD(); + + @CConstant + public static native int JVMTI_PHASE_PRIMORDIAL(); + + @CConstant + public static native int JVMTI_PHASE_START(); + + @CConstant + public static native int JVMTI_PHASE_LIVE(); + + @CConstant + public static native int JVMTI_PHASE_DEAD(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java new file mode 100644 index 000000000000..6845bab10374 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct(value = "jvmtiStackInfo", addStructKeyword = true) +public interface JvmtiStackInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java new file mode 100644 index 000000000000..86a506e8139b --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JvmtiStackInfo.class) +public interface JvmtiStackInfoPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackReferenceCallback.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackReferenceCallback.java new file mode 100644 index 000000000000..17f54923a3d4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackReferenceCallback.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; +import org.graalvm.nativeimage.c.type.VoidPointer; + +import com.oracle.svm.core.jni.headers.JNIMethodId; + +public interface JvmtiStackReferenceCallback extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(int heapRootKind, long classTag, long size, CLongPointer tagPtr, long threadTag, int depth, JNIMethodId method, int slot, VoidPointer userData); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStartFunctionPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStartFunctionPointer.java new file mode 100644 index 000000000000..5276357b4273 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStartFunctionPointer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; +import org.graalvm.nativeimage.c.type.CCharPointer; + +import com.oracle.svm.core.jni.headers.JNIObjectHandle; + +public interface JvmtiStartFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + JNIObjectHandle invoke(JvmtiExternalEnv env, CCharPointer name); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java new file mode 100644 index 000000000000..30dab8951306 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiThreadGroupInfo") +public interface JvmtiThreadGroupInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java new file mode 100644 index 000000000000..1d83f56b05b1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiThreadInfo") +public interface JvmtiThreadInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiTimerInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiTimerInfo.java new file mode 100644 index 000000000000..906a86fe2a29 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiTimerInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.word.PointerBase; + +@CContext(JvmtiDirectives.class) +@CStruct("jvmtiTimerInfo") +public interface JvmtiTimerInfo extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java new file mode 100644 index 000000000000..2bcbc8f5ec0a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiVerboseFlag { + @CConstant + public static native int JVMTI_VERBOSE_OTHER(); + + @CConstant + public static native int JVMTI_VERBOSE_GC(); + + @CConstant + public static native int JVMTI_VERBOSE_CLASS(); + + @CConstant + public static native int JVMTI_VERBOSE_JNI(); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVersion.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVersion.java new file mode 100644 index 000000000000..f6e6724b9d2a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVersion.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; + +@CContext(JvmtiDirectives.class) +public final class JvmtiVersion { + private static final int JVMTI_VERSION_INTERFACE_JVMTI = 0x30000000; + private static final int LATEST_SUPPORTED_MAJOR_VERSION = 21; + + public static final int CURRENT_VERSION = JVMTI_VERSION_INTERFACE_JVMTI + LATEST_SUPPORTED_MAJOR_VERSION * 0x10000; + + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiVersion() { + } + + public static boolean isSupported(int version) { + if (isJvmtiVersion(version)) { + return isSupported0(version); + } + return false; + } + + private static boolean isJvmtiVersion(int version) { + return (version & JVMTI_VERSION_MASK_INTERFACE_TYPE()) == JVMTI_VERSION_INTERFACE_JVMTI; + } + + private static boolean isSupported0(int version) { + int major = (version & JVMTI_VERSION_MASK_MAJOR()) >> JVMTI_VERSION_SHIFT_MAJOR(); + int minor = (version & JVMTI_VERSION_MASK_MINOR()) >> JVMTI_VERSION_SHIFT_MINOR(); + /* The "micro" part of the version doesn't matter at the moment. */ + + if (major == 1) { + return minor >= 0 && minor <= 2; + } else if (major == 9 || major == 11) { + return minor == 0; + } else { + /* Since version 13, we do not care about minor versions. */ + return major >= 13 && major <= LATEST_SUPPORTED_MAJOR_VERSION; + } + } + + // Checkstyle: stop: MethodName + + @CConstant + private static native int JVMTI_VERSION_MASK_INTERFACE_TYPE(); + + @CConstant + private static native int JVMTI_VERSION_MASK_MAJOR(); + + @CConstant + private static native int JVMTI_VERSION_MASK_MINOR(); + + @CConstant + private static native int JVMTI_VERSION_SHIFT_MAJOR(); + + @CConstant + private static native int JVMTI_VERSION_SHIFT_MINOR(); + + // Checkstyle: resume +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java index f5ccebf38230..465e3403e658 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java @@ -30,6 +30,7 @@ import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.constant.CEnumValue; import org.graalvm.nativeimage.c.function.CFunction; import com.oracle.svm.core.AlwaysInline; @@ -219,7 +220,7 @@ private void checkCallees(HostedMethod caller, Uninterruptible callerAnnotation, System.lineSeparator() + invoke.getNodeSourcePosition()); } else { if (directCallerAnnotation.calleeMustBe()) { - if (!Uninterruptible.Utils.isUninterruptible(callee)) { + if (!Uninterruptible.Utils.isUninterruptible(callee) && !AnnotationAccess.isAnnotationPresent(callee, CEnumValue.class)) { violations.add("Unannotated callee: " + callee.format("%H.%n(%p):%r") + " called by annotated caller " + caller.format("%H.%n(%p):%r") + System.lineSeparator() + invoke.getNodeSourcePosition()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java new file mode 100644 index 000000000000..671ff6db37e3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.hosted.jvmti; + +import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.function.CEntryPoint; +import org.graalvm.nativeimage.c.function.CFunctionPointer; + +import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.jvmti.JvmtiAgents; +import com.oracle.svm.core.jvmti.JvmtiFunctionTable; +import com.oracle.svm.core.jvmti.JvmtiFunctions; +import com.oracle.svm.core.jvmti.headers.JvmtiInterface; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.option.SubstrateOptionsParser; +import com.oracle.svm.core.util.UserError; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.BeforeCompilationAccessImpl; +import com.oracle.svm.hosted.FeatureImpl.CompilationAccessImpl; +import com.oracle.svm.hosted.c.NativeLibraries; +import com.oracle.svm.hosted.c.info.ElementInfo; +import com.oracle.svm.hosted.c.info.StructFieldInfo; +import com.oracle.svm.hosted.c.info.StructInfo; +import com.oracle.svm.hosted.code.CEntryPointCallStubSupport; +import com.oracle.svm.hosted.code.CEntryPointData; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedType; + +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +@AutomaticallyRegisteredFeature +public class JvmtiFeature implements InternalFeature { + @Override + public boolean isInConfiguration(IsInConfigurationAccess access) { + return SubstrateOptions.JVMTI.getValue(); + } + + @Override + public void duringSetup(DuringSetupAccess access) { + UserError.guarantee(SubstrateOptions.JNI.getValue(), "JVMTI needs JNI, so please enable the option " + SubstrateOptionsParser.commandArgument(SubstrateOptions.JNI, "+")); + } + + @Override + public void beforeAnalysis(BeforeAnalysisAccess arg) { + BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) arg; + AnalysisMetaAccess metaAccess = access.getMetaAccess(); + + ImageSingletons.add(JvmtiAgents.class, new JvmtiAgents()); + + ImageSingletons.add(JvmtiFunctionTable.class, new JvmtiFunctionTable()); + registerCEntryPoints(metaAccess); + } + + private static void registerCEntryPoints(AnalysisMetaAccess metaAccess) { + /* Manually add the CEntryPoints, so that this is only done when JVMTI is enabled. */ + AnalysisType type = metaAccess.lookupJavaType(JvmtiFunctions.class); + for (AnalysisMethod method : type.getDeclaredMethods(false)) { + VMError.guarantee(AnnotationAccess.getAnnotation(method, CEntryPoint.class) != null, "Method %s does not have a @CEntryPoint annotation.", method.format("%H.%n(%p)")); + CEntryPointCallStubSupport.singleton().registerStubForMethod(method, () -> CEntryPointData.create(method)); + } + } + + @Override + public void beforeCompilation(BeforeCompilationAccess a) { + BeforeCompilationAccessImpl access = (BeforeCompilationAccessImpl) a; + fillJvmtiFunctionTable(access); + + /* CFunctionPointers are relocatable, so they must be in the read-only image heap. */ + access.registerAsImmutable(JvmtiFunctionTable.singleton().getReadOnlyFunctionTable()); + } + + private static void fillJvmtiFunctionTable(CompilationAccessImpl access) { + NativeLibraries nativeLibraries = access.getNativeLibraries(); + MetaAccessProvider metaAccess = access.getMetaAccess(); + + ResolvedJavaType jvmtiInterface = metaAccess.lookupJavaType(JvmtiInterface.class); + StructInfo jvmtiInterfaceMetadata = (StructInfo) nativeLibraries.findElementInfo(jvmtiInterface); + + JvmtiFunctionTable functionTable = JvmtiFunctionTable.singleton(); + HostedType type = access.getMetaAccess().lookupJavaType(JvmtiFunctions.class); + for (HostedMethod method : type.getDeclaredMethods(false)) { + StructFieldInfo field = findFieldFor(jvmtiInterfaceMetadata, method.getName()); + int offset = field.getOffsetInfo().getProperty(); + functionTable.init(offset, getStubFunctionPointer(access, method)); + } + } + + private static CFunctionPointer getStubFunctionPointer(CompilationAccessImpl access, HostedMethod method) { + AnalysisMethod stub = CEntryPointCallStubSupport.singleton().getStubForMethod(method.getWrapped()); + return new MethodPointer(access.getUniverse().lookup(stub)); + } + + private static StructFieldInfo findFieldFor(StructInfo info, String name) { + for (ElementInfo element : info.getChildren()) { + if (element instanceof StructFieldInfo field) { + if (field.getName().equals(name)) { + return field; + } + } + } + throw VMError.shouldNotReachHere("Cannot find function table field for: " + name); + } +} From 6bb17985771fe08cb3b78e63f7f77e1fb62174a7 Mon Sep 17 00:00:00 2001 From: David Pedrucci Date: Mon, 4 Mar 2024 12:59:17 +0100 Subject: [PATCH 2/3] Implement more JVMTI features. --- .../oracle/svm/core/genscavenge/GCImpl.java | 3 + .../svm/core/genscavenge/ImageHeapWalker.java | 2 +- .../com/oracle/svm/core/SubstrateOptions.java | 10 +- .../graal/snippets/CEntryPointSnippets.java | 9 + .../oracle/svm/core/headers/LibCSupport.java | 2 +- .../com/oracle/svm/core/hub/DynamicHub.java | 1 + .../oracle/svm/core/jdk/NativeLibraries.java | 2 +- .../svm/core/jdk/UninterruptibleUtils.java | 38 + .../core/jni/access/JNIAccessibleField.java | 2 +- .../core/jni/access/JNIAccessibleMethod.java | 6 +- .../jni/access/JNIReflectionDictionary.java | 73 ++ .../jni/functions/JNIInvocationInterface.java | 5 +- .../oracle/svm/core/jvmti/JvmtiAgents.java | 2 +- .../svm/core/jvmti/JvmtiCapabilitiesEnum.java | 77 ++ .../svm/core/jvmti/JvmtiCapabilitiesUtil.java | 299 +++++++- .../svm/core/jvmti/JvmtiClassInfoUtil.java | 674 ++++++++++++++++++ .../com/oracle/svm/core/jvmti/JvmtiEnv.java | 21 + .../svm/core/jvmti/JvmtiEnvEventEnabled.java | 50 ++ .../core/jvmti/JvmtiEnvEventEnabledUtils.java | 93 +++ .../svm/core/jvmti/JvmtiEnvManager.java | 178 +++++ .../oracle/svm/core/jvmti/JvmtiEnvShared.java | 38 + .../svm/core/jvmti/JvmtiEnvSharedUtil.java | 234 ++++++ .../svm/core/jvmti/JvmtiEnvStorage.java | 77 ++ .../oracle/svm/core/jvmti/JvmtiEnvUtil.java | 133 +++- .../core/jvmti/JvmtiEventCallbacksUtil.java | 77 ++ .../svm/core/jvmti/JvmtiFunctionTable.java | 2 +- .../oracle/svm/core/jvmti/JvmtiFunctions.java | 349 ++++++--- .../jvmti/JvmtiGenericInfoMapFeature.java | 45 ++ .../svm/core/jvmti/JvmtiGetThreadsUtil.java | 169 +++++ .../oracle/svm/core/jvmti/JvmtiManager.java | 52 ++ .../svm/core/jvmti/JvmtiMemoryManager.java | 30 + .../core/jvmti/JvmtiMultiStackTracesUtil.java | 347 +++++++++ .../svm/core/jvmti/JvmtiObjectInfoUttil.java | 99 +++ .../svm/core/jvmti/JvmtiPostEvents.java | 225 ++++++ .../svm/core/jvmti/JvmtiRawMonitorUtil.java | 265 +++++++ .../svm/core/jvmti/JvmtiStackTraceUtil.java | 368 ++++++++++ .../core/jvmti/JvmtiThreadActionsUtil.java | 109 +++ .../svm/core/jvmti/JvmtiThreadGroupUtil.java | 291 ++++++++ .../core/jvmti/JvmtiThreadLocalStorage.java | 109 +++ .../svm/core/jvmti/JvmtiThreadStateUtil.java | 201 ++++++ .../core/jvmti/headers/BooleanPointer.java | 33 + .../headers/JThreadGroupPointerPointer.java | 30 + .../svm/core/jvmti/headers/JvmtiError.java | 55 ++ .../svm/core/jvmti/headers/JvmtiEvent.java | 77 +- .../jvmti/headers/JvmtiEventCallbacks.java | 57 +- .../core/jvmti/headers/JvmtiFrameInfo.java | 18 +- .../jvmti/headers/JvmtiFrameInfoPointer.java | 33 + .../core/jvmti/headers/JvmtiStackInfo.java | 25 + .../headers/JvmtiStackInfoPointerPointer.java | 32 + .../jvmti/headers/JvmtiThreadGroupInfo.java | 26 + .../core/jvmti/headers/JvmtiThreadInfo.java | 34 + .../core/jvmti/headers/JvmtiThreadState.java | 51 ++ .../jvmti/headers/VoidPointerPointer.java | 33 + .../jvmti/utils/JvmtiLocalStorageUtil.java | 86 +++ .../utils/JvmtiUninterruptibleUtils.java | 71 ++ .../svm/core/jvmti/utils/JvmtiUtils.java | 68 ++ .../svm/core/jvmti/utils/NonmovableMap.java | 58 ++ .../svm/core/jvmti/utils/NonmovableMaps.java | 170 +++++ .../oracle/svm/core/monitor/JavaMonitor.java | 3 +- .../JavaMonitorQueuedSynchronizer.java | 6 +- .../core/monitor/JvmtiRawMonitorHelper.java | 54 ++ .../core/monitor/MonitorInflationCause.java | 10 +- .../com/oracle/svm/core/nmt/NmtCategory.java | 2 + .../Target_java_lang_reflect_Method.java | 3 + .../JavaLangThreadGroupSubstitutions.java | 2 +- .../oracle/svm/core/thread/JavaThreads.java | 6 + .../svm/core/thread/PlatformThreads.java | 7 +- .../hosted/ameta/HostedDynamicHubFeature.java | 20 +- .../oracle/svm/hosted/jvmti/JvmtiFeature.java | 16 +- 69 files changed, 5635 insertions(+), 218 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index df8ca685efbb..1567c4ac6011 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -31,6 +31,7 @@ import java.lang.ref.Reference; +import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -177,6 +178,8 @@ public void collectionHint(boolean fullGC) { private void collect(GCCause cause, boolean forceFullGC) { if (!hasNeverCollectPolicy()) { + JvmtiPostEvents.postGarbageCollectionStart(); + JvmtiPostEvents.postGarbageCollectionFinish(); boolean outOfMemory = collectWithoutAllocating(cause, forceFullGC); if (outOfMemory) { throw OutOfMemoryUtil.heapSizeExceeded(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index da58392793c8..bac30ab1adf6 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -127,7 +127,7 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject @Uninterruptible(reason = "Bridge between uninterruptible and potentially interruptible code.", mayBeInlined = true, calleeMustBe = false) private static boolean visitObject(ObjectVisitor visitor, Object currentObject) { - return visitor.visitObject(currentObject); + return visitor. visitObject(currentObject); } @AlwaysInline("de-virtualize calls to ObjectReferenceVisitor") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 53134aa8b445..410d133efda6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -634,16 +634,16 @@ public static void updateMaxJavaStackTraceDepth(EconomicMap, Object @Option(help = "Enable JVM Tool Interface (JVMTI) support.", type = OptionType.User)// public static final HostedOptionKey JVMTI = new HostedOptionKey<>(false); - // TEMP (chaeubl): we need to support multiple values - @Option(help = "Loads the specified native agent library specified by the absolute path name. " + - "After the library path, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// - public static final RuntimeOptionKey AgentPath = new RuntimeOptionKey<>(null); - // TEMP (chaeubl): we need to support multiple values @Option(help = "Loads the specified native agent library. " + "After the library name, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// public static final RuntimeOptionKey AgentLib = new RuntimeOptionKey<>(null); + // TEMP (chaeubl): we need to support multiple values + @Option(help = "Loads the specified native agent library specified by the absolute path name. " + + "After the library path, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// + public static final RuntimeOptionKey AgentPath = new RuntimeOptionKey<>(null); + @Option(help = "Alignment of AOT and JIT compiled code in bytes.")// public static final HostedOptionKey CodeAlignment = new HostedOptionKey<>(16); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 36d1b21669d5..1d91fc5c4adf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -32,6 +32,9 @@ import java.util.Map; +import com.oracle.svm.core.jvmti.JvmtiEnvManager; +import com.oracle.svm.core.jvmti.JvmtiManager; +import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -399,6 +402,9 @@ private static int initializeIsolateInterruptibly1(CEntryPointCreateIsolateParam if (SubstrateOptions.JVMTI.getValue()) { JvmtiAgents.singleton().load(); + + //JvmtiPostEvents.postVMInit(); + JvmtiPostEvents.postVMStart(); } assert !isolateInitialized; @@ -633,9 +639,12 @@ private static boolean initiateTearDownIsolateInterruptibly() { VMThreads.singleton().threadExit(); if (SubstrateOptions.JVMTI.getValue()) { + JvmtiPostEvents.postVMDeath(); + JvmtiManager.freeAllJvmtiClassesUnmanagedMemory(); JvmtiAgents.singleton().unload(); } + return true; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java index b7ed0b46fdae..73026953fa9c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java @@ -34,7 +34,7 @@ import com.oracle.svm.core.memory.NativeMemory; /** Platform-independent LibC support. Don't use this class directly, use {@link LibC} instead. */ -public interface LibCSupport { +public interface LibCSupport { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) int errno(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index a2c6fc6fb67e..3ca8589e8a5e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -1843,6 +1843,7 @@ private ClassRepository getGenericInfo() { return companion.getGenericInfo(this); } + ClassRepository computeGenericInfo() { String genericSignature = getGenericSignature0(); if (genericSignature == null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NativeLibraries.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NativeLibraries.java index 1ca906d0d49f..5daa87344382 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NativeLibraries.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/NativeLibraries.java @@ -68,7 +68,7 @@ protected static PointerBase findSymbol(Collection> hidingSubclasses, int vtableOffsetEntry, int interfaceTypeIDEntry, CodePointer nonvirtualEntry, PointerBase newObjectEntry, CodePointer callWrapperEntry, CodePointer varargs, CodePointer array, CodePointer valist, CodePointer varargsNonvirtual, CodePointer arrayNonvirtual, diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java index fcf53ecaddb6..c0cb468e6be1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java @@ -28,7 +28,11 @@ import static com.oracle.svm.core.SubstrateOptions.JNIVerboseLookupErrors; import java.io.PrintStream; +import java.util.ArrayList; +import java.util.HashSet; import java.util.Map; +import java.util.Random; +import java.util.Set; import java.util.function.Function; import org.graalvm.collections.EconomicMap; @@ -251,6 +255,75 @@ private JNIAccessibleMethod getDeclaredMethod(Class classObject, JNIAccessibl return method; } + public void printall(){ + classesByClassObject.getKeys().forEach(System.out::println); + } + // TODO @dprcci REMOVE! + public JNIMethodId getRandomMethodID() { + Iterable accessibleClass = classesByClassObject.getValues(); + ArrayList classList = new ArrayList<>(); + accessibleClass.forEach(classList::add); + +// Get random class + Random random = new Random(); + JNIAccessibleClass randomClass = null; + if (!classList.isEmpty()) { + int randomIndex = random.nextInt(classList.size()); + randomClass = classList.get(randomIndex); + } + if (randomClass == null) { + return WordFactory.nullPointer(); + } + MapCursor cursor = randomClass.getMethods(); + if (cursor.advance()) { + return toMethodID(cursor.getValue()); + } else { + return WordFactory.nullPointer(); + } + } + + // TODO @dprcci JVMTI is this correct or should reflection be used? It is assumed the internals + // should not be exposed to the user + public JNIMethodId toMethodID(Class clazz, String methodName) { + //Log.log().string(clazz.getName()); + JNIAccessibleClass accessibleClass = classesByClassObject.get(clazz); + if (accessibleClass == null) { + return WordFactory.nullPointer(); + } + boolean found = false; + MapCursor cursor = accessibleClass.getMethods(); + while (!found && cursor.advance()) { + found = cursor.getKey().getName().equals(methodName); + } + return toMethodID(found ? cursor.getValue() : null); + } + + // TODO @dprcci + @Platforms(HOSTED_ONLY.class) + public Set> getRegisteredClasses() { + Set> res = new HashSet<>(); + classesByClassObject.getKeys().forEach(res::add); + return res; + } + + // TODO @dprcci + public static boolean isMethodNative(JNIMethodId methodId) { + return getMethodByID(methodId).isNative(); + } + + public boolean isValidMethodIdSlow(JNIMethodId methodId){ + Iterable classIterator = classesByClassObject.getValues(); + for (JNIAccessibleClass c : classIterator){ + MapCursor cursor = c.getMethods(); + while(cursor.advance()){ + if(toMethodID(cursor.getValue()).equal(methodId)){ + return true; + } + } + } + return false; + } + public JNIMethodId getMethodID(Class classObject, CharSequence name, CharSequence signature, boolean isStatic) { JNIAccessibleMethod method = findMethod(classObject, new JNIAccessibleMethodDescriptor(name, signature), "getMethodID"); method = checkMethod(method, classObject, name, signature); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java index 6bd7e7553097..f400118ac59f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java @@ -68,7 +68,7 @@ import com.oracle.svm.core.jni.headers.JNIJavaVMOption; import com.oracle.svm.core.jni.headers.JNIJavaVMPointer; import com.oracle.svm.core.jni.headers.JNIVersion; -import com.oracle.svm.core.jvmti.JvmtiEnvUtil; +import com.oracle.svm.core.jvmti.JvmtiEnvManager; import com.oracle.svm.core.jvmti.headers.JvmtiVersion; import com.oracle.svm.core.log.FunctionPointerLogHandler; import com.oracle.svm.core.memory.UntrackedNullableNativeMemory; @@ -294,7 +294,8 @@ static int DestroyJavaVM(JNIJavaVM vm) { @SuppressWarnings("unused") static int GetEnv(JNIJavaVM vm, WordPointer env, int version) { if (SubstrateOptions.JVMTI.getValue() && JvmtiVersion.isSupported(version)) { - env.write(JvmtiEnvUtil.allocate()); + JvmtiEnvManager envManager = JvmtiEnvManager.singleton(); + envManager.createJvmtiEnv(env); return JNIErrors.JNI_OK(); } else if (JNIVersion.isSupported(version, false)) { env.write(JNIThreadLocalEnvironment.getAddress()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java index d265451b2436..670aaf3e0db0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java @@ -29,7 +29,7 @@ import java.io.Serial; import java.util.ArrayList; -import org.graalvm.compiler.api.replacements.Fold; +import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java new file mode 100644 index 000000000000..4fd4fa287afa --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +public enum JvmtiCapabilitiesEnum { + CAN_TAG_OBJECTS, + CAN_GENERATE_FIELD_MODIFICATION_EVENTS, + CAN_GENERATE_FIELD_ACCESS_EVENTS, + CAN_GET_BYTECODES, + CAN_GET_SYNTHETIC_ATTRIBUTE, + CAN_GET_OWNED_MONITOR_INFO, + CAN_GET_CURRENT_CONTENDED_MONITOR, + CAN_GET_MONITOR_INFO, + CAN_POP_FRAME, + CAN_REDEFINE_CLASSES, + CAN_SIGNAL_THREAD, + CAN_GET_SOURCE_FILE_NAME, + CAN_GET_LINE_NUMBERS, + CAN_GET_SOURCE_DEBUG_EXTENSION, + CAN_ACCESS_LOCAL_VARIABLES, + CAN_MAINTAIN_ORIGINAL_METHOD_ORDER, + CAN_GENERATE_SINGLE_STEP_EVENTS, + CAN_GENERATE_EXCEPTION_EVENTS, + CAN_GENERATE_FRAME_POP_EVENTS, + CAN_GENERATE_BREAKPOINT_EVENTS, + CAN_SUSPEND, + CAN_REDEFINE_ANY_CLASS, + CAN_GET_CURRENT_THREAD_CPU_TIME, + CAN_GET_THREAD_CPU_TIME, + CAN_GENERATE_METHOD_ENTRY_EVENTS, + CAN_GENERATE_METHOD_EXIT_EVENTS, + CAN_GENERATE_ALL_CLASS_HOOK_EVENTS, + CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS, + CAN_GENERATE_MONITOR_EVENTS, + CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS, + CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS, + CAN_GENERATE_GARBAGE_COLLECTION_EVENTS, + CAN_GENERATE_OBJECT_FREE_EVENTS, + CAN_FORCE_EARLY_RETURN, + CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO, + CAN_GET_CONSTANT_POOL, + CAN_SET_NATIVE_METHOD_PREFIX, + CAN_RETRANSFORM_CLASSES, + CAN_RETRANSFORM_ANY_CLASS, + CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS, + CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS, + CAN_GENERATE_EARLY_VMSTART, + CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS, + CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS, + CAN_SUPPORT_VIRTUAL_THREADS; + + public static long getBit(JvmtiCapabilitiesEnum capability) { + return 1L << capability.ordinal(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java index feedc76632cc..f67226a3afb2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.core.jvmti; +import static com.oracle.svm.core.jvmti.JvmtiEnvSharedUtil.SHARED_CAPABILITIES_TYPE; + import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.SizeOf; @@ -31,8 +33,12 @@ import com.oracle.svm.core.UnmanagedMemoryUtil; import com.oracle.svm.core.jvmti.headers.JvmtiCapabilities; +import com.oracle.svm.core.jvmti.headers.JvmtiError; public final class JvmtiCapabilitiesUtil { + + private static final JvmtiCapabilitiesEnum[] allCapabilitiesEnumValues = JvmtiCapabilitiesEnum.values(); + @Platforms(Platform.HOSTED_ONLY.class) private JvmtiCapabilitiesUtil() { } @@ -40,13 +46,22 @@ private JvmtiCapabilitiesUtil() { public static boolean hasAny(JvmtiCapabilities capabilities) { assert capabilities.isNonNull(); - Pointer rawData = (Pointer) capabilities; - for (int i = 0; i < SizeOf.get(JvmtiCapabilities.class); i++) { - if (rawData.readByte(i) != 0) { + for (JvmtiCapabilitiesEnum cap : allCapabilitiesEnumValues) { + if (getCapability(cap, capabilities)) { return true; } } return false; + // TODO @dprcci keep old implementation? + /* + * Pointer rawData = (Pointer) capabilities; for (int i = 0; i < + * SizeOf.get(JvmtiCapabilities.class); i++) { if (rawData.readByte(i) != 0) { return true; + * } } return false; + */ + } + + static boolean hasCapability(JvmtiCapabilities capabilities, JvmtiCapabilitiesEnum desired){ + return getCapability(desired, capabilities); } public static void clear(JvmtiCapabilities capabilities) { @@ -57,4 +72,282 @@ public static void clear(JvmtiCapabilities capabilities) { public static void copy(JvmtiCapabilities src, JvmtiCapabilities dst) { UnmanagedMemoryUtil.copyForward((Pointer) src, (Pointer) dst, SizeOf.unsigned(JvmtiCapabilities.class)); } + + public static void initSharedCapabilities(JvmtiEnvShared envShared) { + for (SHARED_CAPABILITIES_TYPE type : SHARED_CAPABILITIES_TYPE.values()) { + setSharedCapabilityFromBitVector(envShared, type, type.getInitial()); + } + } + + public static JvmtiError relinquishCapabilities(JvmtiEnvShared sharedCapabilities, JvmtiCapabilities current, JvmtiCapabilities unwanted) { + long alwaysSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO); + long onLoadSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO); + long onLoadSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING); + long alwaysSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING); + + long currentBitVector = convertCapabilitiesToBitVector(current); + long unwantedBitVector = convertCapabilitiesToBitVector(unwanted); + long toTrash, temp; + + toTrash = both(currentBitVector, unwantedBitVector); + temp = both(alwaysSoloBitVector, toTrash); + alwaysSoloRemainingBitVector = either(alwaysSoloRemainingBitVector, temp); + temp = both(onLoadSoloBitVector, toTrash); + onLoadSoloRemainingBitVector = either(onLoadSoloRemainingBitVector, temp); + + // TODO dprcci add virtual thread support + + update(); + + temp = exclude(currentBitVector, unwantedBitVector); + + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO, alwaysSoloBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO, onLoadSoloBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING, alwaysSoloRemainingBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING, onLoadSoloRemainingBitVector); + + assignBitVectoToCapabilities(current, temp); + + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getPotentialCapabilities(int phase, JvmtiCapabilities current, JvmtiCapabilities prohibited, JvmtiEnvShared sharedCapabilities, JvmtiCapabilities result) { + long always = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS); + long alwaysSoloRemaining = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING); + long onLoad = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD); + long onLoadSoloRemaining = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING); + + long currentVector = convertCapabilitiesToBitVector(current); + long prohibitedVector = convertCapabilitiesToBitVector(prohibited); + + long potentialVector = computePotentialBitVector(phase, currentVector, prohibitedVector, always, alwaysSoloRemaining, onLoad, onLoadSoloRemaining); + assignBitVectoToCapabilities(result, potentialVector); + + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError addCapabilities(int phase, JvmtiEnvShared sharedCapabilities, JvmtiCapabilities current, JvmtiCapabilities prohibited, JvmtiCapabilities desired) { + + long alwaysBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS); + long alwaysSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO); + long onLoadBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD); + long onLoadSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO); + long onLoadSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING); + long alwaysSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING); + long acquiredBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ACQUIRED); + + long currentBitVector = convertCapabilitiesToBitVector(current); + long prohibitedBitVector = convertCapabilitiesToBitVector(prohibited); + long desiredBitVector = convertCapabilitiesToBitVector(desired); + + long temp = computePotentialBitVector(phase, currentBitVector, prohibitedBitVector, + alwaysBitVector, alwaysSoloRemainingBitVector, onLoadBitVector, onLoadSoloRemainingBitVector); + + if (hasSome(exclude(desiredBitVector, temp))) { + return JvmtiError.JVMTI_ERROR_NOT_AVAILABLE; + } + + acquiredBitVector = either(acquiredBitVector, desiredBitVector); + + // onload capabilities that got added are now permanent - so, also remove from onload + temp = both(onLoadBitVector, desiredBitVector); + alwaysBitVector = either(alwaysBitVector, temp); + onLoadBitVector = exclude(onLoadBitVector, temp); + + // same for solo capabilities (transferred capabilities in the remaining sets handled as + // part of standard grab - below) + temp = both(onLoadSoloBitVector, desiredBitVector); + alwaysSoloBitVector = either(alwaysSoloBitVector, temp); + onLoadSoloBitVector = exclude(onLoadSoloBitVector, temp); + + // remove solo capabilities that are now taken + alwaysSoloRemainingBitVector = exclude(alwaysSoloRemainingBitVector, desiredBitVector); + onLoadSoloRemainingBitVector = exclude(onLoadSoloRemainingBitVector, desiredBitVector); + + // TODO dprcci add virtual thread support + + // return the result + temp = either(currentBitVector, desiredBitVector); + update(); + + // update shared capabilities + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS, alwaysBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO, alwaysSoloBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD, onLoadBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO, onLoadSoloBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING, onLoadSoloRemainingBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING, alwaysSoloRemainingBitVector); + setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ACQUIRED, acquiredBitVector); + + // write result back + assignBitVectoToCapabilities(current, temp); + + return JvmtiError.JVMTI_ERROR_NONE; + } + + // TODO @dprcci implement + private static void update() { + } + + private static long computePotentialBitVector(int phase, long current, long prohibited, + long always, long alwaysSoloRemaining, long onLoad, long onLoadSoloRemaining) { + long potential; + + potential = exclude(always, prohibited); + potential = either(potential, current); + potential = either(potential, alwaysSoloRemaining); // TODO @dprcci checck + + // TODO @dprcci temporarily disabled for tests + // if (phase == JvmtiPhase.JVMTI_PHASE_ONLOAD()) { + if (true) { + potential = either(potential, onLoad); + potential = either(potential, onLoadSoloRemaining); + } + return potential; + } + + private static long getBitVectorFromSharedCapability(JvmtiEnvShared sharedCapability, SHARED_CAPABILITIES_TYPE type) { + return convertCapabilitiesToBitVector(JvmtiEnvSharedUtil.getSharedCapability(sharedCapability, type)); + } + + private static void setSharedCapabilityFromBitVector(JvmtiEnvShared sharedCapability, SHARED_CAPABILITIES_TYPE type, long bitVector) { + assignBitVectoToCapabilities(JvmtiEnvSharedUtil.getSharedCapability(sharedCapability, type), bitVector); + } + + private static void assignBitVectoToCapabilities(JvmtiCapabilities capabilities, long capabilityBitVector) { + for (JvmtiCapabilitiesEnum cap : allCapabilitiesEnumValues) { + boolean value = ((1L << cap.ordinal()) & capabilityBitVector) != 0; + setCapability(cap, capabilities, value); + } + } + + private static long convertCapabilitiesToBitVector(JvmtiCapabilities capabilities) { + long capabilitiesVector = 0L; + for (JvmtiCapabilitiesEnum cap : allCapabilitiesEnumValues) { + if (getCapability(cap, capabilities)) { + capabilitiesVector |= 1L << cap.ordinal(); + } + } + return capabilitiesVector; + } + + private static void setCapability(JvmtiCapabilitiesEnum cap, JvmtiCapabilities capabilities, boolean value) { + switch (cap) { + case CAN_TAG_OBJECTS -> capabilities.setCanTagObjects(value); + case CAN_GENERATE_FIELD_MODIFICATION_EVENTS -> capabilities.setCanGenerateFieldModificationEvents(value); + case CAN_GENERATE_FIELD_ACCESS_EVENTS -> capabilities.setCanGenerateFieldAccessEvents(value); + case CAN_GET_BYTECODES -> capabilities.setCanGetBytecodes(value); + case CAN_GET_SYNTHETIC_ATTRIBUTE -> capabilities.setCanGetSyntheticAttribute(value); + case CAN_GET_OWNED_MONITOR_INFO -> capabilities.setCanGetOwnedMonitorInfo(value); + case CAN_GET_CURRENT_CONTENDED_MONITOR -> capabilities.setCanGetCurrentContendedMonitor(value); + case CAN_GET_MONITOR_INFO -> capabilities.setCanGetMonitorInfo(value); + case CAN_POP_FRAME -> capabilities.setCanPopFrame(value); + case CAN_REDEFINE_CLASSES -> capabilities.setCanRedefineClasses(value); + case CAN_SIGNAL_THREAD -> capabilities.setCanSignalThread(value); + case CAN_GET_SOURCE_FILE_NAME -> capabilities.setCanGetSourceFileName(value); + case CAN_GET_LINE_NUMBERS -> capabilities.setCanGetLineNumbers(value); + case CAN_GET_SOURCE_DEBUG_EXTENSION -> capabilities.setCanGetSourceDebugExtension(value); + case CAN_ACCESS_LOCAL_VARIABLES -> capabilities.setCanAccessLocalVariables(value); + case CAN_MAINTAIN_ORIGINAL_METHOD_ORDER -> capabilities.setCanMaintainOriginalMethodOrder(value); + case CAN_GENERATE_SINGLE_STEP_EVENTS -> capabilities.setCanGenerateSingleStepEvents(value); + case CAN_GENERATE_EXCEPTION_EVENTS -> capabilities.setCanGenerateExceptionEvents(value); + case CAN_GENERATE_FRAME_POP_EVENTS -> capabilities.setCanGenerateFramePopEvents(value); + case CAN_GENERATE_BREAKPOINT_EVENTS -> capabilities.setCanGenerateBreakpointEvents(value); + case CAN_SUSPEND -> capabilities.setCanSuspend(value); + case CAN_REDEFINE_ANY_CLASS -> capabilities.setCanRedefineAnyClass(value); + case CAN_GET_CURRENT_THREAD_CPU_TIME -> capabilities.setCanGetCurrentThreadCpuTime(value); + case CAN_GET_THREAD_CPU_TIME -> capabilities.setCanGetThreadCpuTime(value); + case CAN_GENERATE_METHOD_ENTRY_EVENTS -> capabilities.setCanGenerateMethodEntryEvents(value); + case CAN_GENERATE_METHOD_EXIT_EVENTS -> capabilities.setCanGenerateMethodExitEvents(value); + case CAN_GENERATE_ALL_CLASS_HOOK_EVENTS -> capabilities.setCanGenerateAllClassHookEvents(value); + case CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS -> capabilities.setCanGenerateCompiledMethodLoadEvents(value); + case CAN_GENERATE_MONITOR_EVENTS -> capabilities.setCanGenerateMonitorEvents(value); + case CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS -> capabilities.setCanGenerateVmObjectAllocEvents(value); + case CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS -> capabilities.setCanGenerateNativeMethodBindEvents(value); + case CAN_GENERATE_GARBAGE_COLLECTION_EVENTS -> capabilities.setCanGenerateGarbageCollectionEvents(value); + case CAN_GENERATE_OBJECT_FREE_EVENTS -> capabilities.setCanGenerateObjectFreeEvents(value); + case CAN_FORCE_EARLY_RETURN -> capabilities.setCanForceEarlyReturn(value); + case CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO -> capabilities.setCanGetOwnedMonitorStackDepthInfo(value); + case CAN_GET_CONSTANT_POOL -> capabilities.setCanGetConstantPool(value); + case CAN_SET_NATIVE_METHOD_PREFIX -> capabilities.setCanSetNativeMethodPrefix(value); + case CAN_RETRANSFORM_CLASSES -> capabilities.setCanRetransformClasses(value); + case CAN_RETRANSFORM_ANY_CLASS -> capabilities.setCanRetransformAnyClass(value); + case CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS -> capabilities.setCanGenerateResourceExhaustionHeapEvents(value); + case CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS -> capabilities.setCanGenerateResourceExhaustionThreadsEvents(value); + case CAN_GENERATE_EARLY_VMSTART -> capabilities.setCanGenerateEarlyVmstart(value); + case CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS -> capabilities.setCanGenerateEarlyClassHookEvents(value); + case CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS -> capabilities.setCanGenerateSampledObjectAllocEvents(value); + case CAN_SUPPORT_VIRTUAL_THREADS -> capabilities.setCanSupportVirtualThreads(value); + default -> { + } + } + } + + private static boolean getCapability(JvmtiCapabilitiesEnum cap, JvmtiCapabilities capabilities) { + return switch (cap) { + case CAN_TAG_OBJECTS -> capabilities.getCanTagObjects(); + case CAN_GENERATE_FIELD_MODIFICATION_EVENTS -> capabilities.getCanGenerateFieldModificationEvents(); + case CAN_GENERATE_FIELD_ACCESS_EVENTS -> capabilities.getCanGenerateFieldAccessEvents(); + case CAN_GET_BYTECODES -> capabilities.getCanGetBytecodes(); + case CAN_GET_SYNTHETIC_ATTRIBUTE -> capabilities.getCanGetSyntheticAttribute(); + case CAN_GET_OWNED_MONITOR_INFO -> capabilities.getCanGetOwnedMonitorInfo(); + case CAN_GET_CURRENT_CONTENDED_MONITOR -> capabilities.getCanGetCurrentContendedMonitor(); + case CAN_GET_MONITOR_INFO -> capabilities.getCanGetMonitorInfo(); + case CAN_POP_FRAME -> capabilities.getCanPopFrame(); + case CAN_REDEFINE_CLASSES -> capabilities.getCanRedefineClasses(); + case CAN_SIGNAL_THREAD -> capabilities.getCanSignalThread(); + case CAN_GET_SOURCE_FILE_NAME -> capabilities.getCanGetSourceFileName(); + case CAN_GET_LINE_NUMBERS -> capabilities.getCanGetLineNumbers(); + case CAN_GET_SOURCE_DEBUG_EXTENSION -> capabilities.getCanGetSourceDebugExtension(); + case CAN_ACCESS_LOCAL_VARIABLES -> capabilities.getCanAccessLocalVariables(); + case CAN_MAINTAIN_ORIGINAL_METHOD_ORDER -> capabilities.getCanMaintainOriginalMethodOrder(); + case CAN_GENERATE_SINGLE_STEP_EVENTS -> capabilities.getCanGenerateSingleStepEvents(); + case CAN_GENERATE_EXCEPTION_EVENTS -> capabilities.getCanGenerateExceptionEvents(); + case CAN_GENERATE_FRAME_POP_EVENTS -> capabilities.getCanGenerateFramePopEvents(); + case CAN_GENERATE_BREAKPOINT_EVENTS -> capabilities.getCanGenerateBreakpointEvents(); + case CAN_SUSPEND -> capabilities.getCanSuspend(); + case CAN_REDEFINE_ANY_CLASS -> capabilities.getCanRedefineAnyClass(); + case CAN_GET_CURRENT_THREAD_CPU_TIME -> capabilities.getCanGetCurrentThreadCpuTime(); + case CAN_GET_THREAD_CPU_TIME -> capabilities.getCanGetThreadCpuTime(); + case CAN_GENERATE_METHOD_ENTRY_EVENTS -> capabilities.getCanGenerateMethodEntryEvents(); + case CAN_GENERATE_METHOD_EXIT_EVENTS -> capabilities.getCanGenerateMethodExitEvents(); + case CAN_GENERATE_ALL_CLASS_HOOK_EVENTS -> capabilities.getCanGenerateAllClassHookEvents(); + case CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS -> capabilities.getCanGenerateCompiledMethodLoadEvents(); + case CAN_GENERATE_MONITOR_EVENTS -> capabilities.getCanGenerateMonitorEvents(); + case CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS -> capabilities.getCanGenerateVmObjectAllocEvents(); + case CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS -> capabilities.getCanGenerateNativeMethodBindEvents(); + case CAN_GENERATE_GARBAGE_COLLECTION_EVENTS -> capabilities.getCanGenerateGarbageCollectionEvents(); + case CAN_GENERATE_OBJECT_FREE_EVENTS -> capabilities.getCanGenerateObjectFreeEvents(); + case CAN_FORCE_EARLY_RETURN -> capabilities.getCanForceEarlyReturn(); + case CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO -> capabilities.getCanGetOwnedMonitorStackDepthInfo(); + case CAN_GET_CONSTANT_POOL -> capabilities.getCanGetConstantPool(); + case CAN_SET_NATIVE_METHOD_PREFIX -> capabilities.getCanSetNativeMethodPrefix(); + case CAN_RETRANSFORM_CLASSES -> capabilities.getCanRetransformClasses(); + case CAN_RETRANSFORM_ANY_CLASS -> capabilities.getCanRetransformAnyClass(); + case CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS -> capabilities.getCanGenerateResourceExhaustionHeapEvents(); + case CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS -> capabilities.getCanGenerateResourceExhaustionThreadsEvents(); + case CAN_GENERATE_EARLY_VMSTART -> capabilities.getCanGenerateEarlyVmstart(); + case CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS -> capabilities.getCanGenerateEarlyClassHookEvents(); + case CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS -> capabilities.getCanGenerateSampledObjectAllocEvents(); + case CAN_SUPPORT_VIRTUAL_THREADS -> capabilities.getCanSupportVirtualThreads(); + // has to be there for no memory alloc + default -> false; + }; + } + + private static boolean hasSome(long a) { + return a != 0L; + } + + private static long both(long a, long b) { + return a & b; + } + + private static long either(long a, long b) { + return a | b; + } + + private static long exclude(long a, long b) { + return a & ~b; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java new file mode 100644 index 000000000000..11017ff691eb --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.jvmti.utils.JvmtiUninterruptibleUtils.ReplaceDotWithSlash; +import static com.oracle.svm.core.jvmti.utils.JvmtiUninterruptibleUtils.writeStringToCCharArray; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; +import java.util.Objects; +import java.util.Set; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.CCharPointerPointer; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.ComparableWord; +import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.jdk.JavaLangSubstitutions; +import com.oracle.svm.core.jdk.UninterruptibleUtils; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.access.JNIAccessibleMethod; +import com.oracle.svm.core.jni.access.JNIAccessibleMethodDescriptor; +import com.oracle.svm.core.jni.access.JNIReflectionDictionary; +import com.oracle.svm.core.jni.headers.JNIFieldId; +import com.oracle.svm.core.jni.headers.JNIFieldIdPointer; +import com.oracle.svm.core.jni.headers.JNIFieldIdPointerPointer; +import com.oracle.svm.core.jni.headers.JNIMethodId; +import com.oracle.svm.core.jni.headers.JNIMethodIdPointer; +import com.oracle.svm.core.jni.headers.JNIMethodIdPointerPointer; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.BooleanPointer; +import com.oracle.svm.core.jvmti.headers.JClass; +import com.oracle.svm.core.jvmti.headers.JClassPointer; +import com.oracle.svm.core.jvmti.headers.JClassPointerPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.locks.VMMutex; +import com.oracle.svm.core.reflect.target.Target_java_lang_reflect_Method; + +import jdk.graal.compiler.api.replacements.Fold; + +public final class JvmtiClassInfoUtil { + + private static final byte JNI_FALSE = 0; + private static final byte JNI_TRUE = 1; + private static final int MAX_SIGNATURE_LENGTH = 256; + private final char[] signatureCharBuffer; + private final ReplaceDotWithSlash nameToSigReplacer = new ReplaceDotWithSlash(); + private final VMMutex mutex = new VMMutex("jvmtiGetClassSignature"); + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiClassInfoUtil() { + this.signatureCharBuffer = new char[MAX_SIGNATURE_LENGTH]; + } + + @Fold + public static JvmtiClassInfoUtil singleton() { + return ImageSingletons.lookup(JvmtiClassInfoUtil.class); + } + + /* + * Classes + */ + public static JvmtiError getClassSignature(JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + return singleton().getClassSignatureInternal(klass, signaturePtr, genericPtr); + } + + public static JvmtiError isModifiableClass(JClass klass, BooleanPointer isModifiableClassPtr) { + // result is always the same, but checked for consistency + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + ((Pointer) isModifiableClassPtr).writeInt(0, JNI_FALSE); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError isArrayClass(JClass klass, BooleanPointer isArrayClassPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + // TODO @dprcci make sure of the BooleanPointer type + ((Pointer) isArrayClassPtr).writeByte(0, javaClass.isArray() ? JNI_TRUE : JNI_FALSE); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError isInterface(JClass klass, BooleanPointer isInterfacePtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + ((Pointer) isInterfacePtr).writeByte(0, javaClass.isInterface() ? JNI_TRUE : JNI_FALSE); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getImplementedInterfaces(JClass klass, CIntPointer interfaceCountPtr, JClassPointerPointer interfacesPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + + /* + * An empty interface list is returned for array classes and primitive classes (for example, + * java.lang.Integer.TYPE) + */ + if (javaClass.isPrimitive() || javaClass.isArray()) { + ((Pointer) interfacesPtr).writeWord(0, WordFactory.nullPointer()); + interfaceCountPtr.write(0); + return JvmtiError.JVMTI_ERROR_NONE; + } + + Class[] classInterfaces = javaClass.getInterfaces(); + int nbInterfaces = classInterfaces.length; + /* + * if(nbInterfaces == 0){ ((Pointer) interfacesPtr).writeWord(0, WordFactory.nullPointer()); + * interfaceCountPtr.write(nbInterfaces); return JvmtiError.JVMTI_ERROR_NONE; } + */ + + JClassPointer interfaceArray = getResultArray(nbInterfaces, ConfigurationValues.getTarget().wordSize); + for (int i = 0; i < nbInterfaces; i++) { + JClass interfaceHandle = (JClass) JNIObjectHandles.createLocal(classInterfaces[i]); + writeArrayAtIndex(interfaceArray, i, ConfigurationValues.getTarget().wordSize, interfaceHandle); + } + + ((Pointer) interfacesPtr).writeWord(0, interfaceArray); + interfaceCountPtr.write(nbInterfaces); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getClassFields(JClass klass, CIntPointer fieldCountPtr, JNIFieldIdPointerPointer fieldsPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + /* + * An empty field list is returned for array classes and primitive classes (for example, + * java.lang.Integer.TYPE) + */ + if (javaClass.isPrimitive() || javaClass.isArray()) { + ((Pointer) fieldsPtr).writeWord(0, WordFactory.nullPointer()); + fieldCountPtr.write(0); + return JvmtiError.JVMTI_ERROR_NONE; + } + + Field[] declaredFields = javaClass.getDeclaredFields(); + int nbDeclaredFields = declaredFields.length; + JNIFieldIdPointer fieldIDArray = getResultArray(nbDeclaredFields, ConfigurationValues.getTarget().wordSize); + + int nbWritten = 0; + for (int i = 0; i < nbDeclaredFields; i++) { + Field field = declaredFields[i]; + String name = field.getName(); + boolean isStatic = Modifier.isStatic(field.getModifiers()); + JNIFieldId fieldID = JNIReflectionDictionary.singleton().getDeclaredFieldID(javaClass, name, isStatic); + if (fieldID.isNonNull()) { + writeArrayAtIndex(fieldIDArray, nbWritten++, ConfigurationValues.getTarget().wordSize, fieldID); + } + } + // We could realloc if nbWritten != nbDeclaredFields but the time costs seem greater than + // the space gains + ((Pointer) fieldsPtr).writeWord(0, fieldIDArray); + fieldCountPtr.write(nbWritten); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getClassMethods(JClass klass, CIntPointer methodCountPtr, JNIMethodIdPointerPointer methodsPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + + /* + * An empty method list is returned for array classes and primitive classes (for example, + * java.lang.Integer.TYPE) + */ + if (javaClass.isPrimitive() || javaClass.isArray()) { + ((Pointer) methodsPtr).writeWord(0, WordFactory.nullPointer()); + methodCountPtr.write(0); + return JvmtiError.JVMTI_ERROR_NONE; + } + + Method[] declaredMethods = javaClass.getDeclaredMethods(); + int nbMethods = declaredMethods.length; + JNIMethodIdPointer methodsIDArray = getResultArray(nbMethods, ConfigurationValues.getTarget().wordSize); + + int nbWritten = 0; + for (int i = 0; i < nbMethods; i++) { + String methodName = declaredMethods[i].getName(); + JNIMethodId methodId = JNIReflectionDictionary.singleton().toMethodID(javaClass, methodName); + if (methodId.isNonNull()) { + writeArrayAtIndex(methodsIDArray, nbWritten++, ConfigurationValues.getTarget().wordSize, methodId); + } + } + ((Pointer) methodsPtr).writeWord(0, methodsIDArray); + methodCountPtr.write(nbWritten); + return JvmtiError.JVMTI_ERROR_NONE; + + } + + public static JvmtiError getClassModifiers(JClass klass, CIntPointer modifiersPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + modifiersPtr.write(javaClass.getModifiers()); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getSourceFileName(JClass klass, CCharPointerPointer sourceNamePtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + String sourceFileName = DynamicHub.fromClass(javaClass).getSourceFileName(); + UnsignedWord bufferSize = WordFactory.unsigned(UninterruptibleUtils.String.modifiedUTF8Length(sourceFileName, true, null)); + CCharPointer buffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); + UninterruptibleUtils.String.toModifiedUTF8(sourceFileName, (Pointer) buffer, ((Pointer) buffer).add(bufferSize), true); + ((Pointer) sourceNamePtr).writeWord(0, buffer); + return JvmtiError.JVMTI_ERROR_NONE; + } + + /* + * Fields + */ + public static JvmtiError getFieldName(JClass klass, JNIFieldId fieldId, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + Field field = getFieldFromHandle(javaClass, fieldId, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + return singleton().writeFieldInfo(field, namePtr, signaturePtr, genericPtr); + } + + public static JvmtiError getFieldDeclaringClass(JClass klass, JNIFieldId fieldId, JClassPointer declaringClassPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + Field field = getFieldFromHandle(javaClass, fieldId, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + + if (!isValidFieldId(javaClass, fieldId)) { + return JvmtiError.JVMTI_ERROR_INVALID_FIELDID; + } + + Class declaringClass = field.getDeclaringClass(); + JClass jclass = (JClass) JNIObjectHandles.createLocal(declaringClass); + ((Pointer) declaringClassPtr).writeWord(0, jclass); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getFieldModifiers(JClass klass, JNIFieldId fieldId, CIntPointer modifiersPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + Field field = getFieldFromHandle(javaClass, fieldId, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + + if (!isValidFieldId(javaClass, fieldId)) { + return JvmtiError.JVMTI_ERROR_INVALID_FIELDID; + } + + int fieldModifiers = field.getModifiers(); + modifiersPtr.write(fieldModifiers); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError isFieldSynthetic(JClass klass, JNIFieldId fieldId, BooleanPointer isSyntheticPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + Field field = getFieldFromHandle(javaClass, fieldId, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + + if (!isValidFieldId(javaClass, fieldId)) { + return JvmtiError.JVMTI_ERROR_INVALID_FIELDID; + } + + boolean isSynthetic = field.isSynthetic(); + ((Pointer) isSyntheticPtr).writeByte(0, isSynthetic ? JNI_TRUE : JNI_FALSE); + return JvmtiError.JVMTI_ERROR_NONE; + } + + /* + * Methods + */ + public static JvmtiError getMethodDeclaringClass(JNIMethodId method, JClassPointer declaringClassPtr) { + JNIAccessibleMethod accessibleMethod = JNIReflectionDictionary.getMethodByID(method); + if (accessibleMethod == null) { + return null; + } + Class declaringClass = accessibleMethod.getDeclaringClass().getClassObject(); + if (declaringClass == null) { + return JvmtiError.JVMTI_ERROR_INVALID_METHODID; + } + JNIObjectHandle jClass = JNIObjectHandles.createLocal(declaringClass); + ((Pointer) declaringClassPtr).writeWord(0, jClass); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getMethodModifiers(JNIMethodId methodId, CIntPointer modifiersPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Method m = getMethodFromHandle(methodId, error); + if (JvmtiError.fromValue(error.read()) != JvmtiError.JVMTI_ERROR_NONE) { + return JvmtiError.fromValue(error.read()); + } + modifiersPtr.write(m.getModifiers()); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError isMethodNative(JNIMethodId methodId, BooleanPointer isNativePtr) { + if (JNIReflectionDictionary.getMethodByID(methodId) == null) { + return JvmtiError.JVMTI_ERROR_INVALID_METHODID; + } + ((Pointer) isNativePtr).writeByte(0, JNIReflectionDictionary.isMethodNative(methodId) ? JNI_TRUE : JNI_FALSE); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError isMethodSynthetic(JNIMethodId methodId, BooleanPointer isSyntheticPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Method m = getMethodFromHandle(methodId, error); + if (JvmtiError.fromValue(error.read()) != JvmtiError.JVMTI_ERROR_NONE) { + return JvmtiError.fromValue(error.read()); + } + ((Pointer) isSyntheticPtr).writeByte(0, m.isSynthetic() ? JNI_TRUE : JNI_FALSE); + return JvmtiError.JVMTI_ERROR_INVALID_METHODID; + } + + public static JvmtiError getMethodName(JNIMethodId methodId, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + JNIAccessibleMethod accessibleMethod = JNIReflectionDictionary.getMethodByID(methodId); + if (accessibleMethod == null) { + return JvmtiError.JVMTI_ERROR_INVALID_METHODID; + } + JNIAccessibleMethodDescriptor descriptor = JNIReflectionDictionary.getMethodDescriptor(accessibleMethod); + JvmtiError error; + // name + if ((error = writeStringOrNull(descriptor.getName(), namePtr)) != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + // signature + if ((error = writeStringOrNull(descriptor.getSignature(), signaturePtr)) != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + + // generic pointer + if (genericPtr.isNonNull()) { + CIntPointer errorPtr = StackValue.get(CIntPointer.class); + Method m = getMethodFromHandle(methodId, errorPtr); + if (JvmtiError.fromValue(errorPtr.read()) != JvmtiError.JVMTI_ERROR_NONE) { + genericPtr.write(0, WordFactory.nullPointer()); + return JvmtiError.fromValue(errorPtr.read()); + } + String genericSignature = SubstrateUtil.cast(m, Target_java_lang_reflect_Method.class).signature; + if (genericSignature == null) { + genericPtr.write(0, WordFactory.nullPointer()); + return JvmtiError.JVMTI_ERROR_NONE; + } + return writeStringToUTF8(genericSignature, genericPtr); + } + return JvmtiError.JVMTI_ERROR_NONE; + } + + /* + * Helpers + */ + private static void writeArrayAtIndex(P array, int index, int elementSize, T value) { + ((Pointer) array).writeWord(index * elementSize, value); + } + + private static T getResultArray(int arraySize, int elementSize) { + int arrayByteSize = ConfigurationValues.getTarget().wordSize * arraySize; + return ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(arrayByteSize)); + } + + private static boolean isValidFieldId(Class javaClass, JNIFieldId fieldId) { + return JNIReflectionDictionary.singleton().getFieldNameByID(javaClass, fieldId) != null; + } + + private static Class getClassFromHandle(JClass klass, CIntPointer error) { + Class javaClass; + try { + javaClass = JNIObjectHandles.getObject(klass); + } catch (ClassCastException | IllegalArgumentException e) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_CLASS.getCValue()); + return null; + } + if (javaClass == null) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_CLASS.getCValue()); + return null; + } + error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + return javaClass; + } + + private static Field getFieldFromHandle(Class javaClass, JNIFieldId fieldId, CIntPointer error) { + String name = JNIReflectionDictionary.singleton().getFieldNameByID(javaClass, fieldId); + if (name == null) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_FIELDID.getCValue()); + return null; + } + Field field; + try { + field = javaClass.getField(name); + } catch (NoSuchFieldException e) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_FIELDID.getCValue()); + return null; + } + error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + return field; + } + + private static Method getMethodFromHandle(JNIMethodId methodID, CIntPointer error) { + JNIAccessibleMethod accessibleMethod = JNIReflectionDictionary.getMethodByID(methodID); + if (accessibleMethod == null) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_METHODID.getCValue()); + return null; + } + Class declaringClass = accessibleMethod.getDeclaringClass().getClassObject(); + String signature = JNIReflectionDictionary.getMethodDescriptor(accessibleMethod).getSignature(); + for (Method m : declaringClass.getMethods()) { + // TODO @dprcci fix + String sig = SubstrateUtil.cast(m, Target_java_lang_reflect_Method.class).signature; + if (Objects.equals(sig, signature)) { + error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + return m; + } + error.write(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); + return null; + } + error.write(JvmtiError.JVMTI_ERROR_INVALID_METHODID.getCValue()); + return null; + } + + private static JvmtiError writeStringOrNull(String value, CCharPointerPointer bufferPtr) { + if (bufferPtr.isNonNull()) { + return writeStringToUTF8(value, bufferPtr); + } else { + bufferPtr.write(0, WordFactory.nullPointer()); + return JvmtiError.JVMTI_ERROR_NONE; + } + } + + private JvmtiError writeFieldInfo(Field field, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + try { + mutex.lock(); + JvmtiError error; + if (namePtr.isNonNull()) { + String name = field.getName(); + error = writeStringToUTF8(name, namePtr); + if (error != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + } + if (signaturePtr.isNonNull()) { + error = createFieldSignature(field, signaturePtr); + if (error != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + } + if (genericPtr.isNonNull()) { + if (!field.getType().equals(field.getGenericType())) { + return createGenericFieldSignature(field, genericPtr); + } else { + genericPtr.write(WordFactory.nullPointer()); + } + } + return JvmtiError.JVMTI_ERROR_NONE; + } finally { + mutex.unlock(); + } + } + + private JvmtiError createFieldSignature(Field field, CCharPointerPointer signaturePtr) { + Class fieldType = field.getType(); + int signatureSize; + if (fieldType.isPrimitive()) { + signatureSize = addTypeToName(fieldType, signatureCharBuffer); + } else { + signatureSize = encodeNameFromString(fieldType.getName(), signatureCharBuffer, 0); + } + return writeStringToCCharArray(signatureCharBuffer, signatureSize, signaturePtr, nameToSigReplacer); + } + + // TODO @dprcci temp + private JvmtiError createGenericFieldSignature(Field field, CCharPointerPointer genericSignaturePtr) { + String sig = field.toGenericString(); + return writeStringToUTF8(sig, genericSignaturePtr); + } + + private JvmtiError getClassSignatureInternal(JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { + CIntPointer error = StackValue.get(CIntPointer.class); + Class javaClass = getClassFromHandle(klass, error); + if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { + return JvmtiError.fromValue(error.read()); + } + return writeClassSignatures(javaClass, signaturePtr, genericPtr); + } + + private JvmtiError writeClassSignatures(Class javaClass, CCharPointerPointer signaturePtr, CCharPointerPointer genericSignaturePtr) { + try { + mutex.lock(); + if (signaturePtr.isNonNull()) { + JvmtiError error = createClassSignature(javaClass, signaturePtr); + if (error != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + } + if (genericSignaturePtr.isNonNull()) { + String genericSignature = JVMTIGenericInfoMap.singleton().classSignatures.getOrDefault(javaClass, null); + if (genericSignature != null) { + String signature = JVMTIGenericInfoMap.singleton().classSignatures.get(javaClass); + return writeStringToUTF8(signature, genericSignaturePtr); + } else { + genericSignaturePtr.write(WordFactory.nullPointer()); + } + } + return JvmtiError.JVMTI_ERROR_NONE; + } finally { + mutex.unlock(); + } + } + + private JvmtiError createClassSignature(Class javaClass, CCharPointerPointer signaturePtr) { + String signature = DynamicHub.fromClass(javaClass).getName(); + int startIndex = addTypeToName(javaClass, signatureCharBuffer); + int signatureSize = encodeNameFromString(signature, signatureCharBuffer, startIndex); + return writeStringToCCharArray(signatureCharBuffer, signatureSize, signaturePtr, nameToSigReplacer); + } + + private static int addTypeToName(Class clazz, char[] buffer) { + char desc; + int index = 0; + if (clazz.isArray()) { + return 0; + } + if (clazz == boolean.class) { + desc = 'Z'; + } else if (clazz == byte.class) { + desc = 'B'; + } else if (clazz == char.class) { + desc = 'C'; + } else if (clazz == short.class) { + desc = 'S'; + } else if (clazz == int.class) { + desc = 'I'; + } else if (clazz == long.class) { + desc = 'J'; + } else if (clazz == float.class) { + desc = 'F'; + } else if (clazz == double.class) { + desc = 'D'; + } else if (clazz == void.class) { + desc = 'V'; + } else { + desc = 'L'; + } + buffer[index++] = desc; + return index; + } + + private static int encodeNameFromString(String name, char[] buffer, int fromIndex) { + if (fromIndex + name.length() >= MAX_SIGNATURE_LENGTH) { + return -1; + } + for (int i = 0; i < name.length(); i++) { + char curr = JavaLangSubstitutions.StringUtil.charAt(name, i); + buffer[fromIndex + i] = curr; + } + return fromIndex + name.length(); + } + + private static JvmtiError writeStringToUTF8(String signature, CCharPointerPointer signaturePtr) { + UnsignedWord bufferSize = WordFactory.unsigned(UninterruptibleUtils.String.modifiedUTF8Length(signature, true, null)); + CCharPointer cStringBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); + if (cStringBuffer.isNull()) { + signaturePtr.write(WordFactory.nullPointer()); + return JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; + } + UninterruptibleUtils.String.toModifiedUTF8(signature, (Pointer) cStringBuffer, ((Pointer) cStringBuffer).add(bufferSize), true, null); + signaturePtr.write(0, cStringBuffer); + return JvmtiError.JVMTI_ERROR_NONE; + } + + // TODO @dprcci might actually be useless thanks to Target_class. Must test and check + public static class JVMTIGenericInfoMap { + + private IdentityHashMap, String> classSignatures; + private static final int HEURISTIC_NB_CLASSES = 512; + + @Platforms(Platform.HOSTED_ONLY.class) + public JVMTIGenericInfoMap() { + this.classSignatures = new IdentityHashMap<>(HEURISTIC_NB_CLASSES); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public void addSignature(Class clazz, String signature) { + classSignatures.putIfAbsent(clazz, signature); + } + + @Fold + public static JVMTIGenericInfoMap singleton() { + return ImageSingletons.lookup(JVMTIGenericInfoMap.class); + } + + @Platforms(Platform.HOSTED_ONLY.class) + public void discardUnused() { + IdentityHashMap, String> jniSignatures = new IdentityHashMap<>(); + Set> jniRegisteredClasses = JNIReflectionDictionary.singleton().getRegisteredClasses(); + // TODO @dprcci necessary to reduce Map size? + classSignatures.entrySet().stream().filter(e -> jniRegisteredClasses.contains(e.getKey())).forEach(e -> jniSignatures.putIfAbsent(e.getKey(), e.getValue())); + classSignatures = jniSignatures; + } + + } +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java index a2669fa33176..c3500d537f90 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java @@ -43,6 +43,27 @@ public interface JvmtiEnv extends PointerBase { @RawField void setMagic(int value); + // TODO @dprcci is there a way to use type of enum? Also might become global + @RawField + int getPhase(); + + @RawField + void setPhase(int phase); + + //TODO change to global pointer to shared struct or keep per field accesses? + @RawField + JvmtiEnvShared getEnvShared(); + + @RawField + void setEnvShared(JvmtiEnvShared envShared); + + @RawField + JvmtiEnv getNextEnv(); + + @RawField + void setNextEnv(JvmtiEnv env); + + // The annotation-based fields above are incomplete because we directly embed other structures // into this raw struct, see below: // diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java new file mode 100644 index 000000000000..17901134463b --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.word.PointerBase; + +@RawStructure +public interface JvmtiEnvEventEnabled extends PointerBase { + @RawField + long getEventEnabled(); + + @RawField + void setEventEnabled(long eventEnabled); + + @RawField + long getCallbackEnabled(); + + @RawField + void setCallbackEnabled(long callbacksEnabled); + + @RawField + long getEventUserEnabled(); + + @RawField + void setEventUserEnabled(long userEnabled); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java new file mode 100644 index 000000000000..62959017919f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.jvmti.headers.JvmtiEvent; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; + +public final class JvmtiEnvEventEnabledUtils { + + public static final int JVMTI_MIN_EVENT_TYPE_VAL = 50; + public static final int JVMTI_MAX_EVENT_TYPE_VAL = 88; + public static final int JVMTI_NB_EVENTS = JVMTI_MAX_EVENT_TYPE_VAL - JVMTI_MIN_EVENT_TYPE_VAL; + + private static final long NO_EVENTS_ENABLED = 0L; + // TODO dprcci check if it is the actual value + private static final long INITIAL_ENABLED_EVENTS = NO_EVENTS_ENABLED; + + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiEnvEventEnabledUtils() { + } + + public static boolean isInValidEventRange(JvmtiEvent event) { + return event.getCValue() >= JvmtiEnvEventEnabledUtils.JVMTI_MIN_EVENT_TYPE_VAL || + event.getCValue() <= JvmtiEnvEventEnabledUtils.JVMTI_MAX_EVENT_TYPE_VAL; + } + + public static int getEventEnumIndex(JvmtiEvent event) { + return event.getCValue() - JVMTI_MIN_EVENT_TYPE_VAL; + } + + public static int getBitForEvent(JvmtiEvent event) { + return 1 << getEventEnumIndex(event); + } + + public static void setUserEventEnabled(JvmtiEnvEventEnabled envEventEnabled, JvmtiEvent event, boolean enabled) { + + long enabledBits = envEventEnabled.getEventUserEnabled(); + int mask = getBitForEvent(event); + if (enabled) { + enabledBits |= mask; + } else { + enabledBits &= ~mask; + } + envEventEnabled.setEventUserEnabled(enabledBits); + } + + public static boolean isUserEventEnabled(JvmtiEnvEventEnabled envEventEnabled, JvmtiEvent event) { + return (getBitForEvent(event) & envEventEnabled.getEventUserEnabled()) != 0; + } + + public static void clearUserEvents(JvmtiEnvEventEnabled envEventEnabled) { + envEventEnabled.setEventUserEnabled(NO_EVENTS_ENABLED); + } + + // TODO @dprcci expand (might not be useful anyways since memory is calloc'ed) + public static void initialize(JvmtiEnvEventEnabled envEventEnabled) { + envEventEnabled.setEventUserEnabled(INITIAL_ENABLED_EVENTS); + } + + public static void setEventCallbacksEnabled(JvmtiEnvEventEnabled envEventEnabled, JvmtiEventCallbacks callbacks) { + envEventEnabled.setCallbackEnabled(JvmtiEventCallbacksUtil.convertCallbacksToBitVector(callbacks)); + } + + // TODO @dprcci implement in Hotspot this is used to set the event_enabled. Current + // implementation works by checking user_event_enabled and not event_enable + public static void recomputeEnabled() { + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java new file mode 100644 index 000000000000..811a7ebc928e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.type.WordPointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; +import com.oracle.svm.core.locks.VMMutex; +import com.oracle.svm.core.snippets.ImplicitExceptions; + +import jdk.graal.compiler.api.replacements.Fold; + +public final class JvmtiEnvManager { + + private PointerBase headEnvironment; + private PointerBase tailEnvironment; + + private final VMMutex mutex; + private PointerBase sharedEnvironment; + private boolean initialized; + + private int phase; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiEnvManager() { + headEnvironment = WordFactory.nullPointer(); + tailEnvironment = WordFactory.nullPointer(); + mutex = new VMMutex("jvmtiEnvManager"); + sharedEnvironment = WordFactory.nullPointer(); + initialized = false; + phase = -1; + } + + @Fold + public static JvmtiEnvManager singleton() { + return ImageSingletons.lookup(JvmtiEnvManager.class); + } + + public JvmtiEnv getHeadEnvironment() { + return (JvmtiEnv) headEnvironment; + } + + public JvmtiEnv getTailEnvironment() { + return (JvmtiEnv) tailEnvironment; + } + + public void setTailEnvironment(JvmtiEnv env) { + mutex.lock(); + tailEnvironment = env; + mutex.unlock(); + } + + public boolean hasAnyEnvironments() { + return headEnvironment.isNonNull(); + } + + public JvmtiEnvShared getSharedEnvironment() { + return (JvmtiEnvShared) sharedEnvironment; + } + + public boolean isInitialized() { + return initialized; + } + + public int getPhase() { + return phase; + } + + public void setPhase(int phase) { + mutex.lock(); + this.phase = phase; + mutex.unlock(); + } + + public void createJvmtiEnv(WordPointer env) { + JvmtiExternalEnv envExt = JvmtiEnvUtil.allocate(); + JvmtiEnv envInt = JvmtiEnvUtil.toInternal(envExt); + + mutex.lock(); + if (!initialized) { + initialize(); + } + JvmtiEnvUtil.initialize(envInt, (JvmtiEnvShared) sharedEnvironment); + + if (headEnvironment.isNull()) { + headEnvironment = envInt; + } else { + JvmtiEnvUtil.setNextEnvironment((JvmtiEnv) tailEnvironment, envInt); + } + tailEnvironment = envInt; + env.write(envExt); + + mutex.unlock(); + } + + public void destroyJvmtiEnv(JvmtiEnv env) { + mutex.lock(); + JvmtiEnv current = (JvmtiEnv) headEnvironment; + JvmtiEnv previous = WordFactory.nullPointer(); + while (current.notEqual(env)) { + previous = current; + current = current.getNextEnv(); + } + + if (headEnvironment.equal(tailEnvironment) && headEnvironment.equal(env)) { + // TODO @dprcci check whether this is correct? + destroy(); + } else if (previous.isNull()) { + headEnvironment = current.getNextEnv(); + } else { + previous.setNextEnv(current.getNextEnv()); + if (current.equal(tailEnvironment)) { + tailEnvironment = previous; + } + } + JvmtiEnvUtil.free(env); + mutex.unlock(); + } + + private void initialize() { + JvmtiEnvShared envShared = JvmtiEnvSharedUtil.allocate(); + JvmtiEnvSharedUtil.initialize(envShared); + sharedEnvironment = envShared; + initialized = true; + } + + public void destroy() { + if (!initialized) { + if (sharedEnvironment.isNonNull()) { + // TODO @dprcci illegalstateexception would make more sense? + try { + throw ImplicitExceptions.CACHED_ILLEGAL_ARGUMENT_EXCEPTION; + } finally { + if (mutex.isOwner()) { + mutex.unlock(); + } + } + // throw new RuntimeException("Global environment destruction can only occur once + // and has already been performed"); + } + // already destroyed + return; + } + JvmtiEnvSharedUtil.free(getSharedEnvironment()); + sharedEnvironment = WordFactory.nullPointer(); + headEnvironment = WordFactory.nullPointer(); + tailEnvironment = WordFactory.nullPointer(); + initialized = false; + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java new file mode 100644 index 000000000000..43dfdfb0bb75 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.word.PointerBase; + +/** + * Pointer to contiguously allocated capabilities which shared among environments. When (if) + * multiple environments are supported, each would have a vector pointing to this structure There + * are 7 different shared capabilities. Might be reworked into a pointer based @RawStruct + */ +@RawStructure +public interface JvmtiEnvShared extends PointerBase { + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java new file mode 100644 index 000000000000..80cc8aeabd4a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_ACCESS_LOCAL_VARIABLES; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_FORCE_EARLY_RETURN; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_ALL_CLASS_HOOK_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_BREAKPOINT_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_EARLY_VMSTART; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_EXCEPTION_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_FIELD_ACCESS_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_FIELD_MODIFICATION_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_FRAME_POP_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_GARBAGE_COLLECTION_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_METHOD_ENTRY_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_METHOD_EXIT_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_MONITOR_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_OBJECT_FREE_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_SINGLE_STEP_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_BYTECODES; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_CONSTANT_POOL; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_CURRENT_CONTENDED_MONITOR; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_CURRENT_THREAD_CPU_TIME; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_LINE_NUMBERS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_MONITOR_INFO; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_OWNED_MONITOR_INFO; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_SOURCE_DEBUG_EXTENSION; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_SOURCE_FILE_NAME; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_SYNTHETIC_ATTRIBUTE; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_THREAD_CPU_TIME; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_MAINTAIN_ORIGINAL_METHOD_ORDER; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_POP_FRAME; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_REDEFINE_ANY_CLASS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_REDEFINE_CLASSES; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_RETRANSFORM_ANY_CLASS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_RETRANSFORM_CLASSES; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SET_NATIVE_METHOD_PREFIX; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SIGNAL_THREAD; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SUPPORT_VIRTUAL_THREADS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SUSPEND; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_TAG_OBJECTS; +import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.getBit; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.config.ConfigurationValues; + +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.NumUtil; + +public class JvmtiEnvSharedUtil { + // TODO add magic? + /** + * Java enum used to identify shared capabilities among jvmti environments as well as their + * initial values based on hotspot's. Note: Initial values do not accurately depict the actual + * capabilities currently supported by native-image + */ + public enum SHARED_CAPABILITIES_TYPE { + ALWAYS(initAlways()), + ON_LOAD(initOnLoad()), + ALWAYS_SOLO(initAlwaysSolo()), + ON_LOAD_SOLO(initOnLoadSolo()), + ALWAYS_SOLO_REMAINING(initAlwaysSolo()), + ON_LOAD_SOLO_REMAINING(initOnLoadSolo()), + ACQUIRED(0L); + + private final long initial; + + SHARED_CAPABILITIES_TYPE(long initial) { + this.initial = initial; + } + + public long getInitial() { + return this.initial; + } + + private static long initAlways() { + long always = 0L; + always |= getBit(CAN_GET_BYTECODES); + always |= getBit(CAN_SIGNAL_THREAD); + always |= getBit(CAN_GET_SOURCE_FILE_NAME); + always |= getBit(CAN_GET_LINE_NUMBERS); + always |= getBit(CAN_GET_SYNTHETIC_ATTRIBUTE); + always |= getBit(CAN_GET_MONITOR_INFO); + always |= getBit(CAN_GET_CONSTANT_POOL); + always |= getBit(CAN_GENERATE_ALL_CLASS_HOOK_EVENTS); + always |= getBit(CAN_GENERATE_MONITOR_EVENTS); + always |= getBit(CAN_GENERATE_GARBAGE_COLLECTION_EVENTS); + always |= getBit(CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS); + always |= getBit(CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS); + always |= getBit(CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS); + always |= getBit(CAN_REDEFINE_CLASSES); + always |= getBit(CAN_REDEFINE_ANY_CLASS); + always |= getBit(CAN_RETRANSFORM_CLASSES); + always |= getBit(CAN_RETRANSFORM_ANY_CLASS); + always |= getBit(CAN_SET_NATIVE_METHOD_PREFIX); + always |= getBit(CAN_TAG_OBJECTS); + always |= getBit(CAN_GENERATE_OBJECT_FREE_EVENTS); + always |= getBit(CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS); + always |= getBit(CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS); + always |= getBit(CAN_SUPPORT_VIRTUAL_THREADS); + // return always; + // TODO add + /* + * if (os::is_thread_cpu_time_supported()) { jc.can_get_current_thread_cpu_time = 1; + * jc.can_get_thread_cpu_time = 1; } + */ + // TODO @dprcci enabled for tests + always |= getBit(CAN_GET_CURRENT_THREAD_CPU_TIME); + always |= getBit(CAN_GET_THREAD_CPU_TIME); + return always; + } + + private static long initOnLoad() { + long onLoad = 0L; + onLoad |= getBit(CAN_POP_FRAME); + onLoad |= getBit(CAN_FORCE_EARLY_RETURN); + onLoad |= getBit(CAN_GET_SOURCE_DEBUG_EXTENSION); + onLoad |= getBit(CAN_ACCESS_LOCAL_VARIABLES); + onLoad |= getBit(CAN_MAINTAIN_ORIGINAL_METHOD_ORDER); + onLoad |= getBit(CAN_GENERATE_SINGLE_STEP_EVENTS); + onLoad |= getBit(CAN_GENERATE_EXCEPTION_EVENTS); + onLoad |= getBit(CAN_GENERATE_FRAME_POP_EVENTS); + onLoad |= getBit(CAN_GENERATE_METHOD_ENTRY_EVENTS); + onLoad |= getBit(CAN_GENERATE_METHOD_EXIT_EVENTS); + onLoad |= getBit(CAN_GET_OWNED_MONITOR_INFO); + onLoad |= getBit(CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO); + onLoad |= getBit(CAN_GET_CURRENT_CONTENDED_MONITOR); + onLoad |= getBit(CAN_GENERATE_EARLY_VMSTART); + onLoad |= getBit(CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS); + return onLoad; + } + + private static long initAlwaysSolo() { + long alwaysSolo = 0L; + alwaysSolo |= getBit(CAN_SUSPEND); + alwaysSolo |= getBit(CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS); + return alwaysSolo; + } + + private static long initOnLoadSolo() { + long onLoadSolo = 0L; + onLoadSolo |= getBit(CAN_GENERATE_FIELD_MODIFICATION_EVENTS); + onLoadSolo |= getBit(CAN_GENERATE_FIELD_ACCESS_EVENTS); + onLoadSolo |= getBit(CAN_GENERATE_BREAKPOINT_EVENTS); + return onLoadSolo; + } + } + + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiEnvSharedUtil() { + } + + public static JvmtiEnvShared allocate() { + JvmtiEnvShared sharedCapabilities = ImageSingletons.lookup(UnmanagedMemorySupport.class).calloc(WordFactory.unsigned(sharedEnvironmentSize())); + if (sharedCapabilities.isNull()) { + return WordFactory.nullPointer(); + } + return sharedCapabilities; + } + + public static void free(JvmtiEnvShared sharedCapabilities) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(sharedCapabilities); + } + + public static void initialize(JvmtiEnvShared envShared) { + assert envShared.isNonNull(); + JvmtiCapabilitiesUtil.initSharedCapabilities(envShared); + } + + @Fold + static int sharedEnvironmentSize() { + return NumUtil.roundUp(sharedCapabilitiesOffset() + (SizeOf.get(com.oracle.svm.core.jvmti.headers.JvmtiCapabilities.class) * SHARED_CAPABILITIES_TYPE.values().length), + ConfigurationValues.getTarget().wordSize); + } + + @Fold + static int sharedCapabilitiesOffset() { + return NumUtil.roundUp(SizeOf.get(JvmtiEnvShared.class), ConfigurationValues.getTarget().wordSize); + } + + @Fold + static int capabilitiesSize() { + return SizeOf.get(com.oracle.svm.core.jvmti.headers.JvmtiCapabilities.class); + } + + public static com.oracle.svm.core.jvmti.headers.JvmtiCapabilities getSharedCapability(JvmtiEnvShared envShared, SHARED_CAPABILITIES_TYPE type) { + assert envShared.isNonNull(); + return addOffset(envShared, sharedCapabilitiesOffset() + (type.ordinal() * capabilitiesSize())); + } + + @SuppressWarnings("unchecked") + private static T addOffset(JvmtiEnvShared env, int offset) { + return (T) ((Pointer) env).add(offset); + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java new file mode 100644 index 000000000000..e63cdbe96db1 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; +import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; +import com.oracle.svm.core.jvmti.utils.JvmtiLocalStorageUtil; + +import jdk.graal.compiler.api.replacements.Fold; + +public final class JvmtiEnvStorage extends JvmtiLocalStorageUtil { + + private static final int INITIAL_CAPACITY = 4; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiEnvStorage() { + super("Jvmti Environment Local Storage"); + } + + public static JvmtiError setEnvironmentStorage(JvmtiExternalEnv externalEnv, VoidPointer data) { + return singleton().setEnvironmentStorageInternal(externalEnv, data); + } + + public static JvmtiError getEnvironmentStorage(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { + return singleton().getEnvironmentStorageInternal(externalEnv, dataPtr); + } + + public void initialize() { + super.initialize(INITIAL_CAPACITY); + } + + @Fold + public static JvmtiEnvStorage singleton() { + return ImageSingletons.lookup(JvmtiEnvStorage.class); + } + + private JvmtiError setEnvironmentStorageInternal(JvmtiExternalEnv externalEnv, VoidPointer data) { + super.put(externalEnv, data); + return JvmtiError.JVMTI_ERROR_NONE; + } + + private JvmtiError getEnvironmentStorageInternal(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { + VoidPointer data = super.contains(externalEnv) ? super.get(externalEnv) : WordFactory.nullPointer(); + ((Pointer) dataPtr).writeWord(0, data); + return JvmtiError.JVMTI_ERROR_NONE; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java index c1b683d12bc0..9f14362fd607 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java @@ -24,11 +24,8 @@ */ package com.oracle.svm.core.jvmti; -import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NONE; -import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NOT_AVAILABLE; - -import org.graalvm.compiler.api.replacements.Fold; -import org.graalvm.compiler.core.common.NumUtil; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.NumUtil; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -72,8 +69,11 @@ public static JvmtiExternalEnv allocate() { env.setIsolate(CurrentIsolate.getIsolate()); env.setMagic(VALID_ENV_MAGIC); + JvmtiEnvEventEnabledUtils.initialize(getEnvEventEnabled(env)); + JvmtiExternalEnv externalEnv = toExternal(env); externalEnv.setFunctions(functionTable); + return externalEnv; } @@ -83,11 +83,11 @@ public static JvmtiExternalEnv allocate() { * we might need the same approach. */ public static void free(JvmtiEnv env) { - env.setMagic(DISPOSED_ENV_MAGIC); JvmtiCapabilities capabilities = getCapabilities(env); relinquishCapabilities(env, capabilities); + env.setMagic(DISPOSED_ENV_MAGIC); JvmtiExternalEnv externalEnv = toExternal(env); JvmtiFunctionTable.freeFunctionTable(externalEnv.getFunctions()); externalEnv.setFunctions(WordFactory.nullPointer()); @@ -95,13 +95,21 @@ public static void free(JvmtiEnv env) { ImageSingletons.lookup(UnmanagedMemorySupport.class).free(env); } + public static void initialize(JvmtiEnv env, JvmtiEnvShared envShared) { + assert isValid(env); + assert envShared.isNonNull(); + + env.setEnvShared(envShared); + env.setNextEnv(WordFactory.nullPointer()); + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static JvmtiEnv toInternal(JvmtiExternalEnv externalEnv) { assert externalEnv.isNonNull(); return (JvmtiEnv) ((Pointer) externalEnv).subtract(externalEnvOffset()); } - private static JvmtiExternalEnv toExternal(JvmtiEnv env) { + public static JvmtiExternalEnv toExternal(JvmtiEnv env) { assert env.isNonNull(); return (JvmtiExternalEnv) ((Pointer) env).add(externalEnvOffset()); } @@ -118,6 +126,24 @@ public static Isolate getIsolate(JvmtiEnv env) { return env.getIsolate(); } + public static void setNextEnvironment(JvmtiEnv env, JvmtiEnv next) { + assert isValid(env); + assert isValid(next); + env.setNextEnv(next); + } + + public static JvmtiEnv getNextEnvironment(JvmtiEnv env) { + assert isValid(env); + return env.getNextEnv(); + } + + // ------------------ Capabilities API ------------------ // + // TODO @dprcci add to the jvmti api (jvmtifunctions) + public static JvmtiError getPotentialCapabilities(JvmtiEnv env, JvmtiCapabilities result) { + assert isValid(env); + return JvmtiCapabilitiesUtil.getPotentialCapabilities(env.getPhase(), getCapabilities(env), getProhibitedCapabilities(env), env.getEnvShared(), result); + } + public static JvmtiCapabilities getCapabilities(JvmtiEnv env) { assert isValid(env); return addOffset(env, capabilitiesOffset()); @@ -125,17 +151,24 @@ public static JvmtiCapabilities getCapabilities(JvmtiEnv env) { public static JvmtiError addCapabilities(JvmtiEnv env, JvmtiCapabilities capabilities) { assert capabilities.isNonNull(); - /* We don't support any capabilities at the moment. */ - if (JvmtiCapabilitiesUtil.hasAny(capabilities)) { - return JVMTI_ERROR_NOT_AVAILABLE; - } - return JVMTI_ERROR_NONE; + return JvmtiCapabilitiesUtil.addCapabilities(env.getPhase(), getEnvShared(env), getCapabilities(env), getProhibitedCapabilities(env), capabilities); } - public static JvmtiError relinquishCapabilities(JvmtiEnv env, JvmtiCapabilities capabilities) { - assert capabilities.isNonNull(); - /* Nothing to do because we don't support any capabilities at the moment. */ - return JVMTI_ERROR_NONE; + public static JvmtiError relinquishCapabilities(JvmtiEnv env, JvmtiCapabilities unwanted) { + assert unwanted.isNonNull(); + return JvmtiCapabilitiesUtil.relinquishCapabilities(getEnvShared(env), getCapabilities(env), unwanted); + } + + // ------------------------------------------------------ // + + public static JvmtiCapabilities getProhibitedCapabilities(JvmtiEnv env) { + assert isValid(env); + return addOffset(env, prohibitedCapabilitiesOffset()); + } + + public static JvmtiEnvEventEnabled getEnvEventEnabled(JvmtiEnv env) { + assert isValid(env); + return addOffset(env, envEventEnabledOffset()); } public static JvmtiEventCallbacks getEventCallbacks(JvmtiEnv env) { @@ -144,24 +177,16 @@ public static JvmtiEventCallbacks getEventCallbacks(JvmtiEnv env) { } public static void setEventCallbacks(JvmtiEnv env, JvmtiEventCallbacks newCallbacks, int sizeOfCallbacks) { - /* - * int internalStructSize = SizeOf.get(JvmtiEventCallbacks.class); // Clear the whole struct - * (including gaps). JvmtiEventCallbacks envEventCallbacks = getEventCallbacks(env); - * UnmanagedMemoryUtil.fill((Pointer) envEventCallbacks, - * WordFactory.unsigned(internalStructSize), (byte) 0); - * - * if (newCallbacks.isNonNull()) { int bytesToCopy = - * UninterruptibleUtils.Math.min(internalStructSize, sizeOfCallbacks); - * UnmanagedMemoryUtil.copy((Pointer) newCallbacks, (Pointer) envEventCallbacks, - * WordFactory.unsigned(bytesToCopy)); } - * - * jlong enabled_bits = env->env_event_enable()->_event_callback_enabled.get_bits(); for - * (int ei = JVMTI_MIN_EVENT_TYPE_VAL; ei <= JVMTI_MAX_EVENT_TYPE_VAL; ++ei) { jvmtiEvent - * evt_t = (jvmtiEvent)ei; jlong bit_for = JvmtiEventEnabled::bit_for(evt_t); if - * (env->has_callback(evt_t)) { enabled_bits |= bit_for; } else { enabled_bits &= ~bit_for; - * } } env->env_event_enable()->_event_callback_enabled.set_bits(enabled_bits); - * recomputeEnabled(); - */ + + flushObjectFreeEvent(env); + + JvmtiEventCallbacks eventCallbacks = getEventCallbacks(env); + + JvmtiEventCallbacksUtil.setEventCallbacks(eventCallbacks, newCallbacks, sizeOfCallbacks); + JvmtiEnvEventEnabledUtils.setEventCallbacksEnabled(getEnvEventEnabled(env), eventCallbacks); + + JvmtiEnvEventEnabledUtils.recomputeEnabled(); + } /* @@ -179,8 +204,15 @@ public static void setEventCallbacks(JvmtiEnv env, JvmtiEventCallbacks newCallba * * All states transitions dependent on these transitions are also handled here. */ - private static void recomputeEnabled() { + public static JvmtiEnvShared getEnvShared(JvmtiEnv env) { + assert isValid(env); + return env.getEnvShared(); + } + + public static void setEnvShared(JvmtiEnv env, JvmtiEnvShared envShared) { + assert isValid(env); + env.setEnvShared(envShared); } @SuppressWarnings("unchecked") @@ -188,6 +220,13 @@ private static T addOffset(JvmtiEnv env, int offset) { return (T) ((Pointer) env).add(offset); } + public static boolean hasCapability(JvmtiExternalEnv envExt, JvmtiCapabilitiesEnum cap){ + JvmtiEnv internal = toInternal(envExt); + assert isValid(internal); + return JvmtiCapabilitiesUtil.hasCapability(getCapabilities(internal), cap); + } + + // TODO @dprcci implement public static boolean hasEventCapability(JvmtiEnv env, JvmtiEvent eventInfo) { /* At the moment, we only support events that don't need any specific capabilities. */ return true; @@ -199,10 +238,20 @@ static int capabilitiesOffset() { } @Fold - static int eventCallbacksOffset() { + static int prohibitedCapabilitiesOffset() { return NumUtil.roundUp(capabilitiesOffset() + SizeOf.get(JvmtiCapabilities.class), ConfigurationValues.getTarget().wordSize); } + @Fold + static int envEventEnabledOffset() { + return NumUtil.roundUp(prohibitedCapabilitiesOffset() + SizeOf.get(JvmtiCapabilities.class), ConfigurationValues.getTarget().wordSize); + } + + @Fold + static int eventCallbacksOffset() { + return NumUtil.roundUp(envEventEnabledOffset() + SizeOf.get(JvmtiEnvEventEnabled.class), ConfigurationValues.getTarget().wordSize); + } + @Fold static int externalEnvOffset() { return NumUtil.roundUp(eventCallbacksOffset() + SizeOf.get(JvmtiEventCallbacks.class), ConfigurationValues.getTarget().wordSize); @@ -213,6 +262,7 @@ static int internalEnvSize() { return externalEnvOffset() + SizeOf.get(JvmtiExternalEnv.class); } + // TODO @dprcci complete public static void setEventUserEnabled(JvmtiEnv env, Thread javaEventThread, JvmtiEvent eventType, boolean value) { // TEMP (chaeubl): implement /* @@ -225,5 +275,16 @@ public static void setEventUserEnabled(JvmtiEnv env, Thread javaEventThread, Jvm * state->env_thread_state(env)->event_enable()->set_user_enabled(event_type, enabled); } } * recompute_enabled(); */ + if (eventType == JvmtiEvent.JVMTI_EVENT_OBJECT_FREE) { + flushObjectFreeEvent(env); + } + + if (javaEventThread == null) { + JvmtiEnvEventEnabledUtils.setUserEventEnabled(getEnvEventEnabled(env), eventType, value); + } + } + + // TODO dprcci implement? Would need TagMap (or equivalent) first + private static void flushObjectFreeEvent(JvmtiEnv env) { } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java new file mode 100644 index 000000000000..17b3c164d906 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.jdk.UninterruptibleUtils; +import com.oracle.svm.core.jvmti.headers.JvmtiEvent; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; + +public final class JvmtiEventCallbacksUtil { + + @Platforms(Platform.HOSTED_ONLY.class) + private JvmtiEventCallbacksUtil() { + } + + public static long convertCallbacksToBitVector(JvmtiEventCallbacks callbacks) { + + long enabledCallbacks = 0L; + Pointer rawCFunPointer = (Pointer) callbacks; + + for (int i = 0; i < JvmtiEnvEventEnabledUtils.JVMTI_NB_EVENTS; i++) { + CFunctionPointer value = rawCFunPointer.readWord(0); + if (value.isNonNull()) { + enabledCallbacks |= 1L << i; + } + rawCFunPointer = rawCFunPointer.add(ConfigurationValues.getTarget().wordSize); + } + return enabledCallbacks; + } + + private static boolean hasCallback(JvmtiEventCallbacks callbacks, JvmtiEvent event) { + long callBacksBitVector = convertCallbacksToBitVector(callbacks); + long eventIndex = JvmtiEnvEventEnabledUtils.getBitForEvent(event); + return (callBacksBitVector & eventIndex) != 0; + } + + public static void setEventCallbacks(JvmtiEventCallbacks envEventCallbacks, JvmtiEventCallbacks newCallbacks, int sizeOfCallbacks) { + int internalStructSize = SizeOf.get(JvmtiEventCallbacks.class); // Clear the whole struct + // (including gaps). + UnmanagedMemoryUtil.fill((Pointer) envEventCallbacks, WordFactory.unsigned(internalStructSize), (byte) 0); + + if (newCallbacks.isNonNull()) { + int bytesToCopy = UninterruptibleUtils.Math.min(internalStructSize, sizeOfCallbacks); + UnmanagedMemoryUtil.copy((Pointer) newCallbacks, (Pointer) envEventCallbacks, WordFactory.unsigned(bytesToCopy)); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java index a9470d02f7d7..e9abe8dc2a62 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java @@ -24,7 +24,7 @@ */ package com.oracle.svm.core.jvmti; -import org.graalvm.compiler.api.replacements.Fold; +import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java index 56ecb40f3ebd..cfc8ea89e8a1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java @@ -38,6 +38,9 @@ import java.nio.charset.StandardCharsets; +import com.oracle.svm.core.jvmti.headers.BooleanPointer; +import com.oracle.svm.core.jvmti.headers.JThreadGroupPointerPointer; +import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -58,6 +61,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointErrors; @@ -95,7 +99,7 @@ import com.oracle.svm.core.jvmti.headers.JvmtiEventMode; import com.oracle.svm.core.jvmti.headers.JvmtiExtensionFunctionInfoPointer; import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; -import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfoPointer; import com.oracle.svm.core.jvmti.headers.JvmtiHeapCallbacks; import com.oracle.svm.core.jvmti.headers.JvmtiHeapObjectCallback; import com.oracle.svm.core.jvmti.headers.JvmtiHeapRootCallback; @@ -105,7 +109,7 @@ import com.oracle.svm.core.jvmti.headers.JvmtiMonitorUsage; import com.oracle.svm.core.jvmti.headers.JvmtiObjectReferenceCallback; import com.oracle.svm.core.jvmti.headers.JvmtiPhase; -import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointerPointer; import com.oracle.svm.core.jvmti.headers.JvmtiStackReferenceCallback; import com.oracle.svm.core.jvmti.headers.JvmtiStartFunctionPointer; import com.oracle.svm.core.jvmti.headers.JvmtiThreadGroupInfo; @@ -116,7 +120,7 @@ /** * Defines all JVMTI functions. This class may only contain methods that are annotated with * {@link CEntryPoint}. - * + *

* JVMTI functions are annotated with {@link RestrictHeapAccess} because they must not execute any * code that could trigger JVMTI events (could result in endless recursion). *

    @@ -151,7 +155,11 @@ private JvmtiFunctions() { @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int Allocate(JvmtiExternalEnv externalEnv, long size, CCharPointerPointer memPtr) { + if (memPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } if (size < 0) { + memPtr.write(WordFactory.nullPointer()); return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } if (size == 0) { @@ -176,32 +184,41 @@ static int Deallocate(JvmtiExternalEnv externalEnv, CCharPointer mem) { return JVMTI_ERROR_NONE.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadState(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer threadStatePtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (threadStatePtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiThreadStateUtil.getThreadState(thread, threadStatePtr); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetCurrentThread(JvmtiExternalEnv externalEnv, JThreadPointer threadPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (threadPtr.equal(WordFactory.nullPointer())) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiGetThreadsUtil.getCurrentThread(threadPtr); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetAllThreads(JvmtiExternalEnv externalEnv, CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (threadsCountPtr.isNull() || threadsPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiGetThreadsUtil.getAllThreads(threadsCountPtr, threadsPtr); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int SuspendThread(JvmtiExternalEnv externalEnv, JThread thread) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + static int SuspendThread(JvmtiExternalEnv externalEnv, JThreadPointer thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -246,18 +263,24 @@ static int StopThread(JvmtiExternalEnv externalEnv, JThread thread, JNIObjectHan return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int InterruptThread(JvmtiExternalEnv externalEnv, JThread thread) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (!JvmtiEnvUtil.hasCapability(externalEnv, JvmtiCapabilitiesEnum.CAN_SIGNAL_THREAD)) { + return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); + } + return JvmtiThreadActionsUtil.interruptThread(thread); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadInfo(JvmtiExternalEnv externalEnv, JThread thread, JvmtiThreadInfo infoPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (infoPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiThreadActionsUtil.getThreadInfo(thread, infoPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -288,68 +311,107 @@ static int RunAgentThread(JvmtiExternalEnv externalEnv, JThread thread, JvmtiSta return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int SetThreadLocalStorage(JvmtiExternalEnv externalEnv, JThread thread, @CConst VoidPointer data) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiThreadLocalStorage.setThreadLocalStorage(thread, data).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadLocalStorage(JvmtiExternalEnv externalEnv, JThread thread, VoidPointerPointer dataPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(dataPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiThreadLocalStorage.getThreadLocalStorage(thread, dataPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetTopThreadGroups(JvmtiExternalEnv externalEnv, CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + static int GetTopThreadGroups(JvmtiExternalEnv externalEnv, CIntPointer groupCountPtr, JThreadGroupPointerPointer groupsPtr) { + if(groupsPtr.isNull() || groupCountPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiThreadGroupUtil.getTopThreadGroups(groupCountPtr, groupsPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadGroupInfo(JvmtiExternalEnv externalEnv, JThreadGroup group, JvmtiThreadGroupInfo infoPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(infoPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiThreadGroupUtil.getThreadGroupInfo(group, infoPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadGroupChildren(JvmtiExternalEnv externalEnv, JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (threadCountPtr.isNull() || threadsPtr.isNull() ||groupCountPtr.isNull() || groupsPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiThreadGroupUtil.getThreadGroupChildren(group, threadCountPtr, threadsPtr, groupCountPtr, groupsPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetStackTrace(JvmtiExternalEnv externalEnv, JThread thread, int startDepth, int maxFrameCount, JvmtiFrameInfo frameBuffer, CIntPointer countPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + static int GetStackTrace(JvmtiExternalEnv externalEnv, JThread thread, int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer, CIntPointer countPtr) { + if (maxFrameCount < 0) { + return JvmtiError.JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + if (frameBuffer.isNull() || countPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + + if (JvmtiStackTraceUtil.startDepthIsOutOfBound(startDepth, SubstrateOptions.maxJavaStackTraceDepth())) { + return JvmtiError.JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + return JvmtiStackTraceUtil.getStackTrace(thread, startDepth, maxFrameCount, frameBuffer, countPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetAllStackTraces(JvmtiExternalEnv externalEnv, int maxFrameCount, JvmtiStackInfoPointer stackInfoPtr, CIntPointer threadCountPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + static int GetAllStackTraces(JvmtiExternalEnv externalEnv, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr, CIntPointer threadCountPtr) { + if (stackInfoPtr.isNull() || threadCountPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + if (maxFrameCount < 0) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + + return JvmtiMultiStackTracesUtil.getAllStackTraces(maxFrameCount, stackInfoPtr, threadCountPtr); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetThreadListStackTraces(JvmtiExternalEnv externalEnv, int threadCount, @CConst JThreadPointer threadList, int maxFrameCount, JvmtiStackInfoPointer stackInfoPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + static int GetThreadListStackTraces(JvmtiExternalEnv externalEnv, int threadCount, @CConst JThreadPointer threadList, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr) { + if (stackInfoPtr.isNull() || threadList.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + if (maxFrameCount < 0 || threadCount < 0) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + + return JvmtiMultiStackTracesUtil.getListStackTraces(threadCount, threadList, maxFrameCount, stackInfoPtr); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFrameCount(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer countPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(countPtr.isNull()){ + return JvmtiError.JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiStackTraceUtil.getFrameCount(thread, countPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -678,11 +740,11 @@ static int GetClassLoaderClasses(JvmtiExternalEnv externalEnv, JNIObjectHandle i return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassSignature(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiClassInfoUtil.getClassSignature(klass, signaturePtr, genericPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -692,39 +754,55 @@ static int GetClassStatus(JvmtiExternalEnv externalEnv, JClass klass, CIntPointe return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetSourceFileName(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer sourceNamePtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(sourceNamePtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getSourceFileName(klass, sourceNamePtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassModifiers(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer modifiersPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(modifiersPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getClassModifiers(klass, modifiersPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassMethods(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer methodCountPtr, JNIMethodIdPointerPointer methodsPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(methodCountPtr.isNull() || methodsPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getClassMethods(klass, methodCountPtr, methodsPtr).getCValue(); + } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassFields(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer fieldCountPtr, JNIFieldIdPointerPointer fieldsPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(fieldCountPtr.isNull() || fieldsPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getClassFields(klass, fieldCountPtr, fieldsPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetImplementedInterfaces(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer interfaceCountPtr, JClassPointerPointer interfacesPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(interfacesPtr.isNull() || interfaceCountPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getImplementedInterfaces(klass, interfaceCountPtr, interfacesPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -741,25 +819,34 @@ static int GetConstantPool(JvmtiExternalEnv externalEnv, JClass klass, CIntPoint return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsInterface(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isInterfacePtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(isInterfacePtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.isInterface(klass, isInterfacePtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsArrayClass(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isArrayClassPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(isArrayClassPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.isArrayClass(klass, isArrayClassPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsModifiableClass(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isModifiableClassPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(isModifiableClassPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.isModifiableClass(klass, isModifiableClassPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -790,18 +877,24 @@ static int RedefineClasses(JvmtiExternalEnv externalEnv, int classCount, @CConst return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetObjectSize(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CLongPointer sizePtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (sizePtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiObjectInfoUttil.getObjectSize(object, sizePtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetObjectHashCode(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CIntPointer hashCodePtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (hashCodePtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiObjectInfoUttil.getHashCode(object, hashCodePtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -811,53 +904,71 @@ static int GetObjectMonitorUsage(JvmtiExternalEnv externalEnv, JNIObjectHandle o return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFieldName(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiClassInfoUtil.getFieldName(klass, field, namePtr, signaturePtr, genericPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFieldDeclaringClass(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, JClassPointer declaringClassPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (declaringClassPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getFieldDeclaringClass(klass, field, declaringClassPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFieldModifiers(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, CIntPointer modifiersPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (modifiersPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getFieldModifiers(klass, field, modifiersPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsFieldSynthetic(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, BooleanPointer isSyntheticPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (isSyntheticPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + if(!JvmtiEnvUtil.hasCapability(externalEnv, JvmtiCapabilitiesEnum.CAN_GET_SYNTHETIC_ATTRIBUTE)){ + return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); + } + return JvmtiClassInfoUtil.isFieldSynthetic(klass, field, isSyntheticPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetMethodName(JvmtiExternalEnv externalEnv, JNIMethodId method, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiClassInfoUtil.getMethodName(method, namePtr, signaturePtr, genericPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetMethodDeclaringClass(JvmtiExternalEnv externalEnv, JNIMethodId method, JClassPointer declaringClassPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if (declaringClassPtr.isNull()) { + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getMethodDeclaringClass(method, declaringClassPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetMethodModifiers(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer modifiersPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(modifiersPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.getMethodModifiers(method, modifiersPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -902,18 +1013,27 @@ static int GetBytecodes(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPo return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsMethodNative(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isNativePtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(isNativePtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiClassInfoUtil.isMethodNative(method, isNativePtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsMethodSynthetic(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isSyntheticPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(isSyntheticPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + if(!JvmtiEnvUtil.hasCapability(externalEnv, JvmtiCapabilitiesEnum.CAN_GET_SYNTHETIC_ATTRIBUTE)){ + return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); + } + return JvmtiClassInfoUtil.isMethodSynthetic(method, isSyntheticPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -937,53 +1057,53 @@ static int SetNativeMethodPrefixes(JvmtiExternalEnv externalEnv, int prefixCount return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int CreateRawMonitor(JvmtiExternalEnv externalEnv, @CConst CCharPointer name, JRawMonitorIdPointer monitorPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.createRawMonitor(name, monitorPtr).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int DestroyRawMonitor(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.destroyRawMonitor(monitor).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorEnter(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.rawMonitorEnter(monitor).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorExit(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.rawMonitorExit(monitor).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorWait(JvmtiExternalEnv externalEnv, JRawMonitorId monitor, long millis) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.rawMonitorWait(monitor, millis).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorNotify(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.rawMonitorNotify(monitor).getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorNotifyAll(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + return JvmtiRawMonitorUtil.rawMonitorNotifyAll(monitor).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1014,18 +1134,24 @@ static int SetEventCallbacks(JvmtiExternalEnv externalEnv, @CConst JvmtiEventCal return JVMTI_ERROR_NONE.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // TODO dprcci disabled temporarily + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int SetEventNotificationMode(JvmtiExternalEnv externalEnv, int eventMode, JvmtiEvent eventType, JThread eventThread) { // TEMP (chaeubl): this method uses varargs... do we need a native wrapper to deal with // that? seems that this is only reserved for future expansion but may still be tricky. - if (eventType == null) { + + if (eventType == null || !JvmtiEnvEventEnabledUtils.isInValidEventRange(eventType)) { return JVMTI_ERROR_INVALID_EVENT_TYPE.getCValue(); } else if (!eventType.isSupported()) { return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } + if (eventMode != JvmtiEventMode.JVMTI_ENABLE() && eventMode != JvmtiEventMode.JVMTI_DISABLE()) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } + /* Check that the needed capabilities are present. */ boolean enable = (eventMode == JvmtiEventMode.JVMTI_ENABLE()); JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); @@ -1043,7 +1169,6 @@ static int SetEventNotificationMode(JvmtiExternalEnv externalEnv, int eventMode, /* Global events cannot be controlled at thread level. */ return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } - /* At the moment, we don't support enabling events for specific threads. */ return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @@ -1088,8 +1213,12 @@ static int GetPotentialCapabilities(JvmtiExternalEnv externalEnv, JvmtiCapabilit return JVMTI_ERROR_NULL_POINTER.getCValue(); } - /* We don't support any capabilities at the moment. */ - JvmtiCapabilitiesUtil.clear(result); + JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); + JvmtiEnvUtil.getPotentialCapabilities(env, result); + /* We don't support any capabilities at the moment. *//* + * JvmtiCapabilitiesUtil.clear(result) + * ; + */ return JVMTI_ERROR_NONE.getCValue(); } @@ -1113,7 +1242,6 @@ static int AddCapabilities(JvmtiExternalEnv externalEnv, @CConst JvmtiCapabiliti if (capabilities.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); return JvmtiEnvUtil.addCapabilities(env, capabilities).getCValue(); } @@ -1234,7 +1362,8 @@ static int GetPhase(JvmtiExternalEnv externalEnv, CIntPointer phasePtr) { @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int DisposeEnvironment(JvmtiExternalEnv externalEnv) { JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); - JvmtiEnvUtil.free(env); + JvmtiEnvManager manager = JvmtiEnvManager.singleton(); + manager.destroyJvmtiEnv(env); return JVMTI_ERROR_NONE.getCValue(); } @@ -1242,14 +1371,23 @@ static int DisposeEnvironment(JvmtiExternalEnv externalEnv) { @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int SetEnvironmentLocalStorage(JvmtiExternalEnv externalEnv, @CConst VoidPointer data) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(JvmtiEnvUtil.isValid(JvmtiEnvUtil.toInternal(externalEnv))){ + return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); + } + return JvmtiEnvStorage.setEnvironmentStorage(externalEnv, data).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetEnvironmentLocalStorage(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + if(JvmtiEnvUtil.isValid(JvmtiEnvUtil.toInternal(externalEnv))){ + return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); + } + if(dataPtr.isNull()){ + return JVMTI_ERROR_NULL_POINTER.getCValue(); + } + return JvmtiEnvStorage.getEnvironmentStorage(externalEnv, dataPtr).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1263,7 +1401,8 @@ static int GetVersionNumber(JvmtiExternalEnv externalEnv, CIntPointer versionPtr return JVMTI_ERROR_NONE.getCValue(); } - @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + // TODO dprcci disabled temporarily + // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetErrorName(JvmtiExternalEnv externalEnv, JvmtiError jvmtiError, CCharPointerPointer namePtr) { @@ -1337,10 +1476,6 @@ public static int enter(JvmtiExternalEnv externalEnv) { } } - @CPointerTo(VoidPointer.class) - private interface VoidPointerPointer extends PointerBase { - } - @CPointerTo(CCharPointerPointer.class) private interface CCharPointerPointerPointer extends PointerBase { } @@ -1349,8 +1484,4 @@ private interface CCharPointerPointerPointer extends PointerBase { private interface CLongPointerPointer extends PointerBase { } - // TEMP (chaeubl): should be uint_8 - @CPointerTo(nameOfCType = "char") - private interface BooleanPointer extends PointerBase { - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java new file mode 100644 index 000000000000..83df17b74f2d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.feature.InternalFeature; + +//TODO @dprcci not automatically register +@AutomaticallyRegisteredFeature +public final class JvmtiGenericInfoMapFeature implements InternalFeature { + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + ImageSingletons.add(JvmtiClassInfoUtil.JVMTIGenericInfoMap.class, new JvmtiClassInfoUtil.JVMTIGenericInfoMap()); + } + + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + JvmtiClassInfoUtil.JVMTIGenericInfoMap.singleton().discardUnused(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java new file mode 100644 index 000000000000..e01ca2b12932 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.heap.VMOperationInfos; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JThreadPointer; +import com.oracle.svm.core.jvmti.headers.JThreadPointerPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.utils.JvmtiUtils; +import com.oracle.svm.core.thread.JavaThreads; +import com.oracle.svm.core.thread.NativeVMOperation; +import com.oracle.svm.core.thread.NativeVMOperationData; +import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads; + +public final class JvmtiGetThreadsUtil { + + private final JvmtiGetThreadsOperation operation; + private static final int INITIAL_THREAD_BUFFER_CAPACITY = 16; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiGetThreadsUtil() { + this.operation = new JvmtiGetThreadsOperation(); + } + + public static int getAllThreads(CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { + return ImageSingletons.lookup(JvmtiGetThreadsUtil.class).getAllThreadsInternal(threadsCountPtr, threadsPtr); + } + + public static int getCurrentThread(JThreadPointer threadPtr) { + return ImageSingletons.lookup(JvmtiGetThreadsUtil.class).getCurrentThreadsInternal(threadPtr); + } + + @Uninterruptible(reason = "jvmti GetCurrentThread") + private int getCurrentThreadsInternal(JThreadPointer threadPtr) { + Thread currentThread = Thread.currentThread(); + JThread jthread = (JThread) JNIObjectHandles.createLocal(currentThread); + ((Pointer) threadPtr).writeWord(0, jthread); + return JvmtiError.JVMTI_ERROR_NONE.getCValue(); + } + + private int getAllThreadsInternal(CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { + int size = SizeOf.get(JvmtiGetAllThreadsVMOperationData.class); + JvmtiGetAllThreadsVMOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + data.setCIntPointer(threadsCountPtr); + data.setJThreadPointerPointer(threadsPtr.rawValue()); + + operation.enqueue(data); + return data.getJvmtiError(); + } + + // TODO @dprcci Is it better to allocate a bound max memory array in advance and realloc? + + @RawStructure + private interface JvmtiGetAllThreadsVMOperationData extends NativeVMOperationData { + @RawField + void setJThreadPointerPointer(long ptr); + + @RawField + long getJThreadPointerPointer(); + + @RawField + int getJvmtiError(); + + @RawField + void setJvmtiError(int error); + + @RawField + void setCIntPointer(CIntPointer ptr); + + @RawField + CIntPointer getCIntPointer(); + } + + private static class JvmtiGetThreadsOperation extends NativeVMOperation { + JvmtiGetThreadsOperation() { + super(VMOperationInfos.get(JvmtiGetThreadsUtil.JvmtiGetThreadsOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + protected void operate(NativeVMOperationData data) { + getAllThreads((JvmtiGetAllThreadsVMOperationData) data); + } + } + + @Uninterruptible(reason = "jvmti GetAllThreads") + static int getNumberOfThreads() { + int nbOfThreads = 0; + for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { + Thread thread = PlatformThreads.fromVMThread(isolateThread); + // for consistency and clarity + if (thread == null || thread.isVirtual() || !JavaThreads.isAlive(thread)) { + continue; + } + nbOfThreads++; + } + return nbOfThreads; + } + + @Uninterruptible(reason = "jvmti GetAllThreads") + private static void getAllThreads(JvmtiGetAllThreadsVMOperationData data) { + JThreadPointer arrayPtr = JvmtiUtils.allocateWordBuffer(INITIAL_THREAD_BUFFER_CAPACITY); + int currentArraySize = INITIAL_THREAD_BUFFER_CAPACITY; + int nbWritten = 0; + for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { + Thread thread = PlatformThreads.fromVMThread(isolateThread); + // "Get all live platform threads that are attached to the VM" + if (thread == null || thread.isVirtual() || !JavaThreads.isAlive(thread)) { + continue; + } + if (nbWritten == currentArraySize) { + arrayPtr = JvmtiUtils.growWordBuffer(arrayPtr, INITIAL_THREAD_BUFFER_CAPACITY); + currentArraySize += INITIAL_THREAD_BUFFER_CAPACITY; + } + JNIObjectHandle threadHandle = JNIObjectHandles.createLocal(thread); + JvmtiUtils.writeWordAtIdxInBuffer(arrayPtr, nbWritten, threadHandle); + nbWritten++; + } + + JThreadPointerPointer threadsPtr = WordFactory.unsigned(data.getJThreadPointerPointer()); + CIntPointer threadsCountPtr = data.getCIntPointer(); + + ((Pointer) threadsPtr).writeWord(0, arrayPtr); + threadsCountPtr.write(nbWritten); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java new file mode 100644 index 000000000000..02880410ccef --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; + +public final class JvmtiManager { + // TODO @dprcci refactor + public static void registerAllJvmtiClasses() { + ImageSingletons.add(JvmtiAgents.class, new JvmtiAgents()); + ImageSingletons.add(JvmtiEnvManager.class, new JvmtiEnvManager()); + ImageSingletons.add(JvmtiStackTraceUtil.class, new JvmtiStackTraceUtil()); + ImageSingletons.add(JvmtiClassInfoUtil.class, new JvmtiClassInfoUtil()); + ImageSingletons.add(JvmtiGetThreadsUtil.class, new JvmtiGetThreadsUtil()); + ImageSingletons.add(JvmtiMultiStackTracesUtil.class, new JvmtiMultiStackTracesUtil()); + ImageSingletons.add(JvmtiThreadStateUtil.class, new JvmtiThreadStateUtil()); + ImageSingletons.add(JvmtiRawMonitorUtil.class, new JvmtiRawMonitorUtil()); + ImageSingletons.add(JvmtiFunctionTable.class, new JvmtiFunctionTable()); + ImageSingletons.add(JvmtiEnvStorage.class, new JvmtiEnvStorage()); + ImageSingletons.add(JvmtiThreadLocalStorage.class, new JvmtiThreadLocalStorage()); + ImageSingletons.add(JvmtiThreadGroupUtil.class, new JvmtiThreadGroupUtil()); + } + + public static void freeAllJvmtiClassesUnmanagedMemory() { + ; + ImageSingletons.lookup(JvmtiRawMonitorUtil.class).releaseAllUnmanagedMemory(); + ImageSingletons.lookup(JvmtiEnvStorage.class).releaseAllUnmanagedMemory(); + ImageSingletons.lookup(JvmtiThreadLocalStorage.class).releaseAllUnmanagedMemory(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java new file mode 100644 index 000000000000..ca8e747d3339 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +public interface JvmtiMemoryManager { + default void releaseAllUnmanagedMemory() { + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java new file mode 100644 index 000000000000..51301bee4b5e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.jvmti.JvmtiThreadStateUtil.getThreadState; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.CConst; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.heap.VMOperationInfos; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JThreadPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiStackInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointerPointer; +import com.oracle.svm.core.thread.NativeVMOperation; +import com.oracle.svm.core.thread.NativeVMOperationData; +import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads; + +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.NumUtil; + +//TODO @dprcci Group all those thread related classed at some point (or create sub package ?) +public final class JvmtiMultiStackTracesUtil { + private final JvmtiGetAllStackTracesOperation allStackTracesOperation; + private final JvmtiGetListStackTracesOperation listStackTracesOperation; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiMultiStackTracesUtil() { + this.allStackTracesOperation = new JvmtiGetAllStackTracesOperation(); + this.listStackTracesOperation = new JvmtiGetListStackTracesOperation(); + } + + public static int getAllStackTraces(int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr, CIntPointer threadCountPtr) { + return ImageSingletons.lookup(JvmtiMultiStackTracesUtil.class).getAllStackTracesInternal(maxFrameCount, stackInfoPtr, threadCountPtr); + } + + public static int getListStackTraces(int threadCount, @CConst JThreadPointer threadListHead, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr) { + return ImageSingletons.lookup(JvmtiMultiStackTracesUtil.class).getListStackTracesInternal(threadCount, threadListHead, maxFrameCount, stackInfoPtr); + } + + // TODO @dprcci The problem with reusing the existing code is that a thread list (java) cannot + // be used as no memory can be allocated. + // Using a stack array is not an option as the size must be a compile time constant. The only + // option would be to allocated UnamangedMemory? + private int getListStackTracesInternal(int threadCount, @CConst JThreadPointer threadListHead, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr) { + + int size = SizeOf.get(JvmtiGetListStackTracesVMOperationData.class); + JvmtiGetListStackTracesVMOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + data.setStackInfoPointerPointer(stackInfoPtr); + data.setMaxFrameCount(maxFrameCount); + data.setNbThreads(threadCount); + data.setThreadListHead(threadListHead); + + listStackTracesOperation.enqueue(data); + return data.getJvmtiError(); + } + + @RawStructure + private interface JvmtiGetListStackTracesVMOperationData extends NativeVMOperationData { + @RawField + void setStackInfoPointerPointer(JvmtiStackInfoPointerPointer ptr); + + @RawField + JvmtiStackInfoPointerPointer getStackInfoPointerPointer(); + + @RawField + int getJvmtiError(); + + @RawField + void setJvmtiError(int error); + + @RawField + void setNbThreads(int nbThreads); + + @RawField + int getNbThreads(); + + @RawField + void setThreadListHead(JThreadPointer head); + + @RawField + JThreadPointer getThreadListHead(); + + @RawField + void setMaxFrameCount(int maxFrameCount); + + @RawField + int getMaxFrameCount(); + } + + // TODO @dprcci cannot allocate memory + private static class JvmtiGetListStackTracesOperation extends NativeVMOperation { + JvmtiGetListStackTracesOperation() { + super(VMOperationInfos.get(JvmtiGetListStackTracesOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + protected void operate(NativeVMOperationData data) { + getListStackTraces((JvmtiGetListStackTracesVMOperationData) data); + } + } + + private static void getListStackTraces(JvmtiGetListStackTracesVMOperationData data) { + int maxFrameCount = data.getMaxFrameCount(); + int nbThreads = data.getNbThreads(); + JThreadPointer threadListHead = data.getThreadListHead(); + + JvmtiStackInfoPointer stackInfoBuffer = allocateStackInfoBuffer(nbThreads, maxFrameCount); + if (stackInfoBuffer.isNull()) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); + return; + } + + int nbWritten = fillStackInfoBuffer(nbThreads, threadListHead, maxFrameCount, stackInfoBuffer); + if (nbWritten != nbThreads) { + cleanup(stackInfoBuffer); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue()); + return; + } + + ((Pointer) data.getStackInfoPointerPointer()).writeWord(0, stackInfoBuffer); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + } + + private static int fillStackInfoBuffer(int nbThreads, JThreadPointer threadListHead, int maxFrameCount, JvmtiStackInfoPointer stackInfoBuffer) { + int nbWritten = 0; + for (int i = 0; i < nbThreads; i++) { + JThread currentJThread = readThreadAtIdx(threadListHead, i); + Thread currentThread; + + Pointer threadPtr = StackValue.get(ConfigurationValues.getTarget().wordSize); + if (getThreadFromHandle(currentJThread, threadPtr) != 0) { + break; + } + currentThread = (Thread) threadPtr.readObject(0); + JvmtiStackInfo currentStackInfo = readStackInfoAt(stackInfoBuffer, i, maxFrameCount); + fillStackInfo(currentStackInfo, currentThread, maxFrameCount); + nbWritten++; + } + return nbWritten; + } + + private static JThread readThreadAtIdx(JThreadPointer head, int index) { + return ((Pointer) head).readWord(index * ConfigurationValues.getTarget().wordSize); + } + + private int getAllStackTracesInternal(int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr, CIntPointer threadCountPtr) { + int size = SizeOf.get(JvmtiGetAllStackTracesVMOperationData.class); + JvmtiGetAllStackTracesVMOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + data.setStackInfoPointerPointer(stackInfoPtr); + data.setMaxFrameCount(maxFrameCount); + data.setCIntPointer(threadCountPtr); + + allStackTracesOperation.enqueue(data); + return data.getJvmtiError(); + } + + @RawStructure + private interface JvmtiGetAllStackTracesVMOperationData extends NativeVMOperationData { + @RawField + void setStackInfoPointerPointer(JvmtiStackInfoPointerPointer ptr); + + @RawField + JvmtiStackInfoPointerPointer getStackInfoPointerPointer(); + + @RawField + int getJvmtiError(); + + @RawField + void setJvmtiError(int error); + + @RawField + void setCIntPointer(CIntPointer ptr); + + @RawField + CIntPointer getCIntPointer(); + + @RawField + void setMaxFrameCount(int maxFrameCount); + + @RawField + int getMaxFrameCount(); + } + + // TODO @dprcci cannot allocate memory + private static class JvmtiGetAllStackTracesOperation extends NativeVMOperation { + JvmtiGetAllStackTracesOperation() { + super(VMOperationInfos.get(JvmtiGetAllStackTracesOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + // @RestrictHeapAccess(reason = "jvmti", access = RestrictHeapAccess.Access.NO_ALLOCATION) + protected void operate(NativeVMOperationData data) { + getAllStackTraces((JvmtiGetAllStackTracesVMOperationData) data); + } + } + + private static void getAllStackTraces(JvmtiGetAllStackTracesVMOperationData data) { + + int maxFrameCount = data.getMaxFrameCount(); + int nbThreads = JvmtiGetThreadsUtil.getNumberOfThreads(); + + JvmtiStackInfoPointer stackInfoBuffer = allocateStackInfoBuffer(nbThreads, maxFrameCount); + if (stackInfoBuffer.isNull()) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); + return; + } + + int nbStackInfo = fillStackInfoBuffer(stackInfoBuffer, nbThreads, maxFrameCount); + if (nbStackInfo != nbThreads) { + // TODO @dprcci if error means more threads are being written to than expected. Only + // "nbThreads" have been allocated + cleanup(stackInfoBuffer); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); + return; + } + + ((Pointer) data.getStackInfoPointerPointer()).writeWord(0, stackInfoBuffer); + ((Pointer) data.getCIntPointer()).writeInt(0, nbStackInfo); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + } + + private static int fillStackInfoBuffer(JvmtiStackInfoPointer stackInfoBuffer, int nbThreads, int maxFrameCount) { + int nbWritten = 0; + for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { + Thread thread = PlatformThreads.fromVMThread(isolateThread); + // "Get all live platform threads that are attached to the VM" + if (thread == null || thread.isVirtual()) { + continue; + } + if (nbWritten >= nbThreads) { + return -1; + } + JvmtiStackInfo currentStackInfo = readStackInfoAt(stackInfoBuffer, nbWritten, maxFrameCount); + fillStackInfo(currentStackInfo, thread, maxFrameCount); + nbWritten++; + } + return nbWritten; + } + + private static void fillStackInfo(JvmtiStackInfo stackInfo, Thread thread, int maxFrameCount) { + JThread jthread = (JThread) JNIObjectHandles.createLocal(thread); + stackInfo.setThread(jthread); + + CIntPointer nbFramesPr = StackValue.get(CIntPointer.class); + JvmtiStackTraceUtil.getStackTrace(jthread, 0, maxFrameCount, stackInfo.getFrameInfo(), nbFramesPr); + stackInfo.setFrameCount(nbFramesPr.read()); + + int threadState = getThreadState(thread); + stackInfo.setState(threadState); + } + + private static JvmtiStackInfoPointer allocateStackInfoBuffer(int bufferSize, int maxFrameCount) { + int totalBufferSize = bufferSize * stackInfoOffsetWithFrameInfoBuffer(maxFrameCount); + JvmtiStackInfoPointer allocatedBufferPtr = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(totalBufferSize)); + if (allocatedBufferPtr.isNull()) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(allocatedBufferPtr); + return WordFactory.nullPointer(); + } + for (int i = 0; i < bufferSize; i++) { + JvmtiStackInfo currentStackInfo = readStackInfoAt(allocatedBufferPtr, i, maxFrameCount); + JvmtiFrameInfoPointer currentFrame = readFrameInfoAt(allocatedBufferPtr, i, maxFrameCount); + currentStackInfo.setFrameInfo(currentFrame); + } + return allocatedBufferPtr; + } + + // free up to (including) the failed allocated FrameInfo + private static void cleanup(JvmtiStackInfoPointer stackInfoBuffer) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(stackInfoBuffer); + } + + private static JvmtiFrameInfoPointer readFrameInfoAt(JvmtiStackInfoPointer arrayPtr, int index, int maxFrameCount) { + return (JvmtiFrameInfoPointer) ((Pointer) arrayPtr).add(index * stackInfoOffsetWithFrameInfoBuffer(maxFrameCount) + stackInfoOffset()); + } + + private static JvmtiStackInfo readStackInfoAt(JvmtiStackInfoPointer arrayPtr, int index, int maxFrameCount) { + return (JvmtiStackInfo) ((Pointer) arrayPtr).add(index * stackInfoOffsetWithFrameInfoBuffer(maxFrameCount)); + } + + @Fold + static int stackInfoOffset() { + return NumUtil.roundUp(SizeOf.get(JvmtiStackInfo.class), ConfigurationValues.getTarget().wordSize); + } + + static int stackInfoOffsetWithFrameInfoBuffer(int maxFrameInfo) { + return NumUtil.roundUp(stackInfoOffset() + (SizeOf.get(JvmtiFrameInfo.class) * maxFrameInfo), ConfigurationValues.getTarget().wordSize); + } + + private static int getThreadFromHandle(JThread handle, Pointer result) { + Thread thread; + try { + Object threadReference = JNIObjectHandles.getObject(handle); + thread = (Thread) threadReference; + } catch (IllegalArgumentException | ClassCastException e) { + return -1; + } + result.writeObject(0, thread); + return 0; + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java new file mode 100644 index 000000000000..11992aa17ab3 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.c.type.CLongPointer; + +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.hub.LayoutEncoding; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.snippets.KnownIntrinsics; + +import jdk.graal.compiler.nodes.java.ArrayLengthNode; + +public final class JvmtiObjectInfoUttil { + + private JvmtiObjectInfoUttil() { + } + + public static JvmtiError getObjectSize(JNIObjectHandle jobject, CLongPointer sizePtr) { + Object object; + try { + object = JNIObjectHandles.getObject(jobject); + } catch (IllegalArgumentException e) { + return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; + } + if (object == null) { + return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; + } + + long size = 0; + int layoutEncoding = KnownIntrinsics.readHub(object).getLayoutEncoding(); + if (LayoutEncoding.isArray(layoutEncoding)) { + int elementSize; + if (LayoutEncoding.isPrimitiveArray(layoutEncoding)) { + elementSize = LayoutEncoding.getArrayIndexScale(layoutEncoding); + } else { + elementSize = ConfigurationValues.getTarget().wordSize; + } + int length = ArrayLengthNode.arrayLength(object); + size = (long) length * elementSize; + } else { + DynamicHub hub = DynamicHub.fromClass(object.getClass()); + int encoding = hub.getLayoutEncoding(); + if (LayoutEncoding.isPureInstance(encoding)) { + /* + * May underestimate the object size if the identity hashcode field is optional. + * This is the best that what can do because the HPROF format does not support that + * instances of one class have different object sizes. + */ + size = (int) LayoutEncoding.getPureInstanceAllocationSize(encoding).rawValue(); + } else if (LayoutEncoding.isHybrid(encoding)) { + /* For hybrid objects, return the size of the fields. */ + size = LayoutEncoding.getArrayBaseOffsetAsInt(encoding); + } + } + sizePtr.write(size); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getHashCode(JNIObjectHandle jobject, CIntPointer hashCodePtr) { + Object object; + try { + object = JNIObjectHandles.getObject(jobject); + } catch (IllegalArgumentException e) { + return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; + } + if (object == null) { + return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; + } + hashCodePtr.write(object.hashCode()); + return JvmtiError.JVMTI_ERROR_NONE; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java new file mode 100644 index 000000000000..64ca679875eb --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.JNIThreadLocalEnvironment; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JvmtiEvent; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; +import com.oracle.svm.core.jvmti.headers.JvmtiPhase; +import com.oracle.svm.core.log.Log; + +public final class JvmtiPostEvents { + + private static final int EVENT_NOT_FOUND = -1; + private static final int NO_CALLBACK_SET = -2; + private static final int ARGUMENT_ERROR = -3; + + public static void postVMInit() { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_VM_INIT); + } + + public static void postVMStart() { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_VM_START); + } + + public static void postVMDeath() { + // TODO @dprcci create and add call to JvmtiTagMap::flush_all_object_free_events(); + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_VM_DEATH); + JvmtiEnvManager.singleton().setPhase(JvmtiPhase.JVMTI_PHASE_DEAD()); + } + + public static void postThreadStart(Thread thread) { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_THREAD_START, thread); + } + + public static void postThreadEnd(Thread thread) { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_THREAD_END, thread); + } + + public static void postGarbageCollectionStart() { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_GARBAGE_COLLECTION_START); + } + + public static void postGarbageCollectionFinish() { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_GARBAGE_COLLECTION_FINISH); + } + + public static void postMonitorWait(Thread thread, Object obj, long timeout) { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_WAIT, thread, obj, timeout); + } + + public static void postMonitorWaited(Thread thread, Object obj, boolean timedout) { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_WAITED, thread, obj, timedout); + } + + public static void postMonitorContendedEnter(Thread thread, Object obj) { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_CONTENDED_ENTER, thread, obj); + } + + public static void postMonitorContendedEntered(Thread thread, Object obj) { + invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, thread, obj); + } + + private static void invokeCallbackForEvent(JvmtiEvent event, Object... args) { + if (!SubstrateOptions.JVMTI.getValue()) { + return; + } + + JvmtiEnvManager manager = JvmtiEnvManager.singleton(); + if (!manager.hasAnyEnvironments()) { + return; + } + for (JvmtiEnv current = manager.getHeadEnvironment(); current.isNonNull(); current = current.getNextEnv()) { + if (JvmtiEnvEventEnabledUtils.isUserEventEnabled(JvmtiEnvUtil.getEnvEventEnabled(current), event)) { + // assert event.getNbParameters() == args.length; + int res = invokeCallbackFunction(current, event, args); + checkError(res, event, args); + } + } + } + + private static int invokeCallbackFunction(JvmtiEnv env, JvmtiEvent event, Object... args) { + switch (event) { + case JVMTI_EVENT_VM_DEATH -> { + JvmtiEventCallbacks.JvmtiEventVMDeathFunctionPointer vmDeathCallback = JvmtiEnvUtil.getEventCallbacks(env).getVMDeath(); + if (vmDeathCallback.isNonNull()) { + return vmDeathCallback.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress()); + } + } + case JVMTI_EVENT_VM_START -> { + JvmtiEventCallbacks.JvmtiEventVMStartFunctionPointer vmStartCallback = JvmtiEnvUtil.getEventCallbacks(env).getVMStart(); + if (vmStartCallback.isNonNull()) { + return vmStartCallback.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress()); + } + } + case JVMTI_EVENT_VM_INIT -> { + JvmtiEventCallbacks.JvmtiEventVMInitFunctionPointer vmInitCallback = JvmtiEnvUtil.getEventCallbacks(env).getVMInit(); + if (vmInitCallback.isNonNull()) { + return vmInitCallback.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), (JThread) JNIObjectHandles.createLocal(Thread.currentThread())); + } + } + case JVMTI_EVENT_GARBAGE_COLLECTION_START -> { + JvmtiEventCallbacks.JvmtiEventGarbageCollectionStartFunctionPointer gcStart = JvmtiEnvUtil.getEventCallbacks(env).getGarbageCollectionStart(); + if (gcStart.isNonNull()) { + return gcStart.invoke(JvmtiEnvUtil.toExternal(env)); + } + } + case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH -> { + JvmtiEventCallbacks.JvmtiEventGarbageCollectionFinishFunctionPointer gcFinish = JvmtiEnvUtil.getEventCallbacks(env).getGarbageCollectionFinish(); + if (gcFinish.isNonNull()) { + return gcFinish.invoke(JvmtiEnvUtil.toExternal(env)); + } + } + case JVMTI_EVENT_THREAD_START -> { + JvmtiEventCallbacks.JvmtiEventThreadStartFunctionPointer threadStart = JvmtiEnvUtil.getEventCallbacks(env).getThreadStart(); + if (threadStart.isNonNull()) { + if (!validArgumentTypes(args[0], Thread.class)) { + return ARGUMENT_ERROR; + } + JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); + return threadStart.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread); + } + } + case JVMTI_EVENT_THREAD_END -> { + JvmtiEventCallbacks.JvmtiEventThreadEndFunctionPointer threadEnd = JvmtiEnvUtil.getEventCallbacks(env).getThreadEnd(); + if (threadEnd.isNonNull()) { + if (!validArgumentTypes(args[0], Thread.class)) { + return ARGUMENT_ERROR; + } + JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); + return threadEnd.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread); + } + } + case JVMTI_EVENT_MONITOR_WAIT -> { + JvmtiEventCallbacks.JvmtiEventMonitorWaitFunctionPointer monitorWait = JvmtiEnvUtil.getEventCallbacks(env).getMonitorWait(); + if (monitorWait.isNonNull()) { + if (!validArgumentTypes(args[0], Thread.class) || !validArgumentTypes(args[2], Long.class)) { + return ARGUMENT_ERROR; + } + JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); + JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); + long timeout = (Long) args[2]; + return monitorWait.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject, timeout); + } + + } + case JVMTI_EVENT_MONITOR_WAITED -> { + JvmtiEventCallbacks.JvmtiEventMonitorWaitedFunctionPointer monitorWaited = JvmtiEnvUtil.getEventCallbacks(env).getMonitorWaited(); + if (monitorWaited.isNonNull()) { + if (!validArgumentTypes(args[0], Thread.class) || !validArgumentTypes(args[2], Boolean.class)) { + return ARGUMENT_ERROR; + } + JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); + JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); + boolean timedout = (Boolean) args[2]; + return monitorWaited.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject, timedout); + } + } + case JVMTI_EVENT_MONITOR_CONTENDED_ENTER -> { + JvmtiEventCallbacks.JvmtiEventMonitorContendedEnterFunctionPointer monitorContendedEnter = JvmtiEnvUtil.getEventCallbacks(env).getMonitorContendedEnter(); + if (monitorContendedEnter.isNonNull()) { + if (!validArgumentTypes(args[0], Thread.class)) { + return ARGUMENT_ERROR; + } + JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); + JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); + return monitorContendedEnter.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject); + } + } + case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED -> { + JvmtiEventCallbacks.JvmtiEventMonitorContendedEnteredFunctionPointer monitorContendedEntered = JvmtiEnvUtil.getEventCallbacks(env).getMonitorContendedEntered(); + if (monitorContendedEntered.isNonNull()) { + if (!validArgumentTypes(args[0], Thread.class)) { + return ARGUMENT_ERROR; + } + JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); + JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); + return monitorContendedEntered.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject); + } + } + default -> { + return EVENT_NOT_FOUND; + } + } + return NO_CALLBACK_SET; + } + + private static boolean validArgumentTypes(Object arg, Class type) { + return type.isInstance(arg); + } + + private static void checkError(int error, JvmtiEvent event, Object... args) { + if (error == EVENT_NOT_FOUND) { + Log.log().string("Event: " + event + " is not implemented yet"); + } else if (error == NO_CALLBACK_SET) { + Log.log().string("Event: " + event + " has no callback set"); + } + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java new file mode 100644 index 000000000000..bd180a4b1c79 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.word.Pointer; + +import com.oracle.svm.core.c.NonmovableArray; +import com.oracle.svm.core.c.NonmovableArrays; +import com.oracle.svm.core.c.NonmovableObjectArray; +import com.oracle.svm.core.jvmti.headers.JRawMonitorId; +import com.oracle.svm.core.jvmti.headers.JRawMonitorIdPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.locks.VMMutex; +import com.oracle.svm.core.monitor.JvmtiRawMonitorHelper; +import com.oracle.svm.core.monitor.MonitorInflationCause; +import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport; +import com.oracle.svm.core.nmt.NmtCategory; + +import jdk.graal.compiler.api.replacements.Fold; + +public final class JvmtiRawMonitorUtil implements JvmtiMemoryManager { + + // TODO @dprcci Lots of copy pasted code because 2 values would need to be returned when + // refactored into a function. + // Current best idea is group the code and use a StackValue to write the error + + private final VMMutex mutex; + private static final int INITIAL_NB_AVAILABLE_SLOTS = 4; + private static final int ARRAY_GROWTH_FACTOR = 2; + private NonmovableObjectArray monitorObjectsArray; + private NonmovableArray freeIndicesList; + private int nextAvailableIndex; + private int monitorArraySize; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiRawMonitorUtil() { + mutex = new VMMutex("Jvmti RawMonitor"); + nextAvailableIndex = 0; + monitorArraySize = INITIAL_NB_AVAILABLE_SLOTS; + } + + public void initialize() { + monitorObjectsArray = NonmovableArrays.createObjectArray(Object[].class, INITIAL_NB_AVAILABLE_SLOTS, NmtCategory.JVMTI); + freeIndicesList = NonmovableArrays.createIntArray(INITIAL_NB_AVAILABLE_SLOTS, NmtCategory.JVMTI); + initFreeList(freeIndicesList); + } + + @Override + public void releaseAllUnmanagedMemory() { + tearDown(); + } + + @Fold + public static JvmtiRawMonitorUtil singleton() { + return ImageSingletons.lookup(JvmtiRawMonitorUtil.class); + } + + public static JvmtiError createRawMonitor(CCharPointer name, JRawMonitorIdPointer monitorPtr) { + return singleton().createRawMonitorInternal(monitorPtr); + } + + public static JvmtiError destroyRawMonitor(JRawMonitorId monitorId) { + return singleton().destroyRawMonitorInternal(monitorId); + } + + public static JvmtiError rawMonitorEnter(JRawMonitorId monitorId) { + return singleton().rawMonitorEnterInternal(monitorId); + } + + public static JvmtiError rawMonitorExit(JRawMonitorId monitorId) { + return singleton().rawMonitorExitInternal(monitorId); + } + + public static JvmtiError rawMonitorWait(JRawMonitorId monitorId, long millis) { + return singleton().rawMonitorWaitInternal(monitorId, millis); + } + + public static JvmtiError rawMonitorNotify(JRawMonitorId monitorId) { + return singleton().rawMonitorNotifyInternal(monitorId, false); + } + + public static JvmtiError rawMonitorNotifyAll(JRawMonitorId monitorId) { + return singleton().rawMonitorNotifyInternal(monitorId, true); + } + + private JvmtiError rawMonitorNotifyInternal(JRawMonitorId monitorId, boolean notifyAll) { + int monitorIdx = (int) monitorId.rawValue(); + if (isInvalidMonitorIdx(monitorIdx)) { + return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; + } + Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); + if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { + return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; + } + MultiThreadedMonitorSupport.singleton().notify(monitor, notifyAll); + return JvmtiError.JVMTI_ERROR_NONE; + } + + private JvmtiError rawMonitorWaitInternal(JRawMonitorId monitorId, long millis) { + int monitorIdx = (int) monitorId.rawValue(); + if (isInvalidMonitorIdx(monitorIdx)) { + return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; + } + Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); + if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { + return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; + } + // exception is thrown by wait(), but JVM TI does not specify behaviour in that case + if (millis < 0) { + millis = 0L; + } + // TODO @dprcci hard to get rid of the thrown exceptions without reimplementation + try { + MultiThreadedMonitorSupport.singleton().wait(monitor, millis); + } catch (InterruptedException e) { + return JvmtiError.JVMTI_ERROR_INTERRUPT; + } + return JvmtiError.JVMTI_ERROR_NONE; + } + + private JvmtiError rawMonitorExitInternal(JRawMonitorId monitorId) { + int monitorIdx = (int) monitorId.rawValue(); + if (isInvalidMonitorIdx(monitorIdx)) { + return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; + } + // TODO @dprcci handle entering during Agent_OnLoad + Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); + if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { + return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; + } + MultiThreadedMonitorSupport.singleton().monitorExit(monitor, MonitorInflationCause.JVMTI_ENTER); + return JvmtiError.JVMTI_ERROR_NONE; + } + + private JvmtiError rawMonitorEnterInternal(JRawMonitorId monitorId) { + int monitorIdx = (int) monitorId.rawValue(); + if (isInvalidMonitorIdx(monitorIdx)) { + return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; + } + // TODO @dprcci handle entering during Agent_OnLoad + Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); + MultiThreadedMonitorSupport.singleton().monitorEnter(monitor, MonitorInflationCause.JVMTI_ENTER); + return JvmtiError.JVMTI_ERROR_NONE; + } + + private JvmtiError createRawMonitorInternal(JRawMonitorIdPointer monitorPtr) { + try { + mutex.lock(); + // TODO @dprcci probably reimplement monitors without java Objects? + Object obj = new Object(); + JvmtiError err = JvmtiRawMonitorHelper.getOrCreateRawMonitor(obj); + if (err != JvmtiError.JVMTI_ERROR_NONE) { + return err; + } + int monitorIdx = getNextFreeMonitorIdx(); + NonmovableArrays.setObject(monitorObjectsArray, monitorIdx, obj); + ((Pointer) monitorPtr).writeInt(0, monitorIdx); + return JvmtiError.JVMTI_ERROR_NONE; + } finally { + mutex.unlock(); + } + } + + private JvmtiError destroyRawMonitorInternal(JRawMonitorId monitorId) { + try { + mutex.lock(); + int monitorIdx = (int) monitorId.rawValue(); + if (isInvalidMonitorIdx(monitorIdx)) { + return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; + } + Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); + if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { + return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; + } + JvmtiError err = JvmtiRawMonitorHelper.exitCompletely(monitor); + if (err != JvmtiError.JVMTI_ERROR_NONE) { + return err; + } + if (!MultiThreadedMonitorSupport.singleton().isLockedByAnyThread(monitor)) { + return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; + } + NonmovableArrays.setInt(freeIndicesList, --nextAvailableIndex, monitorIdx); + return JvmtiError.JVMTI_ERROR_NONE; + } finally { + mutex.unlock(); + } + } + + private void initFreeList(NonmovableArray freeList) { + for (int i = 0; i < INITIAL_NB_AVAILABLE_SLOTS; i++) { + NonmovableArrays.setInt(freeList, i, i); + } + } + + private void increaseMonitorArraySize() { + int newMonitorArraySize = monitorArraySize * ARRAY_GROWTH_FACTOR; + + NonmovableObjectArray newMonitorArray = NonmovableArrays.createObjectArray(Object[].class, newMonitorArraySize, NmtCategory.JVMTI); + NonmovableArrays.arraycopy(monitorObjectsArray, 0, newMonitorArray, 0, monitorArraySize); + NonmovableArrays.releaseUnmanagedArray(monitorObjectsArray); + monitorObjectsArray = newMonitorArray; + + NonmovableArray newFreeIndicesList = NonmovableArrays.createIntArray(newMonitorArraySize, NmtCategory.JVMTI); + NonmovableArrays.arraycopy(freeIndicesList, 0, newFreeIndicesList, 0, monitorArraySize); + NonmovableArrays.releaseUnmanagedArray(freeIndicesList); + freeIndicesList = newFreeIndicesList; + + monitorArraySize = newMonitorArraySize; + } + + public void tearDown() { + if (monitorObjectsArray.isNonNull()) { + NonmovableArrays.releaseUnmanagedArray(monitorObjectsArray); + } + if (freeIndicesList.isNonNull()) { + NonmovableArrays.releaseUnmanagedArray(freeIndicesList); + } + } + + private int getNextFreeMonitorIdx() { + if (nextAvailableIndex + 1 == monitorArraySize) { + increaseMonitorArraySize(); + } + return NonmovableArrays.getInt(freeIndicesList, nextAvailableIndex++); + } + + private boolean isInvalidMonitorIdx(int monitorIdx) { + if (monitorIdx >= monitorArraySize) { + return true; + } + for (int i = nextAvailableIndex; i < monitorArraySize; i++) { + if (NonmovableArrays.getInt(freeIndicesList, i) == monitorIdx) { + return true; + } + } + return false; + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java new file mode 100644 index 000000000000..6c04cd08172c --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.thread.JavaThreads.isVirtual; +import static com.oracle.svm.core.thread.PlatformThreads.getCarrierSPOrElse; + +import org.graalvm.nativeimage.CurrentIsolate; +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.function.CodePointer; +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.NeverInline; +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.code.FrameInfoQueryResult; +import com.oracle.svm.core.heap.VMOperationInfos; +import com.oracle.svm.core.jdk.StackTraceUtils; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.access.JNIReflectionDictionary; +import com.oracle.svm.core.jni.headers.JNIMethodId; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfoPointer; +import com.oracle.svm.core.locks.VMMutex; +import com.oracle.svm.core.snippets.KnownIntrinsics; +import com.oracle.svm.core.stack.JavaStackFrameVisitor; +import com.oracle.svm.core.stack.JavaStackWalker; +import com.oracle.svm.core.thread.JavaThreads; +import com.oracle.svm.core.thread.NativeVMOperation; +import com.oracle.svm.core.thread.NativeVMOperationData; +import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMOperation; + +public final class JvmtiStackTraceUtil { + private static final int MAX_TEMP_BUFFER_SIZE = 64; + private static final long NATIVE_METHOD_LOCATION = -1; + private final VMMutex mutex; + private final JvmtiStackTraceVisitor stackTraceVisitor; + private final JvmtiFrameCountVisitor frameCountVisitor; + private final JvmtiStackTraceOperation stackTraceOperation; + private final JvmtiFrameCountOperation frameCountOperation; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiStackTraceUtil() { + this.mutex = new VMMutex("jvmti GetStackTrace Visitor"); + this.stackTraceVisitor = new JvmtiStackTraceVisitor(); + this.frameCountVisitor = new JvmtiFrameCountVisitor(); + this.stackTraceOperation = new JvmtiStackTraceOperation(); + this.frameCountOperation = new JvmtiFrameCountOperation(); + } + + public static JvmtiError getStackTrace(JThread jthread, int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer, CIntPointer countPtr) { + return ImageSingletons.lookup(JvmtiStackTraceUtil.class).getStackTraceInternal(jthread, startDepth, maxFrameCount, frameBuffer, countPtr); + } + + public static JvmtiError getFrameCount(JThread jthread, CIntPointer countPtr) { + return ImageSingletons.lookup(JvmtiStackTraceUtil.class).getFrameCountInternal(jthread, countPtr); + } + + private JvmtiError getStackTraceInternal(JThread jthread, int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer, CIntPointer countPtr) { + try { + mutex.lock(); + + // TODO @dprcci correct that logic? Do we want the program to crash + JvmtiError error = verifyJThreadHandle(jthread); + if (error != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + + if (!stackTraceVisitor.initialize(startDepth, maxFrameCount, frameBuffer)) { + return JvmtiError.JVMTI_ERROR_INTERNAL; + } + + int size = SizeOf.get(JvmtiStackWalkVMOperationData.class); + JvmtiStackWalkVMOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + data.setThreadHandle(jthread); + // JNIReflectionDictionary.singleton().dump(true, "egg"); + stackTraceOperation.enqueue(data); + + if (startDepth < 0) { + stackTraceVisitor.fillResultBuffer(); + } + countPtr.write(stackTraceVisitor.nbCollectedFrames); + return JvmtiError.JVMTI_ERROR_NONE; + } finally { + mutex.unlock(); + } + } + + @RawStructure + private interface JvmtiStackWalkVMOperationData extends NativeVMOperationData { + @RawField + JThread getThreadHandle(); + + @RawField + void setThreadHandle(JThread jthread); + } + + private class JvmtiStackTraceOperation extends NativeVMOperation { + JvmtiStackTraceOperation() { + super(VMOperationInfos.get(JvmtiStackTraceUtil.JvmtiStackTraceOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + protected void operate(NativeVMOperationData data) { + visitStackTrace((JvmtiStackWalkVMOperationData) data, stackTraceVisitor); + } + } + + @NeverInline(value = "jvmti GetStackTrace") + private void visitStackTrace(JvmtiStackWalkVMOperationData data, JavaStackFrameVisitor visitor) { + assert VMOperation.isInProgressAtSafepoint(); + + Thread thread = JNIObjectHandles.getObject(data.getThreadHandle()); + if (isVirtual(thread)) { + return; + } + Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); + IsolateThread isolateThread = PlatformThreads.getIsolateThread(thread); + + Pointer carrierSP = getCarrierSPOrElse(thread, WordFactory.nullPointer()); + if (isolateThread == CurrentIsolate.getCurrentThread()) { + Pointer startSP = carrierSP.isNonNull() ? carrierSP : callerSP; + Pointer endSP = WordFactory.nullPointer(); + JavaStackWalker.walkCurrentThread(startSP, endSP, visitor); + return; + } + + if (carrierSP.isNonNull()) { // mounted virtual thread, skip its frames + CodePointer carrierIP = FrameAccess.singleton().readReturnAddress(carrierSP); + Pointer endSP = WordFactory.nullPointer(); + assert VMOperation.isInProgressAtSafepoint(); + JavaStackWalker.walkThreadAtSafepoint(carrierSP, endSP, carrierIP, visitor); + return; + } + if (isolateThread.isNull()) { // recently launched thread + return; + } + Pointer endSP = WordFactory.nullPointer(); + JavaStackWalker.walkThread(isolateThread, endSP, visitor, null); + } + + public static boolean startDepthIsOutOfBound(int startDepth, int maxBound) { + boolean overOrEqualsMaxSize = startDepth > 0 && startDepth >= maxBound; + boolean belowMinSize = startDepth < 0 && startDepth < -maxBound; + return overOrEqualsMaxSize || belowMinSize; + } + + static class JvmtiStackTraceVisitor extends JavaStackFrameVisitor { + private JvmtiFrameInfoPointer jvmtiFramePtr; + private JvmtiFrameInfoPointer jvmtiFramePtrTemp; + private int nbFramesVisited; + private int startDepth; + private int maxFrameCount; + private int nbCollectedFrames; + + private JvmtiStackTraceVisitor() { + } + + boolean initialize(int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer) { + this.jvmtiFramePtr = frameBuffer; + this.startDepth = startDepth; + this.maxFrameCount = maxFrameCount; + this.nbFramesVisited = 0; + this.nbCollectedFrames = 0; + if (startDepth >= 0) { + return true; + } + if (-startDepth > MAX_TEMP_BUFFER_SIZE) { + return false; + } + jvmtiFramePtrTemp = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(SizeOf.get(JvmtiFrameInfo.class) * (-startDepth))); + return true; + } + + @Override + public boolean visitFrame(FrameInfoQueryResult frameInfo) { + if (!StackTraceUtils.shouldShowFrame(frameInfo, false, true, false)) { + /* Always ignore the frame. It is an internal frame of the VM. */ + return true; + + // TODO @dprcci useful? expand? + } else if (Throwable.class.isAssignableFrom(frameInfo.getSourceClass())) { + /* + * We are still in the constructor invocation chain at the beginning of the stack + * trace, which is also filtered by the Java HotSpot VM. + */ + return true; + } + + /* + * if the index is negative, the bottom the stack is the reference point, therefor we + * have to go all the way down. We reuse the same buffer to avoid useless memory + * allocation + */ + if (startDepth < 0) { + int index = nbCollectedFrames % (-startDepth); + assert jvmtiFramePtrTemp.isNonNull(); + nbCollectedFrames += convertToJvmtiFrameInfo(frameInfo, jvmtiFramePtrTemp, index, true); + return true; + } + + // TODO @dprcci What is the expected behaviour? Should a frame not containing a + // registered method be counted when going to startDepth? + if (nbCollectedFrames < maxFrameCount) { + int addedFrame = convertToJvmtiFrameInfo(frameInfo, jvmtiFramePtr, nbCollectedFrames, nbFramesVisited + 1 > startDepth); + nbFramesVisited += addedFrame; + if (nbFramesVisited > startDepth) { + nbCollectedFrames += addedFrame; + } + } + return nbCollectedFrames < maxFrameCount; + } + + private void fillResultBuffer() { + int bufferSize = -startDepth; + int resultSize = Math.min(bufferSize, maxFrameCount); + int oldestIndex = (maxFrameCount > nbCollectedFrames) ? 0 : nbCollectedFrames % bufferSize; + for (int i = 0; i < resultSize; i++) { + JvmtiFrameInfo res = getJvmtiFrameInfoAtIdx(jvmtiFramePtr, i); + JvmtiFrameInfo tmp = getJvmtiFrameInfoAtIdx(jvmtiFramePtrTemp, (oldestIndex + i) % bufferSize); + res.setMethod(tmp.getMethod()); + res.setLocation(tmp.getLocation()); + } + this.nbCollectedFrames = resultSize; + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(jvmtiFramePtrTemp); + } + + private int convertToJvmtiFrameInfo(FrameInfoQueryResult frameInfo, JvmtiFrameInfoPointer jvmtiFrameInfo, int index, boolean fill) { + long location = frameInfo.getBci(); + String methodName = frameInfo.getSourceMethodName(); + Class methodClass = frameInfo.getSourceClass(); + + JNIMethodId jMethodId = JNIReflectionDictionary.singleton().toMethodID(methodClass, methodName); + // JNIMethodId jMethodId = JNIReflectionDictionary.singleton().getRandomMethodID(); + // Method is not (should it be?) exposed to user, do not take it into account + if (jMethodId.isNull()) { + return 0; + } + if (!fill) { + return 1; + } + location = JNIReflectionDictionary.isMethodNative(jMethodId) ? NATIVE_METHOD_LOCATION : location; + JvmtiFrameInfo currentFrame = getJvmtiFrameInfoAtIdx(jvmtiFrameInfo, index); + currentFrame.setLocation(location); + currentFrame.setMethod(jMethodId); + return 1; + } + + private JvmtiFrameInfo getJvmtiFrameInfoAtIdx(JvmtiFrameInfoPointer jvmtiFrameInfo, int index) { + return (JvmtiFrameInfo) ((Pointer) jvmtiFrameInfo).add(index * SizeOf.get(JvmtiFrameInfo.class)); + } + } + + // Frame Count + + private JvmtiError getFrameCountInternal(JThread jthread, CIntPointer countPtr) { + try { + mutex.lock(); + JvmtiError error = verifyJThreadHandle(jthread); + if (error != JvmtiError.JVMTI_ERROR_NONE) { + return error; + } + + int size = SizeOf.get(JvmtiStackWalkVMOperationData.class); + JvmtiStackWalkVMOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + data.setThreadHandle(jthread); + frameCountOperation.enqueue(data); + + countPtr.write(frameCountVisitor.count); + return JvmtiError.JVMTI_ERROR_NONE; + } finally { + mutex.unlock(); + } + } + + private class JvmtiFrameCountOperation extends NativeVMOperation { + JvmtiFrameCountOperation() { + super(VMOperationInfos.get(JvmtiStackTraceUtil.JvmtiFrameCountOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + protected void operate(NativeVMOperationData data) { + frameCountVisitor.count = 0; + visitStackTrace((JvmtiStackWalkVMOperationData) data, frameCountVisitor); + } + } + + static class JvmtiFrameCountVisitor extends JavaStackFrameVisitor { + private int count = 0; + + private JvmtiFrameCountVisitor() { + } + + @Override + public boolean visitFrame(FrameInfoQueryResult frameInfo) { + if (!StackTraceUtils.shouldShowFrame(frameInfo, false, true, false)) { + return true; + } else if (Throwable.class.isAssignableFrom(frameInfo.getSourceClass())) { + return true; + } + // TODO @dprcci collect only frames with contain accessible information? + this.count += 1; + return true; + } + } + + // Helpers + + private static JvmtiError verifyJThreadHandle(JThread jthread) { + Thread thread; + if (jthread.equal(WordFactory.nullPointer())) { + thread = JavaThreads.getCurrentThreadOrNull(); + } else { + try { + Object threadReference = JNIObjectHandles.getObject(jthread); + thread = (Thread) threadReference; + } catch (IllegalArgumentException | ClassCastException e) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD; + } + } + if (thread == null) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD; + } + if (!thread.isAlive()) { + return JvmtiError.JVMTI_ERROR_THREAD_NOT_ALIVE; + } + return JvmtiError.JVMTI_ERROR_NONE; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java new file mode 100644 index 000000000000..606df137ac13 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.jdk.UninterruptibleUtils; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JThreadGroup; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiThreadInfo; +import com.oracle.svm.core.thread.JavaThreads; + +public final class JvmtiThreadActionsUtil { + + private JvmtiThreadActionsUtil() { + } + + public static int interruptThread(JThread jthread) { + // TODO @dprcci refactor + Thread thread; + try { + Object threadReference = JNIObjectHandles.getObject(jthread); + thread = (Thread) threadReference; + } catch (IllegalArgumentException | ClassCastException e) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue(); + } + if (thread == null) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue(); + } + if (!thread.isAlive()) { + return JvmtiError.JVMTI_ERROR_THREAD_NOT_ALIVE.getCValue(); + } + // TODO @dprcci check if works + try { + thread.interrupt(); + } catch (SecurityException e) { + return JvmtiError.JVMTI_ERROR_INTERNAL.getCValue(); + } + return JvmtiError.JVMTI_ERROR_NONE.getCValue(); + } + + public static JvmtiError getThreadInfo(JThread jthread, JvmtiThreadInfo infoPtr) { + Thread thread; + if (jthread.equal(WordFactory.nullPointer())) { + thread = JavaThreads.getCurrentThreadOrNull(); + } else { + try { + Object threadReference = JNIObjectHandles.getObject(jthread); + thread = (Thread) threadReference; + } catch (IllegalArgumentException | ClassCastException e) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD; + } + } + if (thread == null) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD; + } + + String name = thread.getName(); + int priority = thread.getPriority(); + boolean isDaemon = thread.isDaemon(); + ThreadGroup threadGroup = thread.getThreadGroup(); + ClassLoader contextClassLoader = thread.getContextClassLoader(); + + int nameModifiedUTF8Length = UninterruptibleUtils.String.modifiedUTF8Length(name, true); + CCharPointer nameBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(nameModifiedUTF8Length)); + UninterruptibleUtils.String.toModifiedUTF8(name, (Pointer) nameBuffer, ((Pointer) nameBuffer).add(nameModifiedUTF8Length), true); + + JThreadGroup threadGroupHandle = (JThreadGroup) JNIObjectHandles.createLocal(threadGroup); + JNIObjectHandle contextClassLoaderHandle = JNIObjectHandles.createLocal(contextClassLoader); + + infoPtr.setName(nameBuffer); + infoPtr.setPriority(priority); + infoPtr.setIsDaemon(isDaemon); + infoPtr.setThreadGroup(threadGroupHandle); + infoPtr.setContextClassLoader(contextClassLoaderHandle); + + return JvmtiError.JVMTI_ERROR_NONE; + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java new file mode 100644 index 000000000000..51278f3c4d3b --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.IsolateThread; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.heap.VMOperationInfos; +import com.oracle.svm.core.jdk.UninterruptibleUtils; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JThreadGroup; +import com.oracle.svm.core.jvmti.headers.JThreadGroupPointer; +import com.oracle.svm.core.jvmti.headers.JThreadGroupPointerPointer; +import com.oracle.svm.core.jvmti.headers.JThreadPointer; +import com.oracle.svm.core.jvmti.headers.JThreadPointerPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.JvmtiThreadGroupInfo; +import com.oracle.svm.core.jvmti.utils.JvmtiUtils; +import com.oracle.svm.core.thread.JavaLangThreadGroupSubstitutions; +import com.oracle.svm.core.thread.JavaThreads; +import com.oracle.svm.core.thread.NativeVMOperation; +import com.oracle.svm.core.thread.NativeVMOperationData; +import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.VMThreads; + +import jdk.graal.compiler.api.replacements.Fold; + +public class JvmtiThreadGroupUtil { + + private final JvmtiGetThreadGroupChildrenOperation getThreadGroupChildrenOperation; + private static final int INITIAL_THREAD_BUFFER_CAPACITY = 50; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiThreadGroupUtil() { + getThreadGroupChildrenOperation = new JvmtiGetThreadGroupChildrenOperation(); + } + + @Fold + public static JvmtiThreadGroupUtil singleton() { + return ImageSingletons.lookup(JvmtiThreadGroupUtil.class); + } + + public static JvmtiError getTopThreadGroups(CIntPointer groupCountPtr, JThreadGroupPointerPointer groupsPtr) { + ThreadGroup top = PlatformThreads.singleton().systemGroup; + JThreadGroup topHandle = (JThreadGroup) JNIObjectHandles.createLocal(top); + + JThreadGroupPointer topArray = JvmtiUtils.allocateWordBuffer(1); + if (topArray.isNull()) { + return JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; + } + + JvmtiUtils.writeWordAtIdxInBuffer(topArray, 0, topHandle); + + ((Pointer) groupsPtr).writeWord(0, topArray); + groupCountPtr.write(1); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getThreadGroupInfo(JThreadGroup group, JvmtiThreadGroupInfo infoPtr) { + CIntPointer errorPtr = StackValue.get(CIntPointer.class); + ThreadGroup threadGroup = getThreadGroupFromHandle(group, errorPtr); + if (JvmtiError.fromValue(errorPtr.read()) != JvmtiError.JVMTI_ERROR_NONE) { + return JvmtiError.fromValue(errorPtr.read()); + } + ThreadGroup parentGroup = threadGroup.getParent(); + String groupName = threadGroup.getName(); + int groupMaxPriority = threadGroup.getMaxPriority(); + // No longer valid + boolean isDeamonGroup = false; + + fillThreadGroupInfo(infoPtr, parentGroup, groupName, groupMaxPriority, isDeamonGroup); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError getThreadGroupChildren(JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, + CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { + return singleton().getThreadGroupChildrenInternal(group, threadCountPtr, threadsPtr, groupCountPtr, groupsPtr); + } + + private JvmtiError getThreadGroupChildrenInternal(JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, + CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { + CIntPointer errorPtr = StackValue.get(CIntPointer.class); + + ThreadGroup threadGroup = getThreadGroupFromHandle(group, errorPtr); + if (JvmtiError.fromValue(errorPtr.read()) != JvmtiError.JVMTI_ERROR_NONE) { + return JvmtiError.fromValue(errorPtr.read()); + } + + int size = SizeOf.get(JvmtiThreadGroupVMOperationData.class); + JvmtiThreadGroupVMOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + int activeCountEstimate = threadGroup.activeCount(); + int activeGroupCountEstimate = threadGroup.activeCount(); + data.setJThreadBufferSize(activeCountEstimate > 0 ? activeCountEstimate : INITIAL_THREAD_BUFFER_CAPACITY); + data.setJThreadGroupBufferSize(activeGroupCountEstimate > 0 ? activeGroupCountEstimate : INITIAL_THREAD_BUFFER_CAPACITY); + + data.setJThreadGroup(group); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + + getThreadGroupChildrenOperation.enqueue(data); + if (JvmtiError.fromValue(data.getJvmtiError()) != JvmtiError.JVMTI_ERROR_NONE) { + return JvmtiError.fromValue(data.getJvmtiError()); + } + + threadCountPtr.write(data.getJThreadBufferSize()); + ((Pointer) threadsPtr).writeWord(0, data.getJThreadBuffer()); + + groupCountPtr.write(data.getJThreadGroupBufferSize()); + ((Pointer) groupsPtr).writeWord(0, data.getJThreadGroupBuffer()); + return JvmtiError.JVMTI_ERROR_NONE; + } + + // Could be refactored + @Uninterruptible(reason = "jvmti getThreadGroupChildren") + private static void getThreadGroupChildren(JvmtiThreadGroupVMOperationData data) { + int threadGroupsBufferSize = data.getJThreadGroupBufferSize(); + int threadsBufferSize = data.getJThreadBufferSize(); + JThreadGroupPointer threadGroupsBuffer = JvmtiUtils.allocateWordBuffer(threadGroupsBufferSize); + JThreadPointer threadsBuffer = JvmtiUtils.allocateWordBuffer(threadsBufferSize); + + ThreadGroup targetThreadGroup = JNIObjectHandles.getObject(data.getJThreadGroup()); + + int nbThreadsWritten = 0; + int nbThreadGroupsWritten = 0; + + for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { + Thread thread = PlatformThreads.fromVMThread(isolateThread); + // "Get all live platform threads that are attached to the VM" + if (thread == null || thread.isVirtual() || !JavaThreads.isAlive(thread)) { + continue; + } + ThreadGroup currentThreadGroup = JavaThreads.getRawThreadGroup(thread); + // Collect subgroups + if (JavaLangThreadGroupSubstitutions.getParentThreadGroupUnsafe(currentThreadGroup) == targetThreadGroup) { + if (nbThreadGroupsWritten == threadGroupsBufferSize) { + threadGroupsBuffer = JvmtiUtils.growWordBuffer(threadGroupsBuffer, 2 * threadGroupsBufferSize); + threadGroupsBufferSize = 2 * threadGroupsBufferSize; + if (threadGroupsBuffer.isNull()) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY.getCValue()); + JvmtiUtils.freeWordBuffer(threadsBuffer); + return; + } + } + JThreadGroup threadGroupHandle = (JThreadGroup) JNIObjectHandles.createLocal(currentThreadGroup); + JvmtiUtils.writeWordAtIdxInBuffer(threadGroupsBuffer, nbThreadGroupsWritten, threadGroupHandle); + nbThreadGroupsWritten++; + } + // Collect threads belonging to group + if (currentThreadGroup == targetThreadGroup) { + if (nbThreadsWritten == threadsBufferSize) { + threadsBuffer = JvmtiUtils.growWordBuffer(threadsBuffer, 2 * threadsBufferSize); + threadsBufferSize = 2 * threadsBufferSize; + if (threadsBuffer.isNull()) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY.getCValue()); + JvmtiUtils.freeWordBuffer(threadGroupsBuffer); + return; + } + } + JThread threadHandle = (JThread) JNIObjectHandles.createLocal(thread); + JvmtiUtils.writeWordAtIdxInBuffer(threadGroupsBuffer, nbThreadGroupsWritten, threadHandle); + nbThreadsWritten++; + } + } + data.setJThreadGroupBuffer(threadGroupsBuffer); + data.setJThreadGroupBufferSize(nbThreadGroupsWritten); + data.setJThreadBuffer(threadsBuffer); + data.setJThreadBufferSize(nbThreadsWritten); + } + + @RawStructure + private interface JvmtiThreadGroupVMOperationData extends NativeVMOperationData { + @RawField + JThreadGroup getJThreadGroup(); + + @RawField + void setJThreadGroup(JThreadGroup ptr); + + @RawField + void setJvmtiError(int err); + + @RawField + int getJvmtiError(); + + @RawField + void setJThreadBuffer(JThreadPointer ptr); + + @RawField + JThreadPointer getJThreadBuffer(); + + @RawField + void setJThreadBufferSize(int size); + + @RawField + int getJThreadBufferSize(); + + @RawField + void setJThreadGroupBuffer(JThreadGroupPointer ptr); + + @RawField + JThreadGroupPointer getJThreadGroupBuffer(); + + @RawField + void setJThreadGroupBufferSize(int size); + + @RawField + int getJThreadGroupBufferSize(); + } + + private static class JvmtiGetThreadGroupChildrenOperation extends NativeVMOperation { + JvmtiGetThreadGroupChildrenOperation() { + super(VMOperationInfos.get(JvmtiGetThreadGroupChildrenOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + protected void operate(NativeVMOperationData data) { + getThreadGroupChildren((JvmtiThreadGroupVMOperationData) data); + } + } + + private static void fillThreadGroupInfo(JvmtiThreadGroupInfo infoPtr, ThreadGroup parent, String name, int maxPriority, boolean isDaemon) { + JThreadGroup parentHandle = (JThreadGroup) JNIObjectHandles.createLocal(parent); + int nameSize = UninterruptibleUtils.String.modifiedUTF8Length(name, true, null); + CCharPointer nameBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(nameSize)); + UninterruptibleUtils.String.toModifiedUTF8(name, (Pointer) nameBuffer, ((Pointer) nameBuffer).add(nameSize), true); + + infoPtr.setParent(parentHandle); + infoPtr.setName(nameBuffer); + infoPtr.setMaxPriority(maxPriority); + infoPtr.setIsDaemon(isDaemon); + } + + private static ThreadGroup getThreadGroupFromHandle(JThreadGroup handle, CIntPointer error) { + ThreadGroup threadGroup; + try { + threadGroup = JNIObjectHandles.getObject(handle); + } catch (ClassCastException | IllegalArgumentException e) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_THREAD_GROUP.getCValue()); + return null; + } + if (threadGroup == null) { + error.write(JvmtiError.JVMTI_ERROR_INVALID_THREAD_GROUP.getCValue()); + return null; + } + error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + return threadGroup; + } + + private static T allocateReturnArray(int nbElement) { + return ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(nbElement * ConfigurationValues.getTarget().wordSize)); + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java new file mode 100644 index 000000000000..8f43d9821732 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; +import com.oracle.svm.core.jvmti.utils.JvmtiLocalStorageUtil; + +import jdk.graal.compiler.api.replacements.Fold; + +public final class JvmtiThreadLocalStorage extends JvmtiLocalStorageUtil { + + private static final int INITIAL_CAPACITY = 8; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiThreadLocalStorage() { + super("Jvmti Thread Local Storage"); + } + + public void initialize() { + super.initialize(INITIAL_CAPACITY); + } + + @Fold + public static JvmtiThreadLocalStorage singleton() { + return ImageSingletons.lookup(JvmtiThreadLocalStorage.class); + } + + public static JvmtiError setThreadLocalStorage(JThread thread, VoidPointer data) { + JvmtiError threadError = isValidThread(thread); + if (threadError != JvmtiError.JVMTI_ERROR_NONE) { + return threadError; + } + return singleton().setThreadLocalStorageInternal(thread, data); + } + + public static JvmtiError getThreadLocalStorage(JThread thread, VoidPointerPointer dataPtr) { + JvmtiError threadError = isValidThread(thread); + if (threadError != JvmtiError.JVMTI_ERROR_NONE) { + return threadError; + } + return singleton().getThreadLocalStorageInternal(thread, dataPtr); + } + + private JvmtiError getThreadLocalStorageInternal(JThread thread, VoidPointerPointer dataPtr) { + thread = ensureCorrectJThread(thread); + VoidPointer data = super.contains(thread) ? super.get(thread) : WordFactory.nullPointer(); + ((Pointer) dataPtr).writeWord(0, data); + return JvmtiError.JVMTI_ERROR_NONE; + } + + private JvmtiError setThreadLocalStorageInternal(JThread thread, VoidPointer data) { + thread = ensureCorrectJThread(thread); + super.put(thread, data); + return JvmtiError.JVMTI_ERROR_NONE; + } + + private static JThread ensureCorrectJThread(JThread thread) { + return thread.equal(WordFactory.nullPointer()) ? (JThread) JNIObjectHandles.createLocal(Thread.currentThread()) : thread; + } + + private static JvmtiError isValidThread(JThread jthread) { + Thread thread; + try { + Object threadReference = JNIObjectHandles.getObject(jthread); + thread = (Thread) threadReference; + } catch (IllegalArgumentException | ClassCastException e) { + return JvmtiError.JVMTI_ERROR_INVALID_THREAD; + } + if (thread == null) { + thread = Thread.currentThread(); + } + if (!thread.isAlive()) { + return JvmtiError.JVMTI_ERROR_THREAD_NOT_ALIVE; + } + return JvmtiError.JVMTI_ERROR_NONE; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java new file mode 100644 index 000000000000..4a6343e3b193 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_ALIVE; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_INTERRUPTED; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_IN_NATIVE; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_IN_OBJECT_WAIT; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_PARKED; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_RUNNABLE; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_SLEEPING; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_TERMINATED; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_WAITING; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_WAITING_INDEFINITELY; +import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.StackValue; +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.c.type.CIntPointer; +import org.graalvm.word.Pointer; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.UnmanagedMemoryUtil; +import com.oracle.svm.core.heap.VMOperationInfos; +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JvmtiError; +import com.oracle.svm.core.monitor.MonitorSupport; +import com.oracle.svm.core.thread.JavaThreads; +import com.oracle.svm.core.thread.NativeVMOperation; +import com.oracle.svm.core.thread.NativeVMOperationData; +import com.oracle.svm.core.thread.PlatformThreads; +import com.oracle.svm.core.thread.ThreadStatus; +import com.oracle.svm.core.thread.VMThreads; + +public final class JvmtiThreadStateUtil { + private final JvmtiGetThreadStateOperation stateOperation; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiThreadStateUtil() { + this.stateOperation = new JvmtiGetThreadStateOperation(); + } + + public static int getThreadState(JThread jthread, CIntPointer statePtr) { + return ImageSingletons.lookup(JvmtiThreadStateUtil.class).getThreadStateInternal(jthread, statePtr); + } + + private int getThreadStateInternal(JThread jthread, CIntPointer statePtr) { + int size = SizeOf.get(JvmtiGetThreadStateOperationData.class); + JvmtiGetThreadStateOperationData data = StackValue.get(size); + UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); + + data.setJThreadPointer(jthread); + data.setThreadStatePointer(statePtr); + stateOperation.enqueue(data); + return data.getJvmtiError(); + } + + @RawStructure + private interface JvmtiGetThreadStateOperationData extends NativeVMOperationData { + @RawField + void setThreadStatePointer(CIntPointer ptr); + + @RawField + CIntPointer getThreadStatePointer(); + + @RawField + int getJvmtiError(); + + @RawField + void setJvmtiError(int error); + + @RawField + void setJThreadPointer(JThread ptr); + + @RawField + JThread getJThreadPointer(); + } + + // TODO @dprcci cannot allocate memory + private static class JvmtiGetThreadStateOperation extends NativeVMOperation { + JvmtiGetThreadStateOperation() { + super(VMOperationInfos.get(JvmtiGetThreadStateOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); + } + + @Override + // @RestrictHeapAccess(reason = "jvmti", access = RestrictHeapAccess.Access.NO_ALLOCATION) + protected void operate(NativeVMOperationData data) { + getThreadState((JvmtiGetThreadStateOperationData) data); + } + } + + private static void getThreadState(JvmtiGetThreadStateOperationData data) { + JThread jthread = data.getJThreadPointer(); + Thread thread; + try { + Object threadReference = JNIObjectHandles.getObject(jthread); + thread = (Thread) threadReference; + } catch (IllegalArgumentException | ClassCastException e) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue()); + return; + } + if (thread == null) { + thread = JavaThreads.getCurrentThreadOrNull(); + if (thread == null) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); + return; + } + } + int result = getThreadState(thread); + // TODO @dprcci better and more consistent error handling + if (result == -1) { + data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); + return; + } + data.getThreadStatePointer().write(result); + data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); + } + + // TODO @dprcci check + protected static int getThreadState(Thread thread) { + int result = 0; + + Thread.State state = thread.getState(); + if (!thread.isAlive()) { + return (state == Thread.State.TERMINATED) ? JVMTI_THREAD_STATE_TERMINATED.getValue() : 0; + } + + result |= JVMTI_THREAD_STATE_ALIVE.getValue(); + + // threads cannot be suspended + + // Interrupted + if (thread.isInterrupted()) { // if(JavaThreads.isInterrupted(thread)){ + result |= JVMTI_THREAD_STATE_INTERRUPTED.getValue(); + } + // TODO @dprcci Correct IsoalteThread but doesn't work because it is put into safe point + if (VMThreads.StatusSupport.getStatusVolatile(PlatformThreads.getIsolateThread(thread)) == VMThreads.StatusSupport.STATUS_IN_NATIVE) { + result |= JVMTI_THREAD_STATE_IN_NATIVE.getValue(); + } + + if (state == Thread.State.RUNNABLE) { + result |= JVMTI_THREAD_STATE_RUNNABLE.getValue(); + return result; + } + if (state == Thread.State.BLOCKED) { + result |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER.getValue(); + return result; + } + + // Waiting + boolean timedWait; + if ((timedWait = (state != Thread.State.WAITING)) && state != Thread.State.TIMED_WAITING) { + return -1; + } + + result |= JVMTI_THREAD_STATE_WAITING.getValue(); + result |= (timedWait) ? JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT.getValue() : JVMTI_THREAD_STATE_WAITING_INDEFINITELY.getValue(); + + // Waiting reason + int waitingStatus = MonitorSupport.singleton().getParkedThreadStatus(thread, timedWait); + if (waitingStatus == ThreadStatus.IN_OBJECT_WAIT) { + result |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT.getValue(); + } else if (waitingStatus == ThreadStatus.PARKED || waitingStatus == ThreadStatus.PARKED_TIMED) { + result |= JVMTI_THREAD_STATE_PARKED.getValue(); + } + // Sleeping + if (PlatformThreads.getThreadStatus(thread) == ThreadStatus.SLEEPING) { + result |= JVMTI_THREAD_STATE_SLEEPING.getValue(); + } + return result; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java new file mode 100644 index 000000000000..35cd3804f2ed --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +// TEMP (chaeubl): should be uint_8 +@CPointerTo(nameOfCType = "char") +public interface BooleanPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointerPointer.java new file mode 100644 index 000000000000..8c1b1b5bbc95 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JThreadGroupPointerPointer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.word.PointerBase; + +public interface JThreadGroupPointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java index c92317882a01..a268002825f8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java @@ -26,6 +26,7 @@ import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.constant.CEnum; +import org.graalvm.nativeimage.c.constant.CEnumConstant; import org.graalvm.nativeimage.c.constant.CEnumLookup; import org.graalvm.nativeimage.c.constant.CEnumValue; @@ -33,62 +34,116 @@ @CContext(JvmtiDirectives.class) public enum JvmtiError { /* Universal errors. */ + @CEnumConstant("JVMTI_ERROR_NONE") // JVMTI_ERROR_NONE, + + @CEnumConstant("JVMTI_ERROR_NULL_POINTER") JVMTI_ERROR_NULL_POINTER, + @CEnumConstant("JVMTI_ERROR_OUT_OF_MEMORY") JVMTI_ERROR_OUT_OF_MEMORY, + @CEnumConstant("JVMTI_ERROR_ACCESS_DENIED") JVMTI_ERROR_ACCESS_DENIED, + @CEnumConstant("JVMTI_ERROR_UNATTACHED_THREAD") JVMTI_ERROR_UNATTACHED_THREAD, + @CEnumConstant("JVMTI_ERROR_INVALID_ENVIRONMENT") JVMTI_ERROR_INVALID_ENVIRONMENT, + @CEnumConstant("JVMTI_ERROR_WRONG_PHASE") JVMTI_ERROR_WRONG_PHASE, + @CEnumConstant("JVMTI_ERROR_INTERNAL") JVMTI_ERROR_INTERNAL, /* Function specific errors. */ + @CEnumConstant("JVMTI_ERROR_INVALID_PRIORITY") JVMTI_ERROR_INVALID_PRIORITY, + @CEnumConstant("JVMTI_ERROR_THREAD_NOT_SUSPENDED") JVMTI_ERROR_THREAD_NOT_SUSPENDED, + @CEnumConstant("JVMTI_ERROR_THREAD_SUSPENDED") JVMTI_ERROR_THREAD_SUSPENDED, + @CEnumConstant("JVMTI_ERROR_THREAD_NOT_ALIVE") JVMTI_ERROR_THREAD_NOT_ALIVE, + @CEnumConstant("JVMTI_ERROR_CLASS_NOT_PREPARED") JVMTI_ERROR_CLASS_NOT_PREPARED, + @CEnumConstant("JVMTI_ERROR_NO_MORE_FRAMES") JVMTI_ERROR_NO_MORE_FRAMES, + @CEnumConstant("JVMTI_ERROR_OPAQUE_FRAME") JVMTI_ERROR_OPAQUE_FRAME, + @CEnumConstant("JVMTI_ERROR_DUPLICATE") JVMTI_ERROR_DUPLICATE, + @CEnumConstant("JVMTI_ERROR_NOT_FOUND") JVMTI_ERROR_NOT_FOUND, + @CEnumConstant("JVMTI_ERROR_NOT_MONITOR_OWNER") JVMTI_ERROR_NOT_MONITOR_OWNER, + @CEnumConstant("JVMTI_ERROR_INTERRUPT") JVMTI_ERROR_INTERRUPT, + @CEnumConstant("JVMTI_ERROR_UNMODIFIABLE_CLASS") JVMTI_ERROR_UNMODIFIABLE_CLASS, + @CEnumConstant("JVMTI_ERROR_UNMODIFIABLE_MODULE") JVMTI_ERROR_UNMODIFIABLE_MODULE, + @CEnumConstant("JVMTI_ERROR_NOT_AVAILABLE") JVMTI_ERROR_NOT_AVAILABLE, + @CEnumConstant("JVMTI_ERROR_ABSENT_INFORMATION") JVMTI_ERROR_ABSENT_INFORMATION, + @CEnumConstant("JVMTI_ERROR_INVALID_EVENT_TYPE") JVMTI_ERROR_INVALID_EVENT_TYPE, + @CEnumConstant("JVMTI_ERROR_NATIVE_METHOD") JVMTI_ERROR_NATIVE_METHOD, + @CEnumConstant("JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED") JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED, /* Function specific agent errors. */ + @CEnumConstant("JVMTI_ERROR_INVALID_THREAD") JVMTI_ERROR_INVALID_THREAD, + @CEnumConstant("JVMTI_ERROR_INVALID_FIELDID") JVMTI_ERROR_INVALID_FIELDID, + @CEnumConstant("JVMTI_ERROR_INVALID_MODULE") JVMTI_ERROR_INVALID_MODULE, + @CEnumConstant("JVMTI_ERROR_INVALID_METHODID") JVMTI_ERROR_INVALID_METHODID, + @CEnumConstant("JVMTI_ERROR_INVALID_LOCATION") JVMTI_ERROR_INVALID_LOCATION, + @CEnumConstant("JVMTI_ERROR_INVALID_OBJECT") JVMTI_ERROR_INVALID_OBJECT, + @CEnumConstant("JVMTI_ERROR_INVALID_CLASS") JVMTI_ERROR_INVALID_CLASS, + @CEnumConstant("JVMTI_ERROR_TYPE_MISMATCH") JVMTI_ERROR_TYPE_MISMATCH, + @CEnumConstant("JVMTI_ERROR_INVALID_SLOT") JVMTI_ERROR_INVALID_SLOT, + @CEnumConstant("JVMTI_ERROR_MUST_POSSESS_CAPABILITY") JVMTI_ERROR_MUST_POSSESS_CAPABILITY, + @CEnumConstant("JVMTI_ERROR_INVALID_THREAD_GROUP") JVMTI_ERROR_INVALID_THREAD_GROUP, + @CEnumConstant("JVMTI_ERROR_INVALID_MONITOR") JVMTI_ERROR_INVALID_MONITOR, + @CEnumConstant("JVMTI_ERROR_ILLEGAL_ARGUMENT") JVMTI_ERROR_ILLEGAL_ARGUMENT, + @CEnumConstant("JVMTI_ERROR_INVALID_TYPESTATE") JVMTI_ERROR_INVALID_TYPESTATE, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_VERSION") JVMTI_ERROR_UNSUPPORTED_VERSION, + @CEnumConstant("JVMTI_ERROR_INVALID_CLASS_FORMAT") JVMTI_ERROR_INVALID_CLASS_FORMAT, + @CEnumConstant("JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION") JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED, + @CEnumConstant("JVMTI_ERROR_FAILS_VERIFICATION") JVMTI_ERROR_FAILS_VERIFICATION, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED, + @CEnumConstant("JVMTI_ERROR_NAMES_DONT_MATCH") JVMTI_ERROR_NAMES_DONT_MATCH, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED, + @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_OPERATION") JVMTI_ERROR_UNSUPPORTED_OPERATION; @CEnumValue diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java index da8a02ed81e4..b4cafcf6df77 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java @@ -32,47 +32,50 @@ @CEnum("jvmtiEvent") @CContext(JvmtiDirectives.class) public enum JvmtiEvent { - JVMTI_EVENT_VM_INIT(true, true), - JVMTI_EVENT_VM_DEATH(true, true), - JVMTI_EVENT_THREAD_START(true, false), - JVMTI_EVENT_THREAD_END(false, false), - JVMTI_EVENT_CLASS_FILE_LOAD_HOOK(false, false), - JVMTI_EVENT_CLASS_LOAD(false, false), - JVMTI_EVENT_CLASS_PREPARE(false, false), - JVMTI_EVENT_VM_START(true, true), - JVMTI_EVENT_EXCEPTION(false, false), - JVMTI_EVENT_EXCEPTION_CATCH(false, false), - JVMTI_EVENT_SINGLE_STEP(false, false), - JVMTI_EVENT_FRAME_POP(false, false), - JVMTI_EVENT_BREAKPOINT(false, false), - JVMTI_EVENT_FIELD_ACCESS(false, false), - JVMTI_EVENT_FIELD_MODIFICATION(false, false), - JVMTI_EVENT_METHOD_ENTRY(false, false), - JVMTI_EVENT_METHOD_EXIT(false, false), - JVMTI_EVENT_NATIVE_METHOD_BIND(false, false), - JVMTI_EVENT_COMPILED_METHOD_LOAD(true, false), - JVMTI_EVENT_COMPILED_METHOD_UNLOAD(true, false), - JVMTI_EVENT_DYNAMIC_CODE_GENERATED(true, false), - JVMTI_EVENT_DATA_DUMP_REQUEST(true, false), - JVMTI_EVENT_MONITOR_WAIT(false, false), - JVMTI_EVENT_MONITOR_WAITED(false, false), - JVMTI_EVENT_MONITOR_CONTENDED_ENTER(false, false), - JVMTI_EVENT_MONITOR_CONTENDED_ENTERED(false, false), - JVMTI_EVENT_RESOURCE_EXHAUSTED(false, false), - JVMTI_EVENT_GARBAGE_COLLECTION_START(false, false), - JVMTI_EVENT_GARBAGE_COLLECTION_FINISH(false, false), - JVMTI_EVENT_OBJECT_FREE(false, false), - JVMTI_EVENT_VM_OBJECT_ALLOC(false, false), - JVMTI_EVENT_SAMPLED_OBJECT_ALLOC(false, false), - JVMTI_EVENT_VIRTUAL_THREAD_START(false, false), - JVMTI_EVENT_VIRTUAL_THREAD_END(false, false); + JVMTI_EVENT_VM_INIT(true, true, 1), + JVMTI_EVENT_VM_DEATH(true, true, 0), + JVMTI_EVENT_THREAD_START(true, true, 1), + JVMTI_EVENT_THREAD_END(false, true, 1), + JVMTI_EVENT_CLASS_FILE_LOAD_HOOK(false, false, 8), + JVMTI_EVENT_CLASS_LOAD(false, false, 2), + JVMTI_EVENT_CLASS_PREPARE(false, false, 2), + JVMTI_EVENT_VM_START(true, true, 0), + JVMTI_EVENT_EXCEPTION(false, false, 6), + JVMTI_EVENT_EXCEPTION_CATCH(false, false, 4), + JVMTI_EVENT_SINGLE_STEP(false, false, 3), + JVMTI_EVENT_FRAME_POP(false, false, 3), + JVMTI_EVENT_BREAKPOINT(false, false, 3), + JVMTI_EVENT_FIELD_ACCESS(false, false, 6), + JVMTI_EVENT_FIELD_MODIFICATION(false, false, 8), + JVMTI_EVENT_METHOD_ENTRY(true, false, 2), + JVMTI_EVENT_METHOD_EXIT(false, false, 4), + JVMTI_EVENT_NATIVE_METHOD_BIND(false, false, 4), + JVMTI_EVENT_COMPILED_METHOD_LOAD(true, false, 6), + JVMTI_EVENT_COMPILED_METHOD_UNLOAD(true, false, 3), + JVMTI_EVENT_DYNAMIC_CODE_GENERATED(true, false, 3), + JVMTI_EVENT_DATA_DUMP_REQUEST(true, false, 0), + JVMTI_EVENT_MONITOR_WAIT(false, true, 3), + JVMTI_EVENT_MONITOR_WAITED(false, true, 3), + JVMTI_EVENT_MONITOR_CONTENDED_ENTER(false, true, 2), + JVMTI_EVENT_MONITOR_CONTENDED_ENTERED(false, true, 2), + JVMTI_EVENT_RESOURCE_EXHAUSTED(false, false, 3), + JVMTI_EVENT_GARBAGE_COLLECTION_START(false, true, 0), + JVMTI_EVENT_GARBAGE_COLLECTION_FINISH(false, true, 0), + JVMTI_EVENT_OBJECT_FREE(false, false, 1), + JVMTI_EVENT_VM_OBJECT_ALLOC(false, false, 4), + JVMTI_EVENT_SAMPLED_OBJECT_ALLOC(false, false, 4), + JVMTI_EVENT_VIRTUAL_THREAD_START(false, false, 1), + JVMTI_EVENT_VIRTUAL_THREAD_END(false, false, 1); private final boolean isSupported; private final boolean isGlobal; + private final int nbParameters; - JvmtiEvent(boolean isGlobal, boolean isSupported) { + JvmtiEvent(boolean isGlobal, boolean isSupported, int nbParameters) { this.isGlobal = isGlobal; this.isSupported = isSupported; + this.nbParameters = nbParameters; + } public boolean isSupported() { @@ -83,6 +86,10 @@ public boolean isGlobal() { return isGlobal; } + public int getNbParameters() { + return nbParameters; + } + @CEnumValue public native int getCValue(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java index 8208ba742924..8c0b1bafb384 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.jvmti.headers; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; @@ -47,10 +48,10 @@ public interface JvmtiEventCallbacks extends PointerBase { JvmtiEventVMDeathFunctionPointer getVMDeath(); @CField - CFunctionPointer getThreadStart(); + JvmtiEventThreadStartFunctionPointer getThreadStart(); @CField - CFunctionPointer getThreadEnd(); + JvmtiEventThreadEndFunctionPointer getThreadEnd(); @CField CFunctionPointer getClassFileLoadHook(); @@ -110,16 +111,16 @@ public interface JvmtiEventCallbacks extends PointerBase { CFunctionPointer getReserved72(); @CField - CFunctionPointer getMonitorWait(); + JvmtiEventMonitorWaitFunctionPointer getMonitorWait(); @CField - CFunctionPointer getMonitorWaited(); + JvmtiEventMonitorWaitedFunctionPointer getMonitorWaited(); @CField - CFunctionPointer getMonitorContendedEnter(); + JvmtiEventMonitorContendedEnterFunctionPointer getMonitorContendedEnter(); @CField - CFunctionPointer getMonitorContendedEntered(); + JvmtiEventMonitorContendedEnteredFunctionPointer getMonitorContendedEntered(); @CField("reserved77") CFunctionPointer getReserved77(); @@ -134,10 +135,10 @@ public interface JvmtiEventCallbacks extends PointerBase { CFunctionPointer getResourceExhausted(); @CField - CFunctionPointer getGarbageCollectionStart(); + JvmtiEventGarbageCollectionStartFunctionPointer getGarbageCollectionStart(); @CField - CFunctionPointer getGarbageCollectionFinish(); + JvmtiEventGarbageCollectionFinishFunctionPointer getGarbageCollectionFinish(); @CField CFunctionPointer getObjectFree(); @@ -171,4 +172,44 @@ interface JvmtiEventVMStartFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); } + + interface JvmtiEventGarbageCollectionFinishFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv); + } + + interface JvmtiEventGarbageCollectionStartFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv); + } + + interface JvmtiEventThreadStartFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread); + } + + interface JvmtiEventThreadEndFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread); + } + + interface JvmtiEventMonitorWaitFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread, JNIObjectHandle obj, long timeout); + } + + interface JvmtiEventMonitorWaitedFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread, JNIObjectHandle obj, boolean timedOut); + } + + interface JvmtiEventMonitorContendedEnterFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread, JNIObjectHandle obj); + } + + interface JvmtiEventMonitorContendedEnteredFunctionPointer extends CFunctionPointer { + @InvokeCFunctionPointer + int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread, JNIObjectHandle obj); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java index b5b58ebaad28..72796c0d3f38 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java @@ -25,10 +25,24 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CField; import org.graalvm.nativeimage.c.struct.CStruct; import org.graalvm.word.PointerBase; +import com.oracle.svm.core.jni.headers.JNIMethodId; + @CContext(JvmtiDirectives.class) -@CStruct("jvmtiFrameInfo") -public interface JvmtiFrameInfo extends PointerBase { +@CStruct(value = "jvmtiFrameInfo", addStructKeyword = true) +public interface JvmtiFrameInfo extends PointerBase { + @CField("method") + JNIMethodId getMethod(); + + @CField("method") + void setMethod(JNIMethodId method); + + @CField("location") + long getLocation(); + + @CField("location") + void setLocation(long location); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java new file mode 100644 index 000000000000..d96a2d2827a9 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +//TODO @dprcci REMOVE +@CPointerTo(JvmtiFrameInfo.class) +public interface JvmtiFrameInfoPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java index 6845bab10374..2ab061c8c911 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java @@ -25,10 +25,35 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CField; import org.graalvm.nativeimage.c.struct.CStruct; import org.graalvm.word.PointerBase; @CContext(JvmtiDirectives.class) @CStruct(value = "jvmtiStackInfo", addStructKeyword = true) public interface JvmtiStackInfo extends PointerBase { + @CField("thread") + void setThread(JThread thread); + + @CField("thread") + JThread getThread(); + + @CField("state") + void setState(int state); + + @CField("state") + int getState(); + + @CField("frame_buffer") + void setFrameInfo(JvmtiFrameInfoPointer frameInfo); + + @CField("frame_buffer") + JvmtiFrameInfoPointer getFrameInfo(); + + @CField("frame_count") + void setFrameCount(int frameCount); + + @CField("frame_count") + int getFrameCount(); + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java new file mode 100644 index 000000000000..0775cc655966 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.word.PointerBase; + +@CPointerTo(JvmtiStackInfoPointer.class) +public interface JvmtiStackInfoPointerPointer extends PointerBase { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java index 30dab8951306..70da8d80aac6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadGroupInfo.java @@ -25,10 +25,36 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CField; import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.word.PointerBase; @CContext(JvmtiDirectives.class) @CStruct("jvmtiThreadGroupInfo") public interface JvmtiThreadGroupInfo extends PointerBase { + @CField("parent") + JThreadGroup getParent(); + + @CField("parent") + void setParent(JThreadGroup parent); + + @CField("name") + CCharPointer getName(); + + @CField("name") + void setName(CCharPointer name); + + @CField("max_priority") + int getMaxPriority(); + + @CField("max_priority") + void setMaxPriority(int maxPriority); + + @CField("is_daemon") + boolean getIsDaemon(); + + @CField("is_daemon") + void setIsDaemon(boolean isDaemon); + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java index 1d83f56b05b1..321cbaf5a835 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadInfo.java @@ -25,10 +25,44 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.struct.CField; import org.graalvm.nativeimage.c.struct.CStruct; +import org.graalvm.nativeimage.c.type.CCharPointer; import org.graalvm.word.PointerBase; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; + @CContext(JvmtiDirectives.class) @CStruct("jvmtiThreadInfo") public interface JvmtiThreadInfo extends PointerBase { + @CField("name") + CCharPointer getName(); + + @CField("name") + void setName(CCharPointer name); + + @CField("priority") + int getPriority(); + + @CField("priority") + void setPriority(int priority); + + @CField("is_daemon") + boolean getIsDaemon(); + + @CField("is_daemon") + void setIsDaemon(boolean isDaemon); + + @CField("thread_group") + JThreadGroup getThreadGroup(); + + @CField("thread_group") + void setThreadGroup(JThreadGroup jThreadGroup); + + @CField("context_class_loader") + JNIObjectHandle getContextClassLoader(); + + @CField("context_class_loader") + void setContextClassLoader(JNIObjectHandle contextClassLoader); + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java new file mode 100644 index 000000000000..808f292619ff --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +public enum JvmtiThreadState { + JVMTI_THREAD_STATE_ALIVE(0x0001), + JVMTI_THREAD_STATE_TERMINATED(0x0002), + JVMTI_THREAD_STATE_RUNNABLE(0x0004), + JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER(0x0400), + JVMTI_THREAD_STATE_WAITING(0x0080), + JVMTI_THREAD_STATE_WAITING_INDEFINITELY(0x0010), + JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT(0x0020), + JVMTI_THREAD_STATE_SLEEPING(0x0040), + JVMTI_THREAD_STATE_IN_OBJECT_WAIT(0x0100), + JVMTI_THREAD_STATE_PARKED(0x0200), + JVMTI_THREAD_STATE_SUSPENDED(0x100000), + JVMTI_THREAD_STATE_INTERRUPTED(0x200000), + JVMTI_THREAD_STATE_IN_NATIVE(0x400000); + + private final int internalValue; + + JvmtiThreadState(int internalValue) { + this.internalValue = internalValue; + } + + public int getValue() { + return this.internalValue; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java new file mode 100644 index 000000000000..af40e960e3b0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.headers; + +import org.graalvm.nativeimage.c.struct.CPointerTo; +import org.graalvm.nativeimage.c.type.VoidPointer; +import org.graalvm.word.PointerBase; + +@CPointerTo(VoidPointer.class) +public interface VoidPointerPointer extends PointerBase { +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java new file mode 100644 index 000000000000..b846b0053d6b --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.utils; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.word.ComparableWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.jvmti.JvmtiMemoryManager; +import com.oracle.svm.core.locks.VMMutex; +import com.oracle.svm.core.nmt.NmtCategory; + +public class JvmtiLocalStorageUtil implements JvmtiMemoryManager { + + private final VMMutex mutex; + private NonmovableMap localStorage; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiLocalStorageUtil(String mutexName) { + mutex = new VMMutex(mutexName); + } + + public void initialize(int initialCapacity) { + localStorage = NonmovableMaps.createMap(initialCapacity, NmtCategory.JVMTI); + NonmovableMaps.fillValuesWithDefault(localStorage, WordFactory.nullPointer(), 0, initialCapacity); + } + + public void tearDown() { + NonmovableMaps.releaseMap(localStorage); + } + + public final void put(K key, V value) { + try { + mutex.lock(); + NonmovableMaps.put(localStorage, key, value); + } finally { + mutex.unlock(); + } + } + + public final V get(K externalEnv) { + try { + mutex.lock(); + return NonmovableMaps.get(localStorage, externalEnv); + } finally { + mutex.unlock(); + } + } + + public final boolean contains(K externalEnv) { + try { + mutex.lock(); + return NonmovableMaps.contains(localStorage, externalEnv); + } finally { + mutex.unlock(); + } + } + + @Override + public void releaseAllUnmanagedMemory() { + NonmovableMaps.releaseMap(localStorage); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java new file mode 100644 index 000000000000..08025fd78745 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.utils; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.type.CCharPointer; +import org.graalvm.nativeimage.c.type.CCharPointerPointer; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; +import org.graalvm.word.UnsignedWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.jvmti.headers.JvmtiError; + +public class JvmtiUninterruptibleUtils { + + private JvmtiUninterruptibleUtils() { + } + + @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "jvmti") + public static JvmtiError writeStringToCCharArray(char[] buffer, int endIndex, CCharPointerPointer charPtr, ReplaceDotWithSlash replacer) { + if (endIndex <= 0) { + return JvmtiError.JVMTI_ERROR_INTERNAL; + } + UnsignedWord bufferSize = WordFactory.unsigned(com.oracle.svm.core.jdk.UninterruptibleUtils.String.modifiedUTF8LengthCharArray(buffer, endIndex, true, replacer)); + CCharPointer cStringBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); + if (cStringBuffer.isNull()) { + charPtr.write(WordFactory.nullPointer()); + return JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; + } + + com.oracle.svm.core.jdk.UninterruptibleUtils.String.toModifiedUTF8FromCharArray(buffer, endIndex, (Pointer) cStringBuffer, ((Pointer) cStringBuffer).add(bufferSize), true, replacer); + charPtr.write(cStringBuffer); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static class ReplaceDotWithSlash implements com.oracle.svm.core.jdk.UninterruptibleUtils.CharReplacer { + @Override + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public char replace(char ch) { + if (ch == '.') { + return '/'; + } + return ch; + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java new file mode 100644 index 000000000000..89d43ecfd9db --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.utils; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.ComparableWord; +import org.graalvm.word.Pointer; +import org.graalvm.word.PointerBase; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.config.ConfigurationValues; + +public final class JvmtiUtils { + + private JvmtiUtils() { + } + + @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") + public static T allocateWordBuffer(int nbElements) { + int size = nbElements * ConfigurationValues.getTarget().wordSize; + T allocatedPtr = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(size)); + if (allocatedPtr.isNull()) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(allocatedPtr); + return WordFactory.nullPointer(); + } + return allocatedPtr; + } + + @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") + public static void writeWordAtIdxInBuffer(T array, int index, P element) { + ((Pointer) array).writeWord(index * ConfigurationValues.getTarget().wordSize, element); + } + + @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") + public static T growWordBuffer(T buffer, int newNbElements) { + return ImageSingletons.lookup(UnmanagedMemorySupport.class).realloc(buffer, WordFactory.unsigned(newNbElements * ConfigurationValues.getTarget().wordSize)); + } + + @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") + public static void freeWordBuffer(T buffer) { + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(buffer); + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java new file mode 100644 index 000000000000..a15605fd9e66 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.utils; + +import org.graalvm.nativeimage.c.struct.RawField; +import org.graalvm.nativeimage.c.struct.RawStructure; +import org.graalvm.word.PointerBase; + +import com.oracle.svm.core.c.NonmovableArray; + +@RawStructure +public interface NonmovableMap extends PointerBase { + @RawField + NonmovableArray getKeyArray(); + + @RawField + void setKeyArray(NonmovableArray keyArray); + + @RawField + NonmovableArray getValueArray(); + + @RawField + void setValueArray(NonmovableArray valueArray); + + @RawField + int getNextAvailableIndex(); + + @RawField + void setNextAvailableIndex(int index); + + @RawField + int getCurrentSize(); + + @RawField + void setCurrentSize(int size); +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java new file mode 100644 index 000000000000..70e958f2912f --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti.utils; + +import java.util.NoSuchElementException; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.c.struct.SizeOf; +import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.ComparableWord; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.c.NonmovableArray; +import com.oracle.svm.core.c.NonmovableArrays; +import com.oracle.svm.core.jdk.UninterruptibleUtils; +import com.oracle.svm.core.nmt.NmtCategory; + +import jdk.graal.compiler.word.Word; + +public final class NonmovableMaps { + private static final UninterruptibleUtils.AtomicLong runtimeArraysInExistence = new UninterruptibleUtils.AtomicLong(0); + private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Could not allocate nonmovable array"); + private static final NoSuchElementException NO_SUCH_ELEMENT_EXCEPTION = new NoSuchElementException("element is not in the map"); + + private static final int ARRAY_FULL = -1; + private static final int ARRAY_GROWTH_FACTOR = 2; + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static NonmovableMap createMap(int initialCapacity, NmtCategory nmtCategory) { + assert initialCapacity > 0; + NonmovableMap map = ImageSingletons.lookup(UnmanagedMemorySupport.class).calloc(WordFactory.unsigned(SizeOf.get(NonmovableMap.class))); + if (map.isNull()) { + throw OUT_OF_MEMORY_ERROR; + } + NonmovableArray keyArray = NonmovableArrays.createWordArray(initialCapacity, nmtCategory); + NonmovableArray valueArray = NonmovableArrays.createWordArray(initialCapacity, nmtCategory); + if (keyArray.isNull() || valueArray.isNull()) { + throw OUT_OF_MEMORY_ERROR; + } + map.setKeyArray(keyArray); + map.setValueArray(valueArray); + map.setNextAvailableIndex(0); + map.setCurrentSize(initialCapacity); + runtimeArraysInExistence.incrementAndGet(); + return map; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static void releaseMap(NonmovableMap map) { + NonmovableArrays.releaseUnmanagedArray(map.getKeyArray()); + NonmovableArrays.releaseUnmanagedArray(map.getValueArray()); + ImageSingletons.lookup(UnmanagedMemorySupport.class).free(map); + assert map.isNull() || runtimeArraysInExistence.getAndDecrement() > 0; + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static void fillValuesWithDefault(NonmovableMap map, V defaultValue, int start, int end) { + assert map.isNonNull(); + assert map.getCurrentSize() > end; + for (int i = start; i < end; i++) { + NonmovableArrays.setWord(map.getValueArray(), i, defaultValue); + } + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static void put(NonmovableMap map, K key, V value) { + put(map, key, value, true); + } + + // increase the size if at full capacity + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static void put(NonmovableMap map, K key, V value, boolean growIfFull) { + if (map.getCurrentSize() == ARRAY_FULL) { + if (growIfFull) { + growAndFillMap(map, WordFactory.nullPointer()); + } else { + return; + } + } + NonmovableArray keyArray = map.getKeyArray(); + NonmovableArray valueArray = map.getValueArray(); + assert valueArray.isNonNull() && keyArray.isNonNull(); + + int nextAvailableIndex = map.getNextAvailableIndex(); + NonmovableArrays.setWord(keyArray, nextAvailableIndex, key); + NonmovableArrays.setWord(valueArray, nextAvailableIndex, value); + map.setNextAvailableIndex(nextAvailableIndex + 1); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static boolean contains(NonmovableMap map, K key) { + int filledMapSize = map.getNextAvailableIndex(); + int i = 0; + Word current = WordFactory.zero(); + while (i < filledMapSize && current.notEqual(key)) { + current = (Word) NonmovableArrays.getWord(map.getKeyArray(), i); + i++; + } + return !(i == map.getCurrentSize() && current.notEqual(key)); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static V get(NonmovableMap map, K key) { + int filledMapSize = map.getNextAvailableIndex(); + int i = 0; + Word current = WordFactory.zero(); + while (i < filledMapSize && (current = (Word) NonmovableArrays.getWord(map.getKeyArray(), i)).notEqual(key)) { + i++; + } + if (i == map.getCurrentSize() && current.notEqual(key)) { + throw NO_SUCH_ELEMENT_EXCEPTION; + } + return NonmovableArrays.getWord(map.getValueArray(), i); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + private static void growAndFillMap(NonmovableMap map, V defaultValue) { + int oldSize = map.getCurrentSize(); + growMap(map, NmtCategory.JVMTI); + fillValuesWithDefault(map, defaultValue, oldSize, map.getCurrentSize()); + } + + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + private static void growMap(NonmovableMap map, NmtCategory nmtCategory) { + int oldSize = map.getCurrentSize(); + int newMapSize = oldSize * ARRAY_GROWTH_FACTOR; + + NonmovableArray keyArray = map.getKeyArray(); + NonmovableArray valueArray = map.getValueArray(); + + assert valueArray.isNonNull() && keyArray.isNonNull(); + + NonmovableArray newKeyArray = NonmovableArrays.createWordArray(newMapSize, nmtCategory); + NonmovableArrays.arraycopy(keyArray, 0, newKeyArray, 0, oldSize); + NonmovableArrays.releaseUnmanagedArray(keyArray); + + NonmovableArray newValueArray = NonmovableArrays.createWordArray(newMapSize, nmtCategory); + NonmovableArrays.arraycopy(valueArray, 0, newValueArray, 0, oldSize); + NonmovableArrays.releaseUnmanagedArray(valueArray); + + map.setKeyArray(keyArray); + map.setValueArray(newValueArray); + map.setNextAvailableIndex(oldSize); + map.setCurrentSize(newMapSize); + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java index 8461d24bc788..dcac6d7dee63 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java @@ -32,6 +32,7 @@ import java.util.concurrent.locks.ReentrantLock; +import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.IsolateThread; import com.oracle.svm.core.Uninterruptible; @@ -70,7 +71,7 @@ public JavaMonitor() { public void monitorEnter(Object obj) { if (!tryLock()) { long startTicks = JfrTicks.elapsedTicks(); - acquire(1); + acquire(1, obj); JavaMonitorEnterEvent.emit(obj, latestJfrTid, startTicks); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java index 2e034ef9b3ba..b77e3bdb57a7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java @@ -34,6 +34,7 @@ import com.oracle.svm.core.jfr.JfrTicks; import com.oracle.svm.core.jfr.SubstrateJVM; import com.oracle.svm.core.jfr.events.JavaMonitorWaitEvent; +import com.oracle.svm.core.jvmti.JvmtiPostEvents; import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.util.BasedOnJDKClass; @@ -432,9 +433,11 @@ private int cancelAcquire(Node node) { protected abstract boolean isHeldExclusively(); // see AbstractQueuedLongSynchronizer.acquire(long) - protected final void acquire(long arg) { + protected final void acquire(long arg, Object obj) { if (!tryAcquire(arg)) { + JvmtiPostEvents.postMonitorContendedEnter(Thread.currentThread(), obj); acquire(null, arg); + JvmtiPostEvents.postMonitorContendedEntered(Thread.currentThread(), obj); } } @@ -644,6 +647,7 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc } node.clearStatus(); // waiting is done, emit wait event + JvmtiPostEvents.postMonitorWaited(Thread.currentThread(), obj, cancelled); JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfrTid, time, cancelled); acquire(node, savedAcquisitions); if (cancelled) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java new file mode 100644 index 000000000000..ae9c722fd4e0 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.monitor; + +import com.oracle.svm.core.jvmti.headers.JvmtiError; + +public class JvmtiRawMonitorHelper { + + public static JvmtiError getOrCreateRawMonitor(Object obj) { + MonitorSupport monitorSupport = MonitorSupport.singleton(); + if (!(monitorSupport instanceof MultiThreadedMonitorSupport multiThreadedMonitorSupport)) { + return JvmtiError.JVMTI_ERROR_INTERNAL; + } + multiThreadedMonitorSupport.getOrCreateMonitor(obj, MonitorInflationCause.JVMTI_CREATE); + return JvmtiError.JVMTI_ERROR_NONE; + } + + public static JvmtiError exitCompletely(Object obj) { + MonitorSupport monitorSupport = MonitorSupport.singleton(); + if (!(monitorSupport instanceof MultiThreadedMonitorSupport multiThreadedMonitorSupport)) { + return JvmtiError.JVMTI_ERROR_INTERNAL; + } + JavaMonitor monitor = multiThreadedMonitorSupport.getMonitor(obj); + boolean done; + try { + done = monitor.tryRelease(monitor.getAcquisitions()); + } catch (IllegalMonitorStateException e) { + return JvmtiError.JVMTI_ERROR_INTERNAL; + } + return done ? JvmtiError.JVMTI_ERROR_NONE : JvmtiError.JVMTI_ERROR_INTERRUPT; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java index a4ee24912a6d..463007e87a9f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java @@ -35,7 +35,15 @@ public enum MonitorInflationCause { WAIT("Monitor Wait"), NOTIFY("Monitor Notify"), JNI_ENTER("JNI Monitor Enter"), - JNI_EXIT("JNI Monitor Exit"); + JNI_EXIT("JNI Monitor Exit"), + ///TODO @dprcci add?? + JVMTI_CREATE("JVMTI CreateRawMonitor"), + JVMTI_DESTROY("JVMTI DestroyRawMonitor"), + JVMTI_ENTER("JVMTI RawMonitorEnter"), + JVMTI_EXIT("JVMTI RawMonitorExit"), + JVMTI_WAIT("JVMTI RawMonitorWait"), + JVMTI_NOTIFY("JVMTI RawMonitorNotify"), + JVMTI_NOTIFYALL("JVMTI RawMonitorNotifyAll"); private final String text; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nmt/NmtCategory.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nmt/NmtCategory.java index ff71cdfabaed..9fb47fcd21eb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nmt/NmtCategory.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nmt/NmtCategory.java @@ -43,6 +43,8 @@ public enum NmtCategory { JNI("JNI"), /** JVM stat / perf data. */ JvmStat("jvmstat"), + /** Java Virtual Machine Tool Interface. */ + JVMTI("JVMTI"), /** NMT itself. */ NMT("Native Memory Tracking"), /** Profile-guided optimizations. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java index be44935f7757..9a9117656a00 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java @@ -72,6 +72,9 @@ public final class Target_java_lang_reflect_Method { @RecomputeFieldValue(kind = Kind.Reset) // Target_jdk_internal_reflect_MethodAccessor methodAccessorFromMetadata; + @Alias + public transient String signature; + @Alias @TargetElement(name = CONSTRUCTOR_NAME) @SuppressWarnings("hiding") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java index 60da2ca7d22e..b9c9b13600d4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java @@ -167,7 +167,7 @@ private ThreadGroupThreadsAccessor() { } } -public class JavaLangThreadGroupSubstitutions { +public class JavaLangThreadGroupSubstitutions { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static ThreadGroup getParentThreadGroupUnsafe(ThreadGroup threadGroup) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java index 2b19371ee09e..9743cf8dad60 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java @@ -475,4 +475,10 @@ public static Thread getCurrentThreadOrNull() { Target_java_lang_Thread tjlt = SubstrateUtil.cast(thread, Target_java_lang_Thread.class); return (tjlt.vthread != null) ? tjlt.vthread : thread; } + + //TODO @dprcci might be illegal (check for inline value) + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) + public static boolean isAlive(Thread thread){ + return PlatformThreads.isAlive(thread); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index e8930ec79a07..490aab8cd6d4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -47,6 +47,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ImageSingletons; @@ -672,6 +673,7 @@ private static boolean isApplicationThread(IsolateThread isolateThread) { @SuppressFBWarnings(value = "NN", justification = "notifyAll is necessary for Java semantics, no shared state needs to be modified beforehand") public static void exit(Thread thread) { + JvmtiPostEvents.postThreadEnd(thread); ThreadListenerSupport.get().afterThreadRun(); /* @@ -785,6 +787,7 @@ protected static void freeStartData(ThreadStartData startData) { } void startThread(Thread thread, long stackSize) { + JvmtiPostEvents.postThreadStart(thread); boolean started = doStartThread(thread, stackSize); if (!started) { throw new OutOfMemoryError("Unable to create native thread: possibly out of memory or process/resource limits reached"); @@ -896,7 +899,9 @@ static StackTraceElement[] getStackTraceAtSafepoint(Thread thread, Pointer calle return StackTraceUtils.getStackTraceAtSafepoint(isolateThread); } - static Pointer getCarrierSPOrElse(Thread carrier, Pointer other) { + + //TODO @dprcci JVMTI + public static Pointer getCarrierSPOrElse(Thread carrier, Pointer other) { Target_jdk_internal_vm_Continuation cont = toTarget(carrier).cont; while (cont != null) { if (cont.getScope() == Target_java_lang_VirtualThread.VTHREAD_SCOPE) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java index a002f68a1f99..ce7239960adb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java @@ -24,10 +24,17 @@ */ package com.oracle.svm.hosted.ameta; +import java.util.List; + +import org.graalvm.nativeimage.hosted.Feature; + import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; +import com.oracle.svm.core.jvmti.JvmtiClassInfoUtil; +import com.oracle.svm.core.jvmti.JvmtiGenericInfoMapFeature; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.SVMHost; @@ -45,10 +52,21 @@ public void duringSetup(DuringSetupAccess a) { access.registerObjectReplacer(this::replace); } + @Override + public List> getRequiredFeatures() { + return List.of(JvmtiGenericInfoMapFeature.class); + } + private Object replace(Object source) { if (source instanceof Class) { Class clazz = (Class) source; DynamicHub dynamicHub = hostVM.dynamicHub(metaAccess.lookupJavaType(clazz)); + if (SubstrateOptions.JVMTI.getValue()) { + String signature = dynamicHub.getSignature(); + if (signature != null && clazz.getTypeParameters().length > 0) { + JvmtiClassInfoUtil.JVMTIGenericInfoMap.singleton().addSignature(clazz, signature); + } + } return dynamicHub; } return source; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java index 671ff6db37e3..ae9369922d8b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java @@ -24,6 +24,17 @@ */ package com.oracle.svm.hosted.jvmti; +import com.oracle.svm.core.jvmti.JvmtiClassInfoUtil; +import com.oracle.svm.core.jvmti.JvmtiEnvManager; +import com.oracle.svm.core.jvmti.JvmtiEnvStorage; +import com.oracle.svm.core.jvmti.JvmtiManager; +import com.oracle.svm.core.jvmti.JvmtiMultiStackTracesUtil; +import com.oracle.svm.core.jvmti.JvmtiRawMonitorUtil; +import com.oracle.svm.core.jvmti.JvmtiThreadGroupUtil; +import com.oracle.svm.core.jvmti.JvmtiThreadLocalStorage; +import com.oracle.svm.core.jvmti.JvmtiThreadStateUtil; +import com.oracle.svm.core.jvmti.JvmtiGetThreadsUtil; +import com.oracle.svm.core.jvmti.JvmtiStackTraceUtil; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CEntryPoint; @@ -74,10 +85,7 @@ public void duringSetup(DuringSetupAccess access) { public void beforeAnalysis(BeforeAnalysisAccess arg) { BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) arg; AnalysisMetaAccess metaAccess = access.getMetaAccess(); - - ImageSingletons.add(JvmtiAgents.class, new JvmtiAgents()); - - ImageSingletons.add(JvmtiFunctionTable.class, new JvmtiFunctionTable()); + JvmtiManager.registerAllJvmtiClasses(); registerCEntryPoints(metaAccess); } From f5101cb0e5c9e2f363e1c4d251f9a141e05aae1e Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Wed, 28 Feb 2024 18:13:41 +0100 Subject: [PATCH 3/3] Cleanups and fixes. Removed all JVMTI code that uses JNI object handles. --- .../oracle/svm/core/genscavenge/GCImpl.java | 3 - .../svm/core/genscavenge/ImageHeapWalker.java | 2 +- .../com/oracle/svm/core/SubstrateOptions.java | 6 +- .../graal/snippets/CEntryPointSnippets.java | 19 - .../oracle/svm/core/headers/LibCSupport.java | 2 +- .../com/oracle/svm/core/hub/DynamicHub.java | 1 - .../svm/core/jdk/UninterruptibleUtils.java | 38 - .../core/jni/access/JNIAccessibleField.java | 2 +- .../core/jni/access/JNIAccessibleMethod.java | 6 +- .../jni/access/JNIReflectionDictionary.java | 73 -- .../jni/functions/JNIInvocationInterface.java | 8 +- .../core/jni/headers/JNIFieldIdPointer.java | 2 + .../jni/headers/JNIFieldIdPointerPointer.java | 2 + .../core/jni/headers/JNIMethodIdPointer.java | 2 + .../headers/JNIMethodIdPointerPointer.java | 2 + .../headers/JNINativeInterfacePointer.java | 2 + .../oracle/svm/core/jvmti/JvmtiAgents.java | 16 +- .../svm/core/jvmti/JvmtiCapabilitiesEnum.java | 77 -- .../svm/core/jvmti/JvmtiCapabilitiesUtil.java | 300 +------- .../svm/core/jvmti/JvmtiClassInfoUtil.java | 674 ------------------ .../com/oracle/svm/core/jvmti/JvmtiEnv.java | 21 +- .../svm/core/jvmti/JvmtiEnvEventEnabled.java | 50 -- .../core/jvmti/JvmtiEnvEventEnabledUtils.java | 93 --- .../svm/core/jvmti/JvmtiEnvManager.java | 178 ----- .../oracle/svm/core/jvmti/JvmtiEnvShared.java | 38 - .../svm/core/jvmti/JvmtiEnvSharedUtil.java | 234 ------ .../svm/core/jvmti/JvmtiEnvStorage.java | 77 -- .../oracle/svm/core/jvmti/JvmtiEnvUtil.java | 195 ++--- .../com/oracle/svm/core/jvmti/JvmtiEnvs.java | 159 +++++ .../core/jvmti/JvmtiEventCallbacksUtil.java | 29 +- .../oracle/svm/core/jvmti/JvmtiEvents.java | 92 +++ .../svm/core/jvmti/JvmtiFunctionTable.java | 14 +- .../oracle/svm/core/jvmti/JvmtiFunctions.java | 402 +++++------ .../jvmti/JvmtiGenericInfoMapFeature.java | 45 -- .../svm/core/jvmti/JvmtiGetThreadsUtil.java | 169 ----- .../oracle/svm/core/jvmti/JvmtiManager.java | 52 -- .../svm/core/jvmti/JvmtiMemoryManager.java | 30 - .../core/jvmti/JvmtiMultiStackTracesUtil.java | 347 --------- .../svm/core/jvmti/JvmtiObjectInfoUttil.java | 99 --- .../svm/core/jvmti/JvmtiPostEvents.java | 225 ------ .../svm/core/jvmti/JvmtiRawMonitorUtil.java | 265 ------- .../svm/core/jvmti/JvmtiStackTraceUtil.java | 368 ---------- .../oracle/svm/core/jvmti/JvmtiSupport.java | 73 ++ .../core/jvmti/JvmtiThreadActionsUtil.java | 109 --- .../svm/core/jvmti/JvmtiThreadGroupUtil.java | 291 -------- .../core/jvmti/JvmtiThreadLocalStorage.java | 109 --- .../svm/core/jvmti/JvmtiThreadStateUtil.java | 201 ------ .../core/jvmti/headers/BooleanPointer.java | 6 +- .../jvmti/headers/JRawMonitorIdPointer.java | 2 + .../core/jvmti/headers/JvmtiDirectives.java | 5 +- .../svm/core/jvmti/headers/JvmtiError.java | 70 +- .../svm/core/jvmti/headers/JvmtiEvent.java | 96 +-- .../jvmti/headers/JvmtiEventCallbacks.java | 24 +- .../core/jvmti/headers/JvmtiEventMode.java | 4 + .../JvmtiExtensionFunctionInfoPointer.java | 2 + .../core/jvmti/headers/JvmtiFrameInfo.java | 2 +- .../jvmti/headers/JvmtiFrameInfoPointer.java | 33 - .../jvmti/headers/JvmtiHeapObjectFilter.java | 4 + .../core/jvmti/headers/JvmtiHeapRootKind.java | 4 + .../jvmti/headers/JvmtiIterationControl.java | 4 + .../headers/JvmtiLineNumberEntryPointer.java | 2 + .../JvmtiLocalVariableEntryPointer.java | 2 + .../JvmtiMonitorStackDepthInfoPointer.java | 2 + .../headers/JvmtiObjectReferenceKind.java | 4 + .../svm/core/jvmti/headers/JvmtiPhase.java | 28 +- .../core/jvmti/headers/JvmtiStackInfo.java | 4 +- .../jvmti/headers/JvmtiStackInfoPointer.java | 2 + .../headers/JvmtiStackInfoPointerPointer.java | 32 - .../core/jvmti/headers/JvmtiThreadState.java | 45 +- .../core/jvmti/headers/JvmtiVerboseFlag.java | 4 + .../jvmti/headers/VoidPointerPointer.java | 2 +- .../jvmti/utils/JvmtiLocalStorageUtil.java | 86 --- .../utils/JvmtiUninterruptibleUtils.java | 71 -- .../svm/core/jvmti/utils/JvmtiUtils.java | 68 -- .../svm/core/jvmti/utils/NonmovableMap.java | 58 -- .../svm/core/jvmti/utils/NonmovableMaps.java | 170 ----- .../oracle/svm/core/monitor/JavaMonitor.java | 3 +- .../JavaMonitorQueuedSynchronizer.java | 6 +- .../core/monitor/JvmtiRawMonitorHelper.java | 54 -- .../core/monitor/MonitorInflationCause.java | 10 +- .../Target_java_lang_reflect_Method.java | 3 - .../JavaLangThreadGroupSubstitutions.java | 2 +- .../oracle/svm/core/thread/JavaThreads.java | 6 - .../svm/core/thread/PlatformThreads.java | 7 +- .../hosted/ameta/HostedDynamicHubFeature.java | 18 - .../UninterruptibleAnnotationChecker.java | 3 +- .../oracle/svm/hosted/jvmti/JvmtiFeature.java | 30 +- 87 files changed, 790 insertions(+), 5390 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvs.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEvents.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiSupport.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index 1567c4ac6011..df8ca685efbb 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -31,7 +31,6 @@ import java.lang.ref.Reference; -import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.Platform; @@ -178,8 +177,6 @@ public void collectionHint(boolean fullGC) { private void collect(GCCause cause, boolean forceFullGC) { if (!hasNeverCollectPolicy()) { - JvmtiPostEvents.postGarbageCollectionStart(); - JvmtiPostEvents.postGarbageCollectionFinish(); boolean outOfMemory = collectWithoutAllocating(cause, forceFullGC); if (outOfMemory) { throw OutOfMemoryUtil.heapSizeExceeded(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java index bac30ab1adf6..da58392793c8 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/ImageHeapWalker.java @@ -127,7 +127,7 @@ private static boolean walkPartitionInline(Object firstObject, Object lastObject @Uninterruptible(reason = "Bridge between uninterruptible and potentially interruptible code.", mayBeInlined = true, calleeMustBe = false) private static boolean visitObject(ObjectVisitor visitor, Object currentObject) { - return visitor. visitObject(currentObject); + return visitor.visitObject(currentObject); } @AlwaysInline("de-virtualize calls to ObjectReferenceVisitor") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 410d133efda6..1d8ceb6a7c65 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -634,15 +634,13 @@ public static void updateMaxJavaStackTraceDepth(EconomicMap, Object @Option(help = "Enable JVM Tool Interface (JVMTI) support.", type = OptionType.User)// public static final HostedOptionKey JVMTI = new HostedOptionKey<>(false); - // TEMP (chaeubl): we need to support multiple values @Option(help = "Loads the specified native agent library. " + "After the library name, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// - public static final RuntimeOptionKey AgentLib = new RuntimeOptionKey<>(null); + public static final RuntimeOptionKey JVMTIAgentLib = new RuntimeOptionKey<>(null); - // TEMP (chaeubl): we need to support multiple values @Option(help = "Loads the specified native agent library specified by the absolute path name. " + "After the library path, a comma-separated list of options specific to the library can be used.", type = OptionType.User)// - public static final RuntimeOptionKey AgentPath = new RuntimeOptionKey<>(null); + public static final RuntimeOptionKey JVMTIAgentPath = new RuntimeOptionKey<>(null); @Option(help = "Alignment of AOT and JIT compiled code in bytes.")// public static final HostedOptionKey CodeAlignment = new HostedOptionKey<>(16); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java index 1d91fc5c4adf..7a8e3873251c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/CEntryPointSnippets.java @@ -32,9 +32,6 @@ import java.util.Map; -import com.oracle.svm.core.jvmti.JvmtiEnvManager; -import com.oracle.svm.core.jvmti.JvmtiManager; -import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; @@ -80,7 +77,6 @@ import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport; import com.oracle.svm.core.jdk.RuntimeSupport; -import com.oracle.svm.core.jvmti.JvmtiAgents; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.option.RuntimeOptionParser; import com.oracle.svm.core.os.CommittedMemoryProvider; @@ -400,13 +396,6 @@ private static int initializeIsolateInterruptibly1(CEntryPointCreateIsolateParam /* Adjust stack overflow boundary of main thread. */ StackOverflowCheck.singleton().updateStackOverflowBoundary(); - if (SubstrateOptions.JVMTI.getValue()) { - JvmtiAgents.singleton().load(); - - //JvmtiPostEvents.postVMInit(); - JvmtiPostEvents.postVMStart(); - } - assert !isolateInitialized; isolateInitialized = true; @@ -637,14 +626,6 @@ private static boolean initiateTearDownIsolateInterruptibly() { } VMThreads.singleton().threadExit(); - - if (SubstrateOptions.JVMTI.getValue()) { - JvmtiPostEvents.postVMDeath(); - JvmtiManager.freeAllJvmtiClassesUnmanagedMemory(); - JvmtiAgents.singleton().unload(); - } - - return true; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java index 73026953fa9c..b7ed0b46fdae 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/headers/LibCSupport.java @@ -34,7 +34,7 @@ import com.oracle.svm.core.memory.NativeMemory; /** Platform-independent LibC support. Don't use this class directly, use {@link LibC} instead. */ -public interface LibCSupport { +public interface LibCSupport { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) int errno(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index 3ca8589e8a5e..a2c6fc6fb67e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -1843,7 +1843,6 @@ private ClassRepository getGenericInfo() { return companion.getGenericInfo(this); } - ClassRepository computeGenericInfo() { String genericSignature = getGenericSignature0(); if (genericSignature == null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleUtils.java index 17be66932302..f7c432322b09 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/UninterruptibleUtils.java @@ -605,21 +605,6 @@ public static int modifiedUTF8Length(java.lang.String string, boolean addNullTer return result + (addNullTerminator ? 1 : 0); } - //TODO @dprcci FINISH THAT TłOMORROW - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static int modifiedUTF8LengthCharArray(char[] buffer, int bufferLength, boolean addNullTerminator, CharReplacer replacer) { - int result = 0; - for (int index = 0; index < bufferLength; index++) { - char ch = buffer[index]; - if (replacer != null) { - ch = replacer.replace(ch); - } - result += modifiedUTF8Length(ch); - } - - return result + (addNullTerminator ? 1 : 0); - } - /** * Writes the encoded {@code string} into the given {@code buffer} using the modified UTF8 * encoding (null characters that are present in the input will be encoded in a way that @@ -656,29 +641,6 @@ public static Pointer toModifiedUTF8(java.lang.String string, int stringLength, return pos; } - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static Pointer toModifiedUTF8FromCharArray(char[] charArray, int endIndex, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator) { - return toModifiedUTF8FromCharArray(charArray, endIndex, buffer, bufferEnd, addNullTerminator, null); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static Pointer toModifiedUTF8FromCharArray(char[] charArray, int endIndex, Pointer buffer, Pointer bufferEnd, boolean addNullTerminator, CharReplacer replacer) { - Pointer pos = buffer; - for (int i = 0; i < endIndex; i++) { - char ch = charArray[i]; - if (replacer != null) { - ch = replacer.replace(ch); - } - pos = writeModifiedUTF8(pos, ch); - } - if (addNullTerminator) { - pos.writeByte(0, (byte) 0); - pos = pos.add(1); - } - VMError.guarantee(pos.belowOrEqual(bufferEnd), "Must not write out of bounds."); - return pos; - } - /** * Returns a character from a string at {@code index} position based on the encoding format. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java index ee5e2fda25b8..d158f3d104de 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleField.java @@ -44,7 +44,7 @@ /** * Information on a field that can be looked up and accessed via JNI. */ -public final class JNIAccessibleField extends JNIAccessibleMember { +public final class JNIAccessibleField extends JNIAccessibleMember { /* 10000000...0 */ private static final UnsignedWord ID_STATIC_FLAG = WordFactory.unsigned(-1L).unsignedShiftRight(1).add(1); /* 01000000...0 */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java index f2864f9ff3da..40515c3abac7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIAccessibleMethod.java @@ -157,11 +157,13 @@ boolean isPublic() { return Modifier.isPublic(modifiers); } - boolean isNative() { + public boolean isNative() { return Modifier.isNative(modifiers); } - boolean isStatic() {return Modifier.isStatic(modifiers);} + boolean isStatic() { + return Modifier.isStatic(modifiers); + } @Platforms(HOSTED_ONLY.class) public void finishBeforeCompilation(EconomicSet> hidingSubclasses, int vtableOffsetEntry, int interfaceTypeIDEntry, CodePointer nonvirtualEntry, PointerBase newObjectEntry, diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java index c0cb468e6be1..fcf53ecaddb6 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/access/JNIReflectionDictionary.java @@ -28,11 +28,7 @@ import static com.oracle.svm.core.SubstrateOptions.JNIVerboseLookupErrors; import java.io.PrintStream; -import java.util.ArrayList; -import java.util.HashSet; import java.util.Map; -import java.util.Random; -import java.util.Set; import java.util.function.Function; import org.graalvm.collections.EconomicMap; @@ -255,75 +251,6 @@ private JNIAccessibleMethod getDeclaredMethod(Class classObject, JNIAccessibl return method; } - public void printall(){ - classesByClassObject.getKeys().forEach(System.out::println); - } - // TODO @dprcci REMOVE! - public JNIMethodId getRandomMethodID() { - Iterable accessibleClass = classesByClassObject.getValues(); - ArrayList classList = new ArrayList<>(); - accessibleClass.forEach(classList::add); - -// Get random class - Random random = new Random(); - JNIAccessibleClass randomClass = null; - if (!classList.isEmpty()) { - int randomIndex = random.nextInt(classList.size()); - randomClass = classList.get(randomIndex); - } - if (randomClass == null) { - return WordFactory.nullPointer(); - } - MapCursor cursor = randomClass.getMethods(); - if (cursor.advance()) { - return toMethodID(cursor.getValue()); - } else { - return WordFactory.nullPointer(); - } - } - - // TODO @dprcci JVMTI is this correct or should reflection be used? It is assumed the internals - // should not be exposed to the user - public JNIMethodId toMethodID(Class clazz, String methodName) { - //Log.log().string(clazz.getName()); - JNIAccessibleClass accessibleClass = classesByClassObject.get(clazz); - if (accessibleClass == null) { - return WordFactory.nullPointer(); - } - boolean found = false; - MapCursor cursor = accessibleClass.getMethods(); - while (!found && cursor.advance()) { - found = cursor.getKey().getName().equals(methodName); - } - return toMethodID(found ? cursor.getValue() : null); - } - - // TODO @dprcci - @Platforms(HOSTED_ONLY.class) - public Set> getRegisteredClasses() { - Set> res = new HashSet<>(); - classesByClassObject.getKeys().forEach(res::add); - return res; - } - - // TODO @dprcci - public static boolean isMethodNative(JNIMethodId methodId) { - return getMethodByID(methodId).isNative(); - } - - public boolean isValidMethodIdSlow(JNIMethodId methodId){ - Iterable classIterator = classesByClassObject.getValues(); - for (JNIAccessibleClass c : classIterator){ - MapCursor cursor = c.getMethods(); - while(cursor.advance()){ - if(toMethodID(cursor.getValue()).equal(methodId)){ - return true; - } - } - } - return false; - } - public JNIMethodId getMethodID(Class classObject, CharSequence name, CharSequence signature, boolean isStatic) { JNIAccessibleMethod method = findMethod(classObject, new JNIAccessibleMethodDescriptor(name, signature), "getMethodID"); method = checkMethod(method, classObject, name, signature); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java index f400118ac59f..7e815e10a81c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/functions/JNIInvocationInterface.java @@ -39,6 +39,7 @@ import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.UnmanagedMemoryUtil; import com.oracle.svm.core.c.CGlobalData; @@ -68,7 +69,8 @@ import com.oracle.svm.core.jni.headers.JNIJavaVMOption; import com.oracle.svm.core.jni.headers.JNIJavaVMPointer; import com.oracle.svm.core.jni.headers.JNIVersion; -import com.oracle.svm.core.jvmti.JvmtiEnvManager; +import com.oracle.svm.core.jvmti.JvmtiEnvs; +import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; import com.oracle.svm.core.jvmti.headers.JvmtiVersion; import com.oracle.svm.core.log.FunctionPointerLogHandler; import com.oracle.svm.core.memory.UntrackedNullableNativeMemory; @@ -294,8 +296,8 @@ static int DestroyJavaVM(JNIJavaVM vm) { @SuppressWarnings("unused") static int GetEnv(JNIJavaVM vm, WordPointer env, int version) { if (SubstrateOptions.JVMTI.getValue() && JvmtiVersion.isSupported(version)) { - JvmtiEnvManager envManager = JvmtiEnvManager.singleton(); - envManager.createJvmtiEnv(env); + JvmtiExternalEnv jvmtiEnv = JvmtiEnvs.singleton().create(); + env.write(jvmtiEnv); return JNIErrors.JNI_OK(); } else if (JNIVersion.isSupported(version, false)) { env.write(JNIThreadLocalEnvironment.getAddress()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java index 4ed4746e9c83..7d32b102012e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jni.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JNIHeaderDirectives.class) @CPointerTo(JNIFieldId.class) public interface JNIFieldIdPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java index 1a7207ae89da..3c6d61b52b5b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIFieldIdPointerPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jni.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JNIHeaderDirectives.class) @CPointerTo(JNIFieldIdPointer.class) public interface JNIFieldIdPointerPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java index 075753c6f1a1..607c55832329 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jni.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JNIHeaderDirectives.class) @CPointerTo(JNIMethodId.class) public interface JNIMethodIdPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java index cff446f527bb..4464cec4039d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNIMethodIdPointerPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jni.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JNIHeaderDirectives.class) @CPointerTo(JNIMethodIdPointer.class) public interface JNIMethodIdPointerPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java index 7835ca8b4230..580c2c0df72a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jni/headers/JNINativeInterfacePointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jni.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JNIHeaderDirectives.class) @CPointerTo(JNINativeInterface.class) public interface JNINativeInterfacePointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java index 670aaf3e0db0..d0ff735f5334 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiAgents.java @@ -29,7 +29,6 @@ import java.io.Serial; import java.util.ArrayList; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -50,6 +49,9 @@ import com.oracle.svm.core.log.Log; import com.oracle.svm.util.StringUtil; +import jdk.graal.compiler.api.replacements.Fold; + +/** Loads/Unloads JVMTI agents that are located in shared object files. */ public class JvmtiAgents { private static final String AGENT_ON_LOAD = "Agent_OnLoad"; private static final String AGENT_ON_UNLOAD = "Agent_OnUnload"; @@ -65,15 +67,13 @@ public static JvmtiAgents singleton() { return ImageSingletons.lookup(JvmtiAgents.class); } - // TEMP (chaeubl): we could call `Agent_OnAttach` instead - would be closer in terms of the - // semantics. public void load() { - String agentLib = SubstrateOptions.AgentLib.getValue(); + String agentLib = SubstrateOptions.JVMTIAgentLib.getValue(); if (agentLib != null) { loadAgent(agentLib, true); } - String agentPath = SubstrateOptions.AgentPath.getValue(); + String agentPath = SubstrateOptions.JVMTIAgentPath.getValue(); if (agentPath != null) { loadAgent(agentPath, false); } @@ -90,6 +90,10 @@ public void unload() { } private void loadAgent(String agentAndOptions, boolean relative) { + if (!agents.isEmpty()) { + throw new AgentInitException("Only a single agent is supported at the moment."); + } + try { loadAgent0(agentAndOptions, relative); } catch (AgentInitException e) { @@ -129,8 +133,6 @@ private static String getAgentFile(String agent, boolean relative) { String libname = System.mapLibraryName(agent); file = new File(sysPath, libname); if (!file.exists()) { - // TEMP (chaeubl): is this really accurate? What if someone uses a custom - // LD_LIBRARY_PATH? throw new AgentInitException("Could not find agent library '" + agent + "' on the library path."); } } else { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java deleted file mode 100644 index 4fd4fa287afa..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesEnum.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -public enum JvmtiCapabilitiesEnum { - CAN_TAG_OBJECTS, - CAN_GENERATE_FIELD_MODIFICATION_EVENTS, - CAN_GENERATE_FIELD_ACCESS_EVENTS, - CAN_GET_BYTECODES, - CAN_GET_SYNTHETIC_ATTRIBUTE, - CAN_GET_OWNED_MONITOR_INFO, - CAN_GET_CURRENT_CONTENDED_MONITOR, - CAN_GET_MONITOR_INFO, - CAN_POP_FRAME, - CAN_REDEFINE_CLASSES, - CAN_SIGNAL_THREAD, - CAN_GET_SOURCE_FILE_NAME, - CAN_GET_LINE_NUMBERS, - CAN_GET_SOURCE_DEBUG_EXTENSION, - CAN_ACCESS_LOCAL_VARIABLES, - CAN_MAINTAIN_ORIGINAL_METHOD_ORDER, - CAN_GENERATE_SINGLE_STEP_EVENTS, - CAN_GENERATE_EXCEPTION_EVENTS, - CAN_GENERATE_FRAME_POP_EVENTS, - CAN_GENERATE_BREAKPOINT_EVENTS, - CAN_SUSPEND, - CAN_REDEFINE_ANY_CLASS, - CAN_GET_CURRENT_THREAD_CPU_TIME, - CAN_GET_THREAD_CPU_TIME, - CAN_GENERATE_METHOD_ENTRY_EVENTS, - CAN_GENERATE_METHOD_EXIT_EVENTS, - CAN_GENERATE_ALL_CLASS_HOOK_EVENTS, - CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS, - CAN_GENERATE_MONITOR_EVENTS, - CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS, - CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS, - CAN_GENERATE_GARBAGE_COLLECTION_EVENTS, - CAN_GENERATE_OBJECT_FREE_EVENTS, - CAN_FORCE_EARLY_RETURN, - CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO, - CAN_GET_CONSTANT_POOL, - CAN_SET_NATIVE_METHOD_PREFIX, - CAN_RETRANSFORM_CLASSES, - CAN_RETRANSFORM_ANY_CLASS, - CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS, - CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS, - CAN_GENERATE_EARLY_VMSTART, - CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS, - CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS, - CAN_SUPPORT_VIRTUAL_THREADS; - - public static long getBit(JvmtiCapabilitiesEnum capability) { - return 1L << capability.ordinal(); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java index f67226a3afb2..ba148168cac2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiCapabilitiesUtil.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.core.jvmti; -import static com.oracle.svm.core.jvmti.JvmtiEnvSharedUtil.SHARED_CAPABILITIES_TYPE; - import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.SizeOf; @@ -33,12 +31,9 @@ import com.oracle.svm.core.UnmanagedMemoryUtil; import com.oracle.svm.core.jvmti.headers.JvmtiCapabilities; -import com.oracle.svm.core.jvmti.headers.JvmtiError; +/** Methods related to {@link JvmtiCapabilities}. */ public final class JvmtiCapabilitiesUtil { - - private static final JvmtiCapabilitiesEnum[] allCapabilitiesEnumValues = JvmtiCapabilitiesEnum.values(); - @Platforms(Platform.HOSTED_ONLY.class) private JvmtiCapabilitiesUtil() { } @@ -46,22 +41,13 @@ private JvmtiCapabilitiesUtil() { public static boolean hasAny(JvmtiCapabilities capabilities) { assert capabilities.isNonNull(); - for (JvmtiCapabilitiesEnum cap : allCapabilitiesEnumValues) { - if (getCapability(cap, capabilities)) { + Pointer rawData = (Pointer) capabilities; + for (int i = 0; i < SizeOf.get(JvmtiCapabilities.class); i++) { + if (rawData.readByte(i) != 0) { return true; } } return false; - // TODO @dprcci keep old implementation? - /* - * Pointer rawData = (Pointer) capabilities; for (int i = 0; i < - * SizeOf.get(JvmtiCapabilities.class); i++) { if (rawData.readByte(i) != 0) { return true; - * } } return false; - */ - } - - static boolean hasCapability(JvmtiCapabilities capabilities, JvmtiCapabilitiesEnum desired){ - return getCapability(desired, capabilities); } public static void clear(JvmtiCapabilities capabilities) { @@ -72,282 +58,4 @@ public static void clear(JvmtiCapabilities capabilities) { public static void copy(JvmtiCapabilities src, JvmtiCapabilities dst) { UnmanagedMemoryUtil.copyForward((Pointer) src, (Pointer) dst, SizeOf.unsigned(JvmtiCapabilities.class)); } - - public static void initSharedCapabilities(JvmtiEnvShared envShared) { - for (SHARED_CAPABILITIES_TYPE type : SHARED_CAPABILITIES_TYPE.values()) { - setSharedCapabilityFromBitVector(envShared, type, type.getInitial()); - } - } - - public static JvmtiError relinquishCapabilities(JvmtiEnvShared sharedCapabilities, JvmtiCapabilities current, JvmtiCapabilities unwanted) { - long alwaysSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO); - long onLoadSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO); - long onLoadSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING); - long alwaysSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING); - - long currentBitVector = convertCapabilitiesToBitVector(current); - long unwantedBitVector = convertCapabilitiesToBitVector(unwanted); - long toTrash, temp; - - toTrash = both(currentBitVector, unwantedBitVector); - temp = both(alwaysSoloBitVector, toTrash); - alwaysSoloRemainingBitVector = either(alwaysSoloRemainingBitVector, temp); - temp = both(onLoadSoloBitVector, toTrash); - onLoadSoloRemainingBitVector = either(onLoadSoloRemainingBitVector, temp); - - // TODO dprcci add virtual thread support - - update(); - - temp = exclude(currentBitVector, unwantedBitVector); - - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO, alwaysSoloBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO, onLoadSoloBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING, alwaysSoloRemainingBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING, onLoadSoloRemainingBitVector); - - assignBitVectoToCapabilities(current, temp); - - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getPotentialCapabilities(int phase, JvmtiCapabilities current, JvmtiCapabilities prohibited, JvmtiEnvShared sharedCapabilities, JvmtiCapabilities result) { - long always = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS); - long alwaysSoloRemaining = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING); - long onLoad = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD); - long onLoadSoloRemaining = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING); - - long currentVector = convertCapabilitiesToBitVector(current); - long prohibitedVector = convertCapabilitiesToBitVector(prohibited); - - long potentialVector = computePotentialBitVector(phase, currentVector, prohibitedVector, always, alwaysSoloRemaining, onLoad, onLoadSoloRemaining); - assignBitVectoToCapabilities(result, potentialVector); - - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError addCapabilities(int phase, JvmtiEnvShared sharedCapabilities, JvmtiCapabilities current, JvmtiCapabilities prohibited, JvmtiCapabilities desired) { - - long alwaysBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS); - long alwaysSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO); - long onLoadBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD); - long onLoadSoloBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO); - long onLoadSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING); - long alwaysSoloRemainingBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING); - long acquiredBitVector = getBitVectorFromSharedCapability(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ACQUIRED); - - long currentBitVector = convertCapabilitiesToBitVector(current); - long prohibitedBitVector = convertCapabilitiesToBitVector(prohibited); - long desiredBitVector = convertCapabilitiesToBitVector(desired); - - long temp = computePotentialBitVector(phase, currentBitVector, prohibitedBitVector, - alwaysBitVector, alwaysSoloRemainingBitVector, onLoadBitVector, onLoadSoloRemainingBitVector); - - if (hasSome(exclude(desiredBitVector, temp))) { - return JvmtiError.JVMTI_ERROR_NOT_AVAILABLE; - } - - acquiredBitVector = either(acquiredBitVector, desiredBitVector); - - // onload capabilities that got added are now permanent - so, also remove from onload - temp = both(onLoadBitVector, desiredBitVector); - alwaysBitVector = either(alwaysBitVector, temp); - onLoadBitVector = exclude(onLoadBitVector, temp); - - // same for solo capabilities (transferred capabilities in the remaining sets handled as - // part of standard grab - below) - temp = both(onLoadSoloBitVector, desiredBitVector); - alwaysSoloBitVector = either(alwaysSoloBitVector, temp); - onLoadSoloBitVector = exclude(onLoadSoloBitVector, temp); - - // remove solo capabilities that are now taken - alwaysSoloRemainingBitVector = exclude(alwaysSoloRemainingBitVector, desiredBitVector); - onLoadSoloRemainingBitVector = exclude(onLoadSoloRemainingBitVector, desiredBitVector); - - // TODO dprcci add virtual thread support - - // return the result - temp = either(currentBitVector, desiredBitVector); - update(); - - // update shared capabilities - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS, alwaysBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO, alwaysSoloBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD, onLoadBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO, onLoadSoloBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ON_LOAD_SOLO_REMAINING, onLoadSoloRemainingBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ALWAYS_SOLO_REMAINING, alwaysSoloRemainingBitVector); - setSharedCapabilityFromBitVector(sharedCapabilities, SHARED_CAPABILITIES_TYPE.ACQUIRED, acquiredBitVector); - - // write result back - assignBitVectoToCapabilities(current, temp); - - return JvmtiError.JVMTI_ERROR_NONE; - } - - // TODO @dprcci implement - private static void update() { - } - - private static long computePotentialBitVector(int phase, long current, long prohibited, - long always, long alwaysSoloRemaining, long onLoad, long onLoadSoloRemaining) { - long potential; - - potential = exclude(always, prohibited); - potential = either(potential, current); - potential = either(potential, alwaysSoloRemaining); // TODO @dprcci checck - - // TODO @dprcci temporarily disabled for tests - // if (phase == JvmtiPhase.JVMTI_PHASE_ONLOAD()) { - if (true) { - potential = either(potential, onLoad); - potential = either(potential, onLoadSoloRemaining); - } - return potential; - } - - private static long getBitVectorFromSharedCapability(JvmtiEnvShared sharedCapability, SHARED_CAPABILITIES_TYPE type) { - return convertCapabilitiesToBitVector(JvmtiEnvSharedUtil.getSharedCapability(sharedCapability, type)); - } - - private static void setSharedCapabilityFromBitVector(JvmtiEnvShared sharedCapability, SHARED_CAPABILITIES_TYPE type, long bitVector) { - assignBitVectoToCapabilities(JvmtiEnvSharedUtil.getSharedCapability(sharedCapability, type), bitVector); - } - - private static void assignBitVectoToCapabilities(JvmtiCapabilities capabilities, long capabilityBitVector) { - for (JvmtiCapabilitiesEnum cap : allCapabilitiesEnumValues) { - boolean value = ((1L << cap.ordinal()) & capabilityBitVector) != 0; - setCapability(cap, capabilities, value); - } - } - - private static long convertCapabilitiesToBitVector(JvmtiCapabilities capabilities) { - long capabilitiesVector = 0L; - for (JvmtiCapabilitiesEnum cap : allCapabilitiesEnumValues) { - if (getCapability(cap, capabilities)) { - capabilitiesVector |= 1L << cap.ordinal(); - } - } - return capabilitiesVector; - } - - private static void setCapability(JvmtiCapabilitiesEnum cap, JvmtiCapabilities capabilities, boolean value) { - switch (cap) { - case CAN_TAG_OBJECTS -> capabilities.setCanTagObjects(value); - case CAN_GENERATE_FIELD_MODIFICATION_EVENTS -> capabilities.setCanGenerateFieldModificationEvents(value); - case CAN_GENERATE_FIELD_ACCESS_EVENTS -> capabilities.setCanGenerateFieldAccessEvents(value); - case CAN_GET_BYTECODES -> capabilities.setCanGetBytecodes(value); - case CAN_GET_SYNTHETIC_ATTRIBUTE -> capabilities.setCanGetSyntheticAttribute(value); - case CAN_GET_OWNED_MONITOR_INFO -> capabilities.setCanGetOwnedMonitorInfo(value); - case CAN_GET_CURRENT_CONTENDED_MONITOR -> capabilities.setCanGetCurrentContendedMonitor(value); - case CAN_GET_MONITOR_INFO -> capabilities.setCanGetMonitorInfo(value); - case CAN_POP_FRAME -> capabilities.setCanPopFrame(value); - case CAN_REDEFINE_CLASSES -> capabilities.setCanRedefineClasses(value); - case CAN_SIGNAL_THREAD -> capabilities.setCanSignalThread(value); - case CAN_GET_SOURCE_FILE_NAME -> capabilities.setCanGetSourceFileName(value); - case CAN_GET_LINE_NUMBERS -> capabilities.setCanGetLineNumbers(value); - case CAN_GET_SOURCE_DEBUG_EXTENSION -> capabilities.setCanGetSourceDebugExtension(value); - case CAN_ACCESS_LOCAL_VARIABLES -> capabilities.setCanAccessLocalVariables(value); - case CAN_MAINTAIN_ORIGINAL_METHOD_ORDER -> capabilities.setCanMaintainOriginalMethodOrder(value); - case CAN_GENERATE_SINGLE_STEP_EVENTS -> capabilities.setCanGenerateSingleStepEvents(value); - case CAN_GENERATE_EXCEPTION_EVENTS -> capabilities.setCanGenerateExceptionEvents(value); - case CAN_GENERATE_FRAME_POP_EVENTS -> capabilities.setCanGenerateFramePopEvents(value); - case CAN_GENERATE_BREAKPOINT_EVENTS -> capabilities.setCanGenerateBreakpointEvents(value); - case CAN_SUSPEND -> capabilities.setCanSuspend(value); - case CAN_REDEFINE_ANY_CLASS -> capabilities.setCanRedefineAnyClass(value); - case CAN_GET_CURRENT_THREAD_CPU_TIME -> capabilities.setCanGetCurrentThreadCpuTime(value); - case CAN_GET_THREAD_CPU_TIME -> capabilities.setCanGetThreadCpuTime(value); - case CAN_GENERATE_METHOD_ENTRY_EVENTS -> capabilities.setCanGenerateMethodEntryEvents(value); - case CAN_GENERATE_METHOD_EXIT_EVENTS -> capabilities.setCanGenerateMethodExitEvents(value); - case CAN_GENERATE_ALL_CLASS_HOOK_EVENTS -> capabilities.setCanGenerateAllClassHookEvents(value); - case CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS -> capabilities.setCanGenerateCompiledMethodLoadEvents(value); - case CAN_GENERATE_MONITOR_EVENTS -> capabilities.setCanGenerateMonitorEvents(value); - case CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS -> capabilities.setCanGenerateVmObjectAllocEvents(value); - case CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS -> capabilities.setCanGenerateNativeMethodBindEvents(value); - case CAN_GENERATE_GARBAGE_COLLECTION_EVENTS -> capabilities.setCanGenerateGarbageCollectionEvents(value); - case CAN_GENERATE_OBJECT_FREE_EVENTS -> capabilities.setCanGenerateObjectFreeEvents(value); - case CAN_FORCE_EARLY_RETURN -> capabilities.setCanForceEarlyReturn(value); - case CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO -> capabilities.setCanGetOwnedMonitorStackDepthInfo(value); - case CAN_GET_CONSTANT_POOL -> capabilities.setCanGetConstantPool(value); - case CAN_SET_NATIVE_METHOD_PREFIX -> capabilities.setCanSetNativeMethodPrefix(value); - case CAN_RETRANSFORM_CLASSES -> capabilities.setCanRetransformClasses(value); - case CAN_RETRANSFORM_ANY_CLASS -> capabilities.setCanRetransformAnyClass(value); - case CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS -> capabilities.setCanGenerateResourceExhaustionHeapEvents(value); - case CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS -> capabilities.setCanGenerateResourceExhaustionThreadsEvents(value); - case CAN_GENERATE_EARLY_VMSTART -> capabilities.setCanGenerateEarlyVmstart(value); - case CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS -> capabilities.setCanGenerateEarlyClassHookEvents(value); - case CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS -> capabilities.setCanGenerateSampledObjectAllocEvents(value); - case CAN_SUPPORT_VIRTUAL_THREADS -> capabilities.setCanSupportVirtualThreads(value); - default -> { - } - } - } - - private static boolean getCapability(JvmtiCapabilitiesEnum cap, JvmtiCapabilities capabilities) { - return switch (cap) { - case CAN_TAG_OBJECTS -> capabilities.getCanTagObjects(); - case CAN_GENERATE_FIELD_MODIFICATION_EVENTS -> capabilities.getCanGenerateFieldModificationEvents(); - case CAN_GENERATE_FIELD_ACCESS_EVENTS -> capabilities.getCanGenerateFieldAccessEvents(); - case CAN_GET_BYTECODES -> capabilities.getCanGetBytecodes(); - case CAN_GET_SYNTHETIC_ATTRIBUTE -> capabilities.getCanGetSyntheticAttribute(); - case CAN_GET_OWNED_MONITOR_INFO -> capabilities.getCanGetOwnedMonitorInfo(); - case CAN_GET_CURRENT_CONTENDED_MONITOR -> capabilities.getCanGetCurrentContendedMonitor(); - case CAN_GET_MONITOR_INFO -> capabilities.getCanGetMonitorInfo(); - case CAN_POP_FRAME -> capabilities.getCanPopFrame(); - case CAN_REDEFINE_CLASSES -> capabilities.getCanRedefineClasses(); - case CAN_SIGNAL_THREAD -> capabilities.getCanSignalThread(); - case CAN_GET_SOURCE_FILE_NAME -> capabilities.getCanGetSourceFileName(); - case CAN_GET_LINE_NUMBERS -> capabilities.getCanGetLineNumbers(); - case CAN_GET_SOURCE_DEBUG_EXTENSION -> capabilities.getCanGetSourceDebugExtension(); - case CAN_ACCESS_LOCAL_VARIABLES -> capabilities.getCanAccessLocalVariables(); - case CAN_MAINTAIN_ORIGINAL_METHOD_ORDER -> capabilities.getCanMaintainOriginalMethodOrder(); - case CAN_GENERATE_SINGLE_STEP_EVENTS -> capabilities.getCanGenerateSingleStepEvents(); - case CAN_GENERATE_EXCEPTION_EVENTS -> capabilities.getCanGenerateExceptionEvents(); - case CAN_GENERATE_FRAME_POP_EVENTS -> capabilities.getCanGenerateFramePopEvents(); - case CAN_GENERATE_BREAKPOINT_EVENTS -> capabilities.getCanGenerateBreakpointEvents(); - case CAN_SUSPEND -> capabilities.getCanSuspend(); - case CAN_REDEFINE_ANY_CLASS -> capabilities.getCanRedefineAnyClass(); - case CAN_GET_CURRENT_THREAD_CPU_TIME -> capabilities.getCanGetCurrentThreadCpuTime(); - case CAN_GET_THREAD_CPU_TIME -> capabilities.getCanGetThreadCpuTime(); - case CAN_GENERATE_METHOD_ENTRY_EVENTS -> capabilities.getCanGenerateMethodEntryEvents(); - case CAN_GENERATE_METHOD_EXIT_EVENTS -> capabilities.getCanGenerateMethodExitEvents(); - case CAN_GENERATE_ALL_CLASS_HOOK_EVENTS -> capabilities.getCanGenerateAllClassHookEvents(); - case CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS -> capabilities.getCanGenerateCompiledMethodLoadEvents(); - case CAN_GENERATE_MONITOR_EVENTS -> capabilities.getCanGenerateMonitorEvents(); - case CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS -> capabilities.getCanGenerateVmObjectAllocEvents(); - case CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS -> capabilities.getCanGenerateNativeMethodBindEvents(); - case CAN_GENERATE_GARBAGE_COLLECTION_EVENTS -> capabilities.getCanGenerateGarbageCollectionEvents(); - case CAN_GENERATE_OBJECT_FREE_EVENTS -> capabilities.getCanGenerateObjectFreeEvents(); - case CAN_FORCE_EARLY_RETURN -> capabilities.getCanForceEarlyReturn(); - case CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO -> capabilities.getCanGetOwnedMonitorStackDepthInfo(); - case CAN_GET_CONSTANT_POOL -> capabilities.getCanGetConstantPool(); - case CAN_SET_NATIVE_METHOD_PREFIX -> capabilities.getCanSetNativeMethodPrefix(); - case CAN_RETRANSFORM_CLASSES -> capabilities.getCanRetransformClasses(); - case CAN_RETRANSFORM_ANY_CLASS -> capabilities.getCanRetransformAnyClass(); - case CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS -> capabilities.getCanGenerateResourceExhaustionHeapEvents(); - case CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS -> capabilities.getCanGenerateResourceExhaustionThreadsEvents(); - case CAN_GENERATE_EARLY_VMSTART -> capabilities.getCanGenerateEarlyVmstart(); - case CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS -> capabilities.getCanGenerateEarlyClassHookEvents(); - case CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS -> capabilities.getCanGenerateSampledObjectAllocEvents(); - case CAN_SUPPORT_VIRTUAL_THREADS -> capabilities.getCanSupportVirtualThreads(); - // has to be there for no memory alloc - default -> false; - }; - } - - private static boolean hasSome(long a) { - return a != 0L; - } - - private static long both(long a, long b) { - return a & b; - } - - private static long either(long a, long b) { - return a | b; - } - - private static long exclude(long a, long b) { - return a & ~b; - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java deleted file mode 100644 index 11017ff691eb..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiClassInfoUtil.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import static com.oracle.svm.core.jvmti.utils.JvmtiUninterruptibleUtils.ReplaceDotWithSlash; -import static com.oracle.svm.core.jvmti.utils.JvmtiUninterruptibleUtils.writeStringToCCharArray; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.IdentityHashMap; -import java.util.Objects; -import java.util.Set; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.StackValue; -import org.graalvm.nativeimage.c.type.CCharPointer; -import org.graalvm.nativeimage.c.type.CCharPointerPointer; -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.ComparableWord; -import org.graalvm.word.Pointer; -import org.graalvm.word.PointerBase; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.jdk.JavaLangSubstitutions; -import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.access.JNIAccessibleMethod; -import com.oracle.svm.core.jni.access.JNIAccessibleMethodDescriptor; -import com.oracle.svm.core.jni.access.JNIReflectionDictionary; -import com.oracle.svm.core.jni.headers.JNIFieldId; -import com.oracle.svm.core.jni.headers.JNIFieldIdPointer; -import com.oracle.svm.core.jni.headers.JNIFieldIdPointerPointer; -import com.oracle.svm.core.jni.headers.JNIMethodId; -import com.oracle.svm.core.jni.headers.JNIMethodIdPointer; -import com.oracle.svm.core.jni.headers.JNIMethodIdPointerPointer; -import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.core.jvmti.headers.BooleanPointer; -import com.oracle.svm.core.jvmti.headers.JClass; -import com.oracle.svm.core.jvmti.headers.JClassPointer; -import com.oracle.svm.core.jvmti.headers.JClassPointerPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.locks.VMMutex; -import com.oracle.svm.core.reflect.target.Target_java_lang_reflect_Method; - -import jdk.graal.compiler.api.replacements.Fold; - -public final class JvmtiClassInfoUtil { - - private static final byte JNI_FALSE = 0; - private static final byte JNI_TRUE = 1; - private static final int MAX_SIGNATURE_LENGTH = 256; - private final char[] signatureCharBuffer; - private final ReplaceDotWithSlash nameToSigReplacer = new ReplaceDotWithSlash(); - private final VMMutex mutex = new VMMutex("jvmtiGetClassSignature"); - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiClassInfoUtil() { - this.signatureCharBuffer = new char[MAX_SIGNATURE_LENGTH]; - } - - @Fold - public static JvmtiClassInfoUtil singleton() { - return ImageSingletons.lookup(JvmtiClassInfoUtil.class); - } - - /* - * Classes - */ - public static JvmtiError getClassSignature(JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return singleton().getClassSignatureInternal(klass, signaturePtr, genericPtr); - } - - public static JvmtiError isModifiableClass(JClass klass, BooleanPointer isModifiableClassPtr) { - // result is always the same, but checked for consistency - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - ((Pointer) isModifiableClassPtr).writeInt(0, JNI_FALSE); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError isArrayClass(JClass klass, BooleanPointer isArrayClassPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - // TODO @dprcci make sure of the BooleanPointer type - ((Pointer) isArrayClassPtr).writeByte(0, javaClass.isArray() ? JNI_TRUE : JNI_FALSE); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError isInterface(JClass klass, BooleanPointer isInterfacePtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - ((Pointer) isInterfacePtr).writeByte(0, javaClass.isInterface() ? JNI_TRUE : JNI_FALSE); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getImplementedInterfaces(JClass klass, CIntPointer interfaceCountPtr, JClassPointerPointer interfacesPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - - /* - * An empty interface list is returned for array classes and primitive classes (for example, - * java.lang.Integer.TYPE) - */ - if (javaClass.isPrimitive() || javaClass.isArray()) { - ((Pointer) interfacesPtr).writeWord(0, WordFactory.nullPointer()); - interfaceCountPtr.write(0); - return JvmtiError.JVMTI_ERROR_NONE; - } - - Class[] classInterfaces = javaClass.getInterfaces(); - int nbInterfaces = classInterfaces.length; - /* - * if(nbInterfaces == 0){ ((Pointer) interfacesPtr).writeWord(0, WordFactory.nullPointer()); - * interfaceCountPtr.write(nbInterfaces); return JvmtiError.JVMTI_ERROR_NONE; } - */ - - JClassPointer interfaceArray = getResultArray(nbInterfaces, ConfigurationValues.getTarget().wordSize); - for (int i = 0; i < nbInterfaces; i++) { - JClass interfaceHandle = (JClass) JNIObjectHandles.createLocal(classInterfaces[i]); - writeArrayAtIndex(interfaceArray, i, ConfigurationValues.getTarget().wordSize, interfaceHandle); - } - - ((Pointer) interfacesPtr).writeWord(0, interfaceArray); - interfaceCountPtr.write(nbInterfaces); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getClassFields(JClass klass, CIntPointer fieldCountPtr, JNIFieldIdPointerPointer fieldsPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - /* - * An empty field list is returned for array classes and primitive classes (for example, - * java.lang.Integer.TYPE) - */ - if (javaClass.isPrimitive() || javaClass.isArray()) { - ((Pointer) fieldsPtr).writeWord(0, WordFactory.nullPointer()); - fieldCountPtr.write(0); - return JvmtiError.JVMTI_ERROR_NONE; - } - - Field[] declaredFields = javaClass.getDeclaredFields(); - int nbDeclaredFields = declaredFields.length; - JNIFieldIdPointer fieldIDArray = getResultArray(nbDeclaredFields, ConfigurationValues.getTarget().wordSize); - - int nbWritten = 0; - for (int i = 0; i < nbDeclaredFields; i++) { - Field field = declaredFields[i]; - String name = field.getName(); - boolean isStatic = Modifier.isStatic(field.getModifiers()); - JNIFieldId fieldID = JNIReflectionDictionary.singleton().getDeclaredFieldID(javaClass, name, isStatic); - if (fieldID.isNonNull()) { - writeArrayAtIndex(fieldIDArray, nbWritten++, ConfigurationValues.getTarget().wordSize, fieldID); - } - } - // We could realloc if nbWritten != nbDeclaredFields but the time costs seem greater than - // the space gains - ((Pointer) fieldsPtr).writeWord(0, fieldIDArray); - fieldCountPtr.write(nbWritten); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getClassMethods(JClass klass, CIntPointer methodCountPtr, JNIMethodIdPointerPointer methodsPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - - /* - * An empty method list is returned for array classes and primitive classes (for example, - * java.lang.Integer.TYPE) - */ - if (javaClass.isPrimitive() || javaClass.isArray()) { - ((Pointer) methodsPtr).writeWord(0, WordFactory.nullPointer()); - methodCountPtr.write(0); - return JvmtiError.JVMTI_ERROR_NONE; - } - - Method[] declaredMethods = javaClass.getDeclaredMethods(); - int nbMethods = declaredMethods.length; - JNIMethodIdPointer methodsIDArray = getResultArray(nbMethods, ConfigurationValues.getTarget().wordSize); - - int nbWritten = 0; - for (int i = 0; i < nbMethods; i++) { - String methodName = declaredMethods[i].getName(); - JNIMethodId methodId = JNIReflectionDictionary.singleton().toMethodID(javaClass, methodName); - if (methodId.isNonNull()) { - writeArrayAtIndex(methodsIDArray, nbWritten++, ConfigurationValues.getTarget().wordSize, methodId); - } - } - ((Pointer) methodsPtr).writeWord(0, methodsIDArray); - methodCountPtr.write(nbWritten); - return JvmtiError.JVMTI_ERROR_NONE; - - } - - public static JvmtiError getClassModifiers(JClass klass, CIntPointer modifiersPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - modifiersPtr.write(javaClass.getModifiers()); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getSourceFileName(JClass klass, CCharPointerPointer sourceNamePtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - String sourceFileName = DynamicHub.fromClass(javaClass).getSourceFileName(); - UnsignedWord bufferSize = WordFactory.unsigned(UninterruptibleUtils.String.modifiedUTF8Length(sourceFileName, true, null)); - CCharPointer buffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); - UninterruptibleUtils.String.toModifiedUTF8(sourceFileName, (Pointer) buffer, ((Pointer) buffer).add(bufferSize), true); - ((Pointer) sourceNamePtr).writeWord(0, buffer); - return JvmtiError.JVMTI_ERROR_NONE; - } - - /* - * Fields - */ - public static JvmtiError getFieldName(JClass klass, JNIFieldId fieldId, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - Field field = getFieldFromHandle(javaClass, fieldId, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - return singleton().writeFieldInfo(field, namePtr, signaturePtr, genericPtr); - } - - public static JvmtiError getFieldDeclaringClass(JClass klass, JNIFieldId fieldId, JClassPointer declaringClassPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - Field field = getFieldFromHandle(javaClass, fieldId, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - - if (!isValidFieldId(javaClass, fieldId)) { - return JvmtiError.JVMTI_ERROR_INVALID_FIELDID; - } - - Class declaringClass = field.getDeclaringClass(); - JClass jclass = (JClass) JNIObjectHandles.createLocal(declaringClass); - ((Pointer) declaringClassPtr).writeWord(0, jclass); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getFieldModifiers(JClass klass, JNIFieldId fieldId, CIntPointer modifiersPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - Field field = getFieldFromHandle(javaClass, fieldId, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - - if (!isValidFieldId(javaClass, fieldId)) { - return JvmtiError.JVMTI_ERROR_INVALID_FIELDID; - } - - int fieldModifiers = field.getModifiers(); - modifiersPtr.write(fieldModifiers); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError isFieldSynthetic(JClass klass, JNIFieldId fieldId, BooleanPointer isSyntheticPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - Field field = getFieldFromHandle(javaClass, fieldId, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - - if (!isValidFieldId(javaClass, fieldId)) { - return JvmtiError.JVMTI_ERROR_INVALID_FIELDID; - } - - boolean isSynthetic = field.isSynthetic(); - ((Pointer) isSyntheticPtr).writeByte(0, isSynthetic ? JNI_TRUE : JNI_FALSE); - return JvmtiError.JVMTI_ERROR_NONE; - } - - /* - * Methods - */ - public static JvmtiError getMethodDeclaringClass(JNIMethodId method, JClassPointer declaringClassPtr) { - JNIAccessibleMethod accessibleMethod = JNIReflectionDictionary.getMethodByID(method); - if (accessibleMethod == null) { - return null; - } - Class declaringClass = accessibleMethod.getDeclaringClass().getClassObject(); - if (declaringClass == null) { - return JvmtiError.JVMTI_ERROR_INVALID_METHODID; - } - JNIObjectHandle jClass = JNIObjectHandles.createLocal(declaringClass); - ((Pointer) declaringClassPtr).writeWord(0, jClass); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getMethodModifiers(JNIMethodId methodId, CIntPointer modifiersPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Method m = getMethodFromHandle(methodId, error); - if (JvmtiError.fromValue(error.read()) != JvmtiError.JVMTI_ERROR_NONE) { - return JvmtiError.fromValue(error.read()); - } - modifiersPtr.write(m.getModifiers()); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError isMethodNative(JNIMethodId methodId, BooleanPointer isNativePtr) { - if (JNIReflectionDictionary.getMethodByID(methodId) == null) { - return JvmtiError.JVMTI_ERROR_INVALID_METHODID; - } - ((Pointer) isNativePtr).writeByte(0, JNIReflectionDictionary.isMethodNative(methodId) ? JNI_TRUE : JNI_FALSE); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError isMethodSynthetic(JNIMethodId methodId, BooleanPointer isSyntheticPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Method m = getMethodFromHandle(methodId, error); - if (JvmtiError.fromValue(error.read()) != JvmtiError.JVMTI_ERROR_NONE) { - return JvmtiError.fromValue(error.read()); - } - ((Pointer) isSyntheticPtr).writeByte(0, m.isSynthetic() ? JNI_TRUE : JNI_FALSE); - return JvmtiError.JVMTI_ERROR_INVALID_METHODID; - } - - public static JvmtiError getMethodName(JNIMethodId methodId, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - JNIAccessibleMethod accessibleMethod = JNIReflectionDictionary.getMethodByID(methodId); - if (accessibleMethod == null) { - return JvmtiError.JVMTI_ERROR_INVALID_METHODID; - } - JNIAccessibleMethodDescriptor descriptor = JNIReflectionDictionary.getMethodDescriptor(accessibleMethod); - JvmtiError error; - // name - if ((error = writeStringOrNull(descriptor.getName(), namePtr)) != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - // signature - if ((error = writeStringOrNull(descriptor.getSignature(), signaturePtr)) != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - - // generic pointer - if (genericPtr.isNonNull()) { - CIntPointer errorPtr = StackValue.get(CIntPointer.class); - Method m = getMethodFromHandle(methodId, errorPtr); - if (JvmtiError.fromValue(errorPtr.read()) != JvmtiError.JVMTI_ERROR_NONE) { - genericPtr.write(0, WordFactory.nullPointer()); - return JvmtiError.fromValue(errorPtr.read()); - } - String genericSignature = SubstrateUtil.cast(m, Target_java_lang_reflect_Method.class).signature; - if (genericSignature == null) { - genericPtr.write(0, WordFactory.nullPointer()); - return JvmtiError.JVMTI_ERROR_NONE; - } - return writeStringToUTF8(genericSignature, genericPtr); - } - return JvmtiError.JVMTI_ERROR_NONE; - } - - /* - * Helpers - */ - private static void writeArrayAtIndex(P array, int index, int elementSize, T value) { - ((Pointer) array).writeWord(index * elementSize, value); - } - - private static T getResultArray(int arraySize, int elementSize) { - int arrayByteSize = ConfigurationValues.getTarget().wordSize * arraySize; - return ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(arrayByteSize)); - } - - private static boolean isValidFieldId(Class javaClass, JNIFieldId fieldId) { - return JNIReflectionDictionary.singleton().getFieldNameByID(javaClass, fieldId) != null; - } - - private static Class getClassFromHandle(JClass klass, CIntPointer error) { - Class javaClass; - try { - javaClass = JNIObjectHandles.getObject(klass); - } catch (ClassCastException | IllegalArgumentException e) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_CLASS.getCValue()); - return null; - } - if (javaClass == null) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_CLASS.getCValue()); - return null; - } - error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - return javaClass; - } - - private static Field getFieldFromHandle(Class javaClass, JNIFieldId fieldId, CIntPointer error) { - String name = JNIReflectionDictionary.singleton().getFieldNameByID(javaClass, fieldId); - if (name == null) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_FIELDID.getCValue()); - return null; - } - Field field; - try { - field = javaClass.getField(name); - } catch (NoSuchFieldException e) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_FIELDID.getCValue()); - return null; - } - error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - return field; - } - - private static Method getMethodFromHandle(JNIMethodId methodID, CIntPointer error) { - JNIAccessibleMethod accessibleMethod = JNIReflectionDictionary.getMethodByID(methodID); - if (accessibleMethod == null) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_METHODID.getCValue()); - return null; - } - Class declaringClass = accessibleMethod.getDeclaringClass().getClassObject(); - String signature = JNIReflectionDictionary.getMethodDescriptor(accessibleMethod).getSignature(); - for (Method m : declaringClass.getMethods()) { - // TODO @dprcci fix - String sig = SubstrateUtil.cast(m, Target_java_lang_reflect_Method.class).signature; - if (Objects.equals(sig, signature)) { - error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - return m; - } - error.write(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); - return null; - } - error.write(JvmtiError.JVMTI_ERROR_INVALID_METHODID.getCValue()); - return null; - } - - private static JvmtiError writeStringOrNull(String value, CCharPointerPointer bufferPtr) { - if (bufferPtr.isNonNull()) { - return writeStringToUTF8(value, bufferPtr); - } else { - bufferPtr.write(0, WordFactory.nullPointer()); - return JvmtiError.JVMTI_ERROR_NONE; - } - } - - private JvmtiError writeFieldInfo(Field field, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - try { - mutex.lock(); - JvmtiError error; - if (namePtr.isNonNull()) { - String name = field.getName(); - error = writeStringToUTF8(name, namePtr); - if (error != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - } - if (signaturePtr.isNonNull()) { - error = createFieldSignature(field, signaturePtr); - if (error != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - } - if (genericPtr.isNonNull()) { - if (!field.getType().equals(field.getGenericType())) { - return createGenericFieldSignature(field, genericPtr); - } else { - genericPtr.write(WordFactory.nullPointer()); - } - } - return JvmtiError.JVMTI_ERROR_NONE; - } finally { - mutex.unlock(); - } - } - - private JvmtiError createFieldSignature(Field field, CCharPointerPointer signaturePtr) { - Class fieldType = field.getType(); - int signatureSize; - if (fieldType.isPrimitive()) { - signatureSize = addTypeToName(fieldType, signatureCharBuffer); - } else { - signatureSize = encodeNameFromString(fieldType.getName(), signatureCharBuffer, 0); - } - return writeStringToCCharArray(signatureCharBuffer, signatureSize, signaturePtr, nameToSigReplacer); - } - - // TODO @dprcci temp - private JvmtiError createGenericFieldSignature(Field field, CCharPointerPointer genericSignaturePtr) { - String sig = field.toGenericString(); - return writeStringToUTF8(sig, genericSignaturePtr); - } - - private JvmtiError getClassSignatureInternal(JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - CIntPointer error = StackValue.get(CIntPointer.class); - Class javaClass = getClassFromHandle(klass, error); - if (error.read() != JvmtiError.JVMTI_ERROR_NONE.getCValue()) { - return JvmtiError.fromValue(error.read()); - } - return writeClassSignatures(javaClass, signaturePtr, genericPtr); - } - - private JvmtiError writeClassSignatures(Class javaClass, CCharPointerPointer signaturePtr, CCharPointerPointer genericSignaturePtr) { - try { - mutex.lock(); - if (signaturePtr.isNonNull()) { - JvmtiError error = createClassSignature(javaClass, signaturePtr); - if (error != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - } - if (genericSignaturePtr.isNonNull()) { - String genericSignature = JVMTIGenericInfoMap.singleton().classSignatures.getOrDefault(javaClass, null); - if (genericSignature != null) { - String signature = JVMTIGenericInfoMap.singleton().classSignatures.get(javaClass); - return writeStringToUTF8(signature, genericSignaturePtr); - } else { - genericSignaturePtr.write(WordFactory.nullPointer()); - } - } - return JvmtiError.JVMTI_ERROR_NONE; - } finally { - mutex.unlock(); - } - } - - private JvmtiError createClassSignature(Class javaClass, CCharPointerPointer signaturePtr) { - String signature = DynamicHub.fromClass(javaClass).getName(); - int startIndex = addTypeToName(javaClass, signatureCharBuffer); - int signatureSize = encodeNameFromString(signature, signatureCharBuffer, startIndex); - return writeStringToCCharArray(signatureCharBuffer, signatureSize, signaturePtr, nameToSigReplacer); - } - - private static int addTypeToName(Class clazz, char[] buffer) { - char desc; - int index = 0; - if (clazz.isArray()) { - return 0; - } - if (clazz == boolean.class) { - desc = 'Z'; - } else if (clazz == byte.class) { - desc = 'B'; - } else if (clazz == char.class) { - desc = 'C'; - } else if (clazz == short.class) { - desc = 'S'; - } else if (clazz == int.class) { - desc = 'I'; - } else if (clazz == long.class) { - desc = 'J'; - } else if (clazz == float.class) { - desc = 'F'; - } else if (clazz == double.class) { - desc = 'D'; - } else if (clazz == void.class) { - desc = 'V'; - } else { - desc = 'L'; - } - buffer[index++] = desc; - return index; - } - - private static int encodeNameFromString(String name, char[] buffer, int fromIndex) { - if (fromIndex + name.length() >= MAX_SIGNATURE_LENGTH) { - return -1; - } - for (int i = 0; i < name.length(); i++) { - char curr = JavaLangSubstitutions.StringUtil.charAt(name, i); - buffer[fromIndex + i] = curr; - } - return fromIndex + name.length(); - } - - private static JvmtiError writeStringToUTF8(String signature, CCharPointerPointer signaturePtr) { - UnsignedWord bufferSize = WordFactory.unsigned(UninterruptibleUtils.String.modifiedUTF8Length(signature, true, null)); - CCharPointer cStringBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); - if (cStringBuffer.isNull()) { - signaturePtr.write(WordFactory.nullPointer()); - return JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; - } - UninterruptibleUtils.String.toModifiedUTF8(signature, (Pointer) cStringBuffer, ((Pointer) cStringBuffer).add(bufferSize), true, null); - signaturePtr.write(0, cStringBuffer); - return JvmtiError.JVMTI_ERROR_NONE; - } - - // TODO @dprcci might actually be useless thanks to Target_class. Must test and check - public static class JVMTIGenericInfoMap { - - private IdentityHashMap, String> classSignatures; - private static final int HEURISTIC_NB_CLASSES = 512; - - @Platforms(Platform.HOSTED_ONLY.class) - public JVMTIGenericInfoMap() { - this.classSignatures = new IdentityHashMap<>(HEURISTIC_NB_CLASSES); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void addSignature(Class clazz, String signature) { - classSignatures.putIfAbsent(clazz, signature); - } - - @Fold - public static JVMTIGenericInfoMap singleton() { - return ImageSingletons.lookup(JVMTIGenericInfoMap.class); - } - - @Platforms(Platform.HOSTED_ONLY.class) - public void discardUnused() { - IdentityHashMap, String> jniSignatures = new IdentityHashMap<>(); - Set> jniRegisteredClasses = JNIReflectionDictionary.singleton().getRegisteredClasses(); - // TODO @dprcci necessary to reduce Map size? - classSignatures.entrySet().stream().filter(e -> jniRegisteredClasses.contains(e.getKey())).forEach(e -> jniSignatures.putIfAbsent(e.getKey(), e.getValue())); - classSignatures = jniSignatures; - } - - } -} \ No newline at end of file diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java index c3500d537f90..8e1fb4174127 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnv.java @@ -29,6 +29,10 @@ import org.graalvm.nativeimage.c.struct.RawStructure; import org.graalvm.word.PointerBase; +/** + * Stores information about a JVMTI environment. JVMTI environments and their lifecycle are managed + * by {@link JvmtiEnvs}. + */ @RawStructure public interface JvmtiEnv extends PointerBase { @RawField @@ -43,26 +47,17 @@ public interface JvmtiEnv extends PointerBase { @RawField void setMagic(int value); - // TODO @dprcci is there a way to use type of enum? Also might become global - @RawField - int getPhase(); - @RawField - void setPhase(int phase); + JvmtiEnv getNext(); - //TODO change to global pointer to shared struct or keep per field accesses? @RawField - JvmtiEnvShared getEnvShared(); + void setNext(JvmtiEnv env); @RawField - void setEnvShared(JvmtiEnvShared envShared); + long getEventUserEnabled(); @RawField - JvmtiEnv getNextEnv(); - - @RawField - void setNextEnv(JvmtiEnv env); - + void setEventUserEnabled(long userEnabled); // The annotation-based fields above are incomplete because we directly embed other structures // into this raw struct, see below: diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java deleted file mode 100644 index 17901134463b..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabled.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.word.PointerBase; - -@RawStructure -public interface JvmtiEnvEventEnabled extends PointerBase { - @RawField - long getEventEnabled(); - - @RawField - void setEventEnabled(long eventEnabled); - - @RawField - long getCallbackEnabled(); - - @RawField - void setCallbackEnabled(long callbacksEnabled); - - @RawField - long getEventUserEnabled(); - - @RawField - void setEventUserEnabled(long userEnabled); -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java deleted file mode 100644 index 62959017919f..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvEventEnabledUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; - -import com.oracle.svm.core.jvmti.headers.JvmtiEvent; -import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; - -public final class JvmtiEnvEventEnabledUtils { - - public static final int JVMTI_MIN_EVENT_TYPE_VAL = 50; - public static final int JVMTI_MAX_EVENT_TYPE_VAL = 88; - public static final int JVMTI_NB_EVENTS = JVMTI_MAX_EVENT_TYPE_VAL - JVMTI_MIN_EVENT_TYPE_VAL; - - private static final long NO_EVENTS_ENABLED = 0L; - // TODO dprcci check if it is the actual value - private static final long INITIAL_ENABLED_EVENTS = NO_EVENTS_ENABLED; - - @Platforms(Platform.HOSTED_ONLY.class) - private JvmtiEnvEventEnabledUtils() { - } - - public static boolean isInValidEventRange(JvmtiEvent event) { - return event.getCValue() >= JvmtiEnvEventEnabledUtils.JVMTI_MIN_EVENT_TYPE_VAL || - event.getCValue() <= JvmtiEnvEventEnabledUtils.JVMTI_MAX_EVENT_TYPE_VAL; - } - - public static int getEventEnumIndex(JvmtiEvent event) { - return event.getCValue() - JVMTI_MIN_EVENT_TYPE_VAL; - } - - public static int getBitForEvent(JvmtiEvent event) { - return 1 << getEventEnumIndex(event); - } - - public static void setUserEventEnabled(JvmtiEnvEventEnabled envEventEnabled, JvmtiEvent event, boolean enabled) { - - long enabledBits = envEventEnabled.getEventUserEnabled(); - int mask = getBitForEvent(event); - if (enabled) { - enabledBits |= mask; - } else { - enabledBits &= ~mask; - } - envEventEnabled.setEventUserEnabled(enabledBits); - } - - public static boolean isUserEventEnabled(JvmtiEnvEventEnabled envEventEnabled, JvmtiEvent event) { - return (getBitForEvent(event) & envEventEnabled.getEventUserEnabled()) != 0; - } - - public static void clearUserEvents(JvmtiEnvEventEnabled envEventEnabled) { - envEventEnabled.setEventUserEnabled(NO_EVENTS_ENABLED); - } - - // TODO @dprcci expand (might not be useful anyways since memory is calloc'ed) - public static void initialize(JvmtiEnvEventEnabled envEventEnabled) { - envEventEnabled.setEventUserEnabled(INITIAL_ENABLED_EVENTS); - } - - public static void setEventCallbacksEnabled(JvmtiEnvEventEnabled envEventEnabled, JvmtiEventCallbacks callbacks) { - envEventEnabled.setCallbackEnabled(JvmtiEventCallbacksUtil.convertCallbacksToBitVector(callbacks)); - } - - // TODO @dprcci implement in Hotspot this is used to set the event_enabled. Current - // implementation works by checking user_event_enabled and not event_enable - public static void recomputeEnabled() { - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java deleted file mode 100644 index 811a7ebc928e..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvManager.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.type.WordPointer; -import org.graalvm.word.PointerBase; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; -import com.oracle.svm.core.locks.VMMutex; -import com.oracle.svm.core.snippets.ImplicitExceptions; - -import jdk.graal.compiler.api.replacements.Fold; - -public final class JvmtiEnvManager { - - private PointerBase headEnvironment; - private PointerBase tailEnvironment; - - private final VMMutex mutex; - private PointerBase sharedEnvironment; - private boolean initialized; - - private int phase; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiEnvManager() { - headEnvironment = WordFactory.nullPointer(); - tailEnvironment = WordFactory.nullPointer(); - mutex = new VMMutex("jvmtiEnvManager"); - sharedEnvironment = WordFactory.nullPointer(); - initialized = false; - phase = -1; - } - - @Fold - public static JvmtiEnvManager singleton() { - return ImageSingletons.lookup(JvmtiEnvManager.class); - } - - public JvmtiEnv getHeadEnvironment() { - return (JvmtiEnv) headEnvironment; - } - - public JvmtiEnv getTailEnvironment() { - return (JvmtiEnv) tailEnvironment; - } - - public void setTailEnvironment(JvmtiEnv env) { - mutex.lock(); - tailEnvironment = env; - mutex.unlock(); - } - - public boolean hasAnyEnvironments() { - return headEnvironment.isNonNull(); - } - - public JvmtiEnvShared getSharedEnvironment() { - return (JvmtiEnvShared) sharedEnvironment; - } - - public boolean isInitialized() { - return initialized; - } - - public int getPhase() { - return phase; - } - - public void setPhase(int phase) { - mutex.lock(); - this.phase = phase; - mutex.unlock(); - } - - public void createJvmtiEnv(WordPointer env) { - JvmtiExternalEnv envExt = JvmtiEnvUtil.allocate(); - JvmtiEnv envInt = JvmtiEnvUtil.toInternal(envExt); - - mutex.lock(); - if (!initialized) { - initialize(); - } - JvmtiEnvUtil.initialize(envInt, (JvmtiEnvShared) sharedEnvironment); - - if (headEnvironment.isNull()) { - headEnvironment = envInt; - } else { - JvmtiEnvUtil.setNextEnvironment((JvmtiEnv) tailEnvironment, envInt); - } - tailEnvironment = envInt; - env.write(envExt); - - mutex.unlock(); - } - - public void destroyJvmtiEnv(JvmtiEnv env) { - mutex.lock(); - JvmtiEnv current = (JvmtiEnv) headEnvironment; - JvmtiEnv previous = WordFactory.nullPointer(); - while (current.notEqual(env)) { - previous = current; - current = current.getNextEnv(); - } - - if (headEnvironment.equal(tailEnvironment) && headEnvironment.equal(env)) { - // TODO @dprcci check whether this is correct? - destroy(); - } else if (previous.isNull()) { - headEnvironment = current.getNextEnv(); - } else { - previous.setNextEnv(current.getNextEnv()); - if (current.equal(tailEnvironment)) { - tailEnvironment = previous; - } - } - JvmtiEnvUtil.free(env); - mutex.unlock(); - } - - private void initialize() { - JvmtiEnvShared envShared = JvmtiEnvSharedUtil.allocate(); - JvmtiEnvSharedUtil.initialize(envShared); - sharedEnvironment = envShared; - initialized = true; - } - - public void destroy() { - if (!initialized) { - if (sharedEnvironment.isNonNull()) { - // TODO @dprcci illegalstateexception would make more sense? - try { - throw ImplicitExceptions.CACHED_ILLEGAL_ARGUMENT_EXCEPTION; - } finally { - if (mutex.isOwner()) { - mutex.unlock(); - } - } - // throw new RuntimeException("Global environment destruction can only occur once - // and has already been performed"); - } - // already destroyed - return; - } - JvmtiEnvSharedUtil.free(getSharedEnvironment()); - sharedEnvironment = WordFactory.nullPointer(); - headEnvironment = WordFactory.nullPointer(); - tailEnvironment = WordFactory.nullPointer(); - initialized = false; - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java deleted file mode 100644 index 43dfdfb0bb75..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvShared.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.word.PointerBase; - -/** - * Pointer to contiguously allocated capabilities which shared among environments. When (if) - * multiple environments are supported, each would have a vector pointing to this structure There - * are 7 different shared capabilities. Might be reworked into a pointer based @RawStruct - */ -@RawStructure -public interface JvmtiEnvShared extends PointerBase { - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java deleted file mode 100644 index 80cc8aeabd4a..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvSharedUtil.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_ACCESS_LOCAL_VARIABLES; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_FORCE_EARLY_RETURN; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_ALL_CLASS_HOOK_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_BREAKPOINT_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_EARLY_VMSTART; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_EXCEPTION_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_FIELD_ACCESS_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_FIELD_MODIFICATION_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_FRAME_POP_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_GARBAGE_COLLECTION_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_METHOD_ENTRY_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_METHOD_EXIT_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_MONITOR_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_OBJECT_FREE_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_SINGLE_STEP_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_BYTECODES; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_CONSTANT_POOL; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_CURRENT_CONTENDED_MONITOR; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_CURRENT_THREAD_CPU_TIME; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_LINE_NUMBERS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_MONITOR_INFO; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_OWNED_MONITOR_INFO; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_SOURCE_DEBUG_EXTENSION; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_SOURCE_FILE_NAME; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_SYNTHETIC_ATTRIBUTE; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_GET_THREAD_CPU_TIME; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_MAINTAIN_ORIGINAL_METHOD_ORDER; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_POP_FRAME; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_REDEFINE_ANY_CLASS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_REDEFINE_CLASSES; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_RETRANSFORM_ANY_CLASS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_RETRANSFORM_CLASSES; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SET_NATIVE_METHOD_PREFIX; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SIGNAL_THREAD; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SUPPORT_VIRTUAL_THREADS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_SUSPEND; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.CAN_TAG_OBJECTS; -import static com.oracle.svm.core.jvmti.JvmtiCapabilitiesEnum.getBit; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.Pointer; -import org.graalvm.word.PointerBase; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.config.ConfigurationValues; - -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.NumUtil; - -public class JvmtiEnvSharedUtil { - // TODO add magic? - /** - * Java enum used to identify shared capabilities among jvmti environments as well as their - * initial values based on hotspot's. Note: Initial values do not accurately depict the actual - * capabilities currently supported by native-image - */ - public enum SHARED_CAPABILITIES_TYPE { - ALWAYS(initAlways()), - ON_LOAD(initOnLoad()), - ALWAYS_SOLO(initAlwaysSolo()), - ON_LOAD_SOLO(initOnLoadSolo()), - ALWAYS_SOLO_REMAINING(initAlwaysSolo()), - ON_LOAD_SOLO_REMAINING(initOnLoadSolo()), - ACQUIRED(0L); - - private final long initial; - - SHARED_CAPABILITIES_TYPE(long initial) { - this.initial = initial; - } - - public long getInitial() { - return this.initial; - } - - private static long initAlways() { - long always = 0L; - always |= getBit(CAN_GET_BYTECODES); - always |= getBit(CAN_SIGNAL_THREAD); - always |= getBit(CAN_GET_SOURCE_FILE_NAME); - always |= getBit(CAN_GET_LINE_NUMBERS); - always |= getBit(CAN_GET_SYNTHETIC_ATTRIBUTE); - always |= getBit(CAN_GET_MONITOR_INFO); - always |= getBit(CAN_GET_CONSTANT_POOL); - always |= getBit(CAN_GENERATE_ALL_CLASS_HOOK_EVENTS); - always |= getBit(CAN_GENERATE_MONITOR_EVENTS); - always |= getBit(CAN_GENERATE_GARBAGE_COLLECTION_EVENTS); - always |= getBit(CAN_GENERATE_COMPILED_METHOD_LOAD_EVENTS); - always |= getBit(CAN_GENERATE_NATIVE_METHOD_BIND_EVENTS); - always |= getBit(CAN_GENERATE_VM_OBJECT_ALLOC_EVENTS); - always |= getBit(CAN_REDEFINE_CLASSES); - always |= getBit(CAN_REDEFINE_ANY_CLASS); - always |= getBit(CAN_RETRANSFORM_CLASSES); - always |= getBit(CAN_RETRANSFORM_ANY_CLASS); - always |= getBit(CAN_SET_NATIVE_METHOD_PREFIX); - always |= getBit(CAN_TAG_OBJECTS); - always |= getBit(CAN_GENERATE_OBJECT_FREE_EVENTS); - always |= getBit(CAN_GENERATE_RESOURCE_EXHAUSTION_HEAP_EVENTS); - always |= getBit(CAN_GENERATE_RESOURCE_EXHAUSTION_THREADS_EVENTS); - always |= getBit(CAN_SUPPORT_VIRTUAL_THREADS); - // return always; - // TODO add - /* - * if (os::is_thread_cpu_time_supported()) { jc.can_get_current_thread_cpu_time = 1; - * jc.can_get_thread_cpu_time = 1; } - */ - // TODO @dprcci enabled for tests - always |= getBit(CAN_GET_CURRENT_THREAD_CPU_TIME); - always |= getBit(CAN_GET_THREAD_CPU_TIME); - return always; - } - - private static long initOnLoad() { - long onLoad = 0L; - onLoad |= getBit(CAN_POP_FRAME); - onLoad |= getBit(CAN_FORCE_EARLY_RETURN); - onLoad |= getBit(CAN_GET_SOURCE_DEBUG_EXTENSION); - onLoad |= getBit(CAN_ACCESS_LOCAL_VARIABLES); - onLoad |= getBit(CAN_MAINTAIN_ORIGINAL_METHOD_ORDER); - onLoad |= getBit(CAN_GENERATE_SINGLE_STEP_EVENTS); - onLoad |= getBit(CAN_GENERATE_EXCEPTION_EVENTS); - onLoad |= getBit(CAN_GENERATE_FRAME_POP_EVENTS); - onLoad |= getBit(CAN_GENERATE_METHOD_ENTRY_EVENTS); - onLoad |= getBit(CAN_GENERATE_METHOD_EXIT_EVENTS); - onLoad |= getBit(CAN_GET_OWNED_MONITOR_INFO); - onLoad |= getBit(CAN_GET_OWNED_MONITOR_STACK_DEPTH_INFO); - onLoad |= getBit(CAN_GET_CURRENT_CONTENDED_MONITOR); - onLoad |= getBit(CAN_GENERATE_EARLY_VMSTART); - onLoad |= getBit(CAN_GENERATE_EARLY_CLASS_HOOK_EVENTS); - return onLoad; - } - - private static long initAlwaysSolo() { - long alwaysSolo = 0L; - alwaysSolo |= getBit(CAN_SUSPEND); - alwaysSolo |= getBit(CAN_GENERATE_SAMPLED_OBJECT_ALLOC_EVENTS); - return alwaysSolo; - } - - private static long initOnLoadSolo() { - long onLoadSolo = 0L; - onLoadSolo |= getBit(CAN_GENERATE_FIELD_MODIFICATION_EVENTS); - onLoadSolo |= getBit(CAN_GENERATE_FIELD_ACCESS_EVENTS); - onLoadSolo |= getBit(CAN_GENERATE_BREAKPOINT_EVENTS); - return onLoadSolo; - } - } - - @Platforms(Platform.HOSTED_ONLY.class) - private JvmtiEnvSharedUtil() { - } - - public static JvmtiEnvShared allocate() { - JvmtiEnvShared sharedCapabilities = ImageSingletons.lookup(UnmanagedMemorySupport.class).calloc(WordFactory.unsigned(sharedEnvironmentSize())); - if (sharedCapabilities.isNull()) { - return WordFactory.nullPointer(); - } - return sharedCapabilities; - } - - public static void free(JvmtiEnvShared sharedCapabilities) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(sharedCapabilities); - } - - public static void initialize(JvmtiEnvShared envShared) { - assert envShared.isNonNull(); - JvmtiCapabilitiesUtil.initSharedCapabilities(envShared); - } - - @Fold - static int sharedEnvironmentSize() { - return NumUtil.roundUp(sharedCapabilitiesOffset() + (SizeOf.get(com.oracle.svm.core.jvmti.headers.JvmtiCapabilities.class) * SHARED_CAPABILITIES_TYPE.values().length), - ConfigurationValues.getTarget().wordSize); - } - - @Fold - static int sharedCapabilitiesOffset() { - return NumUtil.roundUp(SizeOf.get(JvmtiEnvShared.class), ConfigurationValues.getTarget().wordSize); - } - - @Fold - static int capabilitiesSize() { - return SizeOf.get(com.oracle.svm.core.jvmti.headers.JvmtiCapabilities.class); - } - - public static com.oracle.svm.core.jvmti.headers.JvmtiCapabilities getSharedCapability(JvmtiEnvShared envShared, SHARED_CAPABILITIES_TYPE type) { - assert envShared.isNonNull(); - return addOffset(envShared, sharedCapabilitiesOffset() + (type.ordinal() * capabilitiesSize())); - } - - @SuppressWarnings("unchecked") - private static T addOffset(JvmtiEnvShared env, int offset) { - return (T) ((Pointer) env).add(offset); - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java deleted file mode 100644 index e63cdbe96db1..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvStorage.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.type.VoidPointer; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; -import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; -import com.oracle.svm.core.jvmti.utils.JvmtiLocalStorageUtil; - -import jdk.graal.compiler.api.replacements.Fold; - -public final class JvmtiEnvStorage extends JvmtiLocalStorageUtil { - - private static final int INITIAL_CAPACITY = 4; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiEnvStorage() { - super("Jvmti Environment Local Storage"); - } - - public static JvmtiError setEnvironmentStorage(JvmtiExternalEnv externalEnv, VoidPointer data) { - return singleton().setEnvironmentStorageInternal(externalEnv, data); - } - - public static JvmtiError getEnvironmentStorage(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { - return singleton().getEnvironmentStorageInternal(externalEnv, dataPtr); - } - - public void initialize() { - super.initialize(INITIAL_CAPACITY); - } - - @Fold - public static JvmtiEnvStorage singleton() { - return ImageSingletons.lookup(JvmtiEnvStorage.class); - } - - private JvmtiError setEnvironmentStorageInternal(JvmtiExternalEnv externalEnv, VoidPointer data) { - super.put(externalEnv, data); - return JvmtiError.JVMTI_ERROR_NONE; - } - - private JvmtiError getEnvironmentStorageInternal(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { - VoidPointer data = super.contains(externalEnv) ? super.get(externalEnv) : WordFactory.nullPointer(); - ((Pointer) dataPtr).writeWord(0, data); - return JvmtiError.JVMTI_ERROR_NONE; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java index 9f14362fd607..835c93cd17aa 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvUtil.java @@ -24,15 +24,14 @@ */ package com.oracle.svm.core.jvmti; -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.NumUtil; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NONE; +import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NOT_AVAILABLE; + import org.graalvm.nativeimage.CurrentIsolate; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Isolate; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.WordFactory; @@ -45,7 +44,13 @@ import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; import com.oracle.svm.core.jvmti.headers.JvmtiInterface; +import com.oracle.svm.core.memory.NullableNativeMemory; +import com.oracle.svm.core.nmt.NmtCategory; +import jdk.graal.compiler.api.replacements.Fold; +import jdk.graal.compiler.core.common.NumUtil; + +/** Methods related to {@link JvmtiEnv}. */ public final class JvmtiEnvUtil { private static final int VALID_ENV_MAGIC = 0x71EE; private static final int DISPOSED_ENV_MAGIC = 0xDEFC; @@ -54,53 +59,39 @@ public final class JvmtiEnvUtil { private JvmtiEnvUtil() { } - public static JvmtiExternalEnv allocate() { + static JvmtiEnv allocate() { JvmtiInterface functionTable = JvmtiFunctionTable.allocateFunctionTable(); if (functionTable.isNull()) { return WordFactory.nullPointer(); } - JvmtiEnv env = ImageSingletons.lookup(UnmanagedMemorySupport.class).calloc(WordFactory.unsigned(internalEnvSize())); + JvmtiEnv env = NullableNativeMemory.calloc(WordFactory.unsigned(internalEnvSize()), NmtCategory.JVMTI); if (env.isNull()) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(functionTable); + JvmtiFunctionTable.freeFunctionTable(functionTable); return WordFactory.nullPointer(); } env.setIsolate(CurrentIsolate.getIsolate()); env.setMagic(VALID_ENV_MAGIC); - JvmtiEnvEventEnabledUtils.initialize(getEnvEventEnabled(env)); - JvmtiExternalEnv externalEnv = toExternal(env); externalEnv.setFunctions(functionTable); - - return externalEnv; + return env; } - /* - * Note that HotSpot doesn't necessarily free the environment right away to prevent certain - * races. Depending on the functionality that we are going to add to our JVMTI implementation, - * we might need the same approach. - */ - public static void free(JvmtiEnv env) { - + static void dispose(JvmtiEnv env) { JvmtiCapabilities capabilities = getCapabilities(env); - relinquishCapabilities(env, capabilities); + relinquishCapabilities(capabilities); env.setMagic(DISPOSED_ENV_MAGIC); + } + + static void free(JvmtiEnv env) { JvmtiExternalEnv externalEnv = toExternal(env); JvmtiFunctionTable.freeFunctionTable(externalEnv.getFunctions()); externalEnv.setFunctions(WordFactory.nullPointer()); - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(env); - } - - public static void initialize(JvmtiEnv env, JvmtiEnvShared envShared) { - assert isValid(env); - assert envShared.isNonNull(); - - env.setEnvShared(envShared); - env.setNextEnv(WordFactory.nullPointer()); + NullableNativeMemory.free(env); } @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) @@ -120,99 +111,67 @@ public static boolean isValid(JvmtiEnv env) { return env.getMagic() == VALID_ENV_MAGIC; } + public static boolean isDead(JvmtiEnv env) { + return env.getMagic() == DISPOSED_ENV_MAGIC; + } + @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static Isolate getIsolate(JvmtiEnv env) { assert isValid(env); return env.getIsolate(); } - public static void setNextEnvironment(JvmtiEnv env, JvmtiEnv next) { - assert isValid(env); - assert isValid(next); - env.setNextEnv(next); - } - - public static JvmtiEnv getNextEnvironment(JvmtiEnv env) { - assert isValid(env); - return env.getNextEnv(); - } - - // ------------------ Capabilities API ------------------ // - // TODO @dprcci add to the jvmti api (jvmtifunctions) - public static JvmtiError getPotentialCapabilities(JvmtiEnv env, JvmtiCapabilities result) { - assert isValid(env); - return JvmtiCapabilitiesUtil.getPotentialCapabilities(env.getPhase(), getCapabilities(env), getProhibitedCapabilities(env), env.getEnvShared(), result); - } - public static JvmtiCapabilities getCapabilities(JvmtiEnv env) { assert isValid(env); return addOffset(env, capabilitiesOffset()); } - public static JvmtiError addCapabilities(JvmtiEnv env, JvmtiCapabilities capabilities) { + public static JvmtiError addCapabilities(JvmtiCapabilities capabilities) { assert capabilities.isNonNull(); - return JvmtiCapabilitiesUtil.addCapabilities(env.getPhase(), getEnvShared(env), getCapabilities(env), getProhibitedCapabilities(env), capabilities); - } - - public static JvmtiError relinquishCapabilities(JvmtiEnv env, JvmtiCapabilities unwanted) { - assert unwanted.isNonNull(); - return JvmtiCapabilitiesUtil.relinquishCapabilities(getEnvShared(env), getCapabilities(env), unwanted); - } - - // ------------------------------------------------------ // - - public static JvmtiCapabilities getProhibitedCapabilities(JvmtiEnv env) { - assert isValid(env); - return addOffset(env, prohibitedCapabilitiesOffset()); + /* We don't support any capabilities at the moment. */ + if (JvmtiCapabilitiesUtil.hasAny(capabilities)) { + return JVMTI_ERROR_NOT_AVAILABLE; + } + return JVMTI_ERROR_NONE; } - public static JvmtiEnvEventEnabled getEnvEventEnabled(JvmtiEnv env) { - assert isValid(env); - return addOffset(env, envEventEnabledOffset()); + public static JvmtiError relinquishCapabilities(JvmtiCapabilities capabilities) { + assert capabilities.isNonNull(); + /* Nothing to do because we don't support any capabilities at the moment. */ + return JVMTI_ERROR_NONE; } - public static JvmtiEventCallbacks getEventCallbacks(JvmtiEnv env) { + static JvmtiEventCallbacks getEventCallbacks(JvmtiEnv env) { assert isValid(env); return addOffset(env, eventCallbacksOffset()); } public static void setEventCallbacks(JvmtiEnv env, JvmtiEventCallbacks newCallbacks, int sizeOfCallbacks) { - - flushObjectFreeEvent(env); - JvmtiEventCallbacks eventCallbacks = getEventCallbacks(env); - JvmtiEventCallbacksUtil.setEventCallbacks(eventCallbacks, newCallbacks, sizeOfCallbacks); - JvmtiEnvEventEnabledUtils.setEventCallbacksEnabled(getEnvEventEnabled(env), eventCallbacks); - - JvmtiEnvEventEnabledUtils.recomputeEnabled(); + } + public static boolean hasEventCapability() { + /* At the moment, we only support events that don't need any specific capabilities. */ + return true; } - /* - * Compute truly enabled events - meaning if the event can and could be sent. - * - * An event is truly enabled if it is user enabled on the thread or globally user enabled, but - * only if there is a callback or event hook for it and, for field watch and frame pop, one has - * been set. Compute if truly enabled, per thread, per environment, per combination (thread x - * environment), and overall. These merges are true if any is true. True per thread if some - * environment has callback set and the event is globally enabled or enabled for this thread. - * True per environment if the callback is set and the event is globally enabled in this - * environment or enabled for any thread in this environment. True per combination if the - * environment has the callback set and the event is globally enabled in this environment or the - * event is enabled for this thread and environment. - * - * All states transitions dependent on these transitions are also handled here. - */ - - public static JvmtiEnvShared getEnvShared(JvmtiEnv env) { - assert isValid(env); - return env.getEnvShared(); + public static void setEventUserEnabled(JvmtiEnv env, Thread javaEventThread, JvmtiEvent eventType, boolean value) { + assert javaEventThread == null : "thread-local events are not supported at the moment"; + + long enabledBits = env.getEventUserEnabled(); + long bit = JvmtiEvent.getBit(eventType); + if (value) { + enabledBits |= bit; + } else { + enabledBits &= ~bit; + } + env.setEventUserEnabled(enabledBits); } - public static void setEnvShared(JvmtiEnv env, JvmtiEnvShared envShared) { - assert isValid(env); - env.setEnvShared(envShared); + public static boolean isEventEnabled(JvmtiEnv env, JvmtiEvent eventType) { + /* At the moment, this only checks if an event is user-enabled. */ + return (env.getEventUserEnabled() & JvmtiEvent.getBit(eventType)) != 0; } @SuppressWarnings("unchecked") @@ -220,36 +179,14 @@ private static T addOffset(JvmtiEnv env, int offset) { return (T) ((Pointer) env).add(offset); } - public static boolean hasCapability(JvmtiExternalEnv envExt, JvmtiCapabilitiesEnum cap){ - JvmtiEnv internal = toInternal(envExt); - assert isValid(internal); - return JvmtiCapabilitiesUtil.hasCapability(getCapabilities(internal), cap); - } - - // TODO @dprcci implement - public static boolean hasEventCapability(JvmtiEnv env, JvmtiEvent eventInfo) { - /* At the moment, we only support events that don't need any specific capabilities. */ - return true; - } - @Fold static int capabilitiesOffset() { return NumUtil.roundUp(SizeOf.get(JvmtiEnv.class), ConfigurationValues.getTarget().wordSize); } - @Fold - static int prohibitedCapabilitiesOffset() { - return NumUtil.roundUp(capabilitiesOffset() + SizeOf.get(JvmtiCapabilities.class), ConfigurationValues.getTarget().wordSize); - } - - @Fold - static int envEventEnabledOffset() { - return NumUtil.roundUp(prohibitedCapabilitiesOffset() + SizeOf.get(JvmtiCapabilities.class), ConfigurationValues.getTarget().wordSize); - } - @Fold static int eventCallbacksOffset() { - return NumUtil.roundUp(envEventEnabledOffset() + SizeOf.get(JvmtiEnvEventEnabled.class), ConfigurationValues.getTarget().wordSize); + return NumUtil.roundUp(capabilitiesOffset() + SizeOf.get(JvmtiCapabilities.class), ConfigurationValues.getTarget().wordSize); } @Fold @@ -261,30 +198,4 @@ static int externalEnvOffset() { static int internalEnvSize() { return externalEnvOffset() + SizeOf.get(JvmtiExternalEnv.class); } - - // TODO @dprcci complete - public static void setEventUserEnabled(JvmtiEnv env, Thread javaEventThread, JvmtiEvent eventType, boolean value) { - // TEMP (chaeubl): implement - /* - * if (thread == null && thread_oop_h() == nullptr) { // Null thread and null thread_oop now - * indicate setting globally instead of setting thread specific since null thread by itself - * means an unmounted virtual thread. env->env_event_enable()->set_user_enabled(event_type, - * enabled); } else { // create the thread state (if it didn't exist before) - * JvmtiThreadState *state = JvmtiThreadState::state_for_while_locked(thread, - * thread_oop_h()); if (state != nullptr) { - * state->env_thread_state(env)->event_enable()->set_user_enabled(event_type, enabled); } } - * recompute_enabled(); - */ - if (eventType == JvmtiEvent.JVMTI_EVENT_OBJECT_FREE) { - flushObjectFreeEvent(env); - } - - if (javaEventThread == null) { - JvmtiEnvEventEnabledUtils.setUserEventEnabled(getEnvEventEnabled(env), eventType, value); - } - } - - // TODO dprcci implement? Would need TagMap (or equivalent) first - private static void flushObjectFreeEvent(JvmtiEnv env) { - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvs.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvs.java new file mode 100644 index 000000000000..65678fb6d34e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEnvs.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; +import org.graalvm.word.WordFactory; + +import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; +import com.oracle.svm.core.locks.VMMutex; + +import jdk.graal.compiler.api.replacements.Fold; + +/** + * Stores information about all currently existing JVMTI environments and manages their lifecycle. + */ +public final class JvmtiEnvs { + private final VMMutex mutex = new VMMutex("jvmtiEnvManager"); + + private JvmtiEnv headEnv; + private JvmtiEnv tailEnv; + + private int threadsIteratingEnvs; + private boolean hasDisposedEnvs; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiEnvs() { + } + + @Fold + public static JvmtiEnvs singleton() { + return ImageSingletons.lookup(JvmtiEnvs.class); + } + + public JvmtiEnv getHead() { + return headEnv; + } + + public JvmtiExternalEnv create() { + JvmtiEnv env = JvmtiEnvUtil.allocate(); + if (env.isNull()) { + return WordFactory.nullPointer(); + } + + mutex.lock(); + try { + if (headEnv.isNull()) { + headEnv = env; + } else { + tailEnv.setNext(env); + } + tailEnv = env; + assert env.getNext().isNull(); + return JvmtiEnvUtil.toExternal(env); + } finally { + mutex.unlock(); + } + } + + public void dispose(JvmtiEnv env) { + mutex.lock(); + try { + JvmtiEnvUtil.dispose(env); + hasDisposedEnvs = true; + } finally { + mutex.unlock(); + } + } + + public void enterEnvIteration() { + mutex.lock(); + try { + threadsIteratingEnvs++; + } finally { + mutex.unlock(); + } + } + + public void leaveEnvIteration() { + mutex.lock(); + try { + int remainingThreads = threadsIteratingEnvs--; + assert remainingThreads >= 0; + if (remainingThreads == 0 && hasDisposedEnvs) { + cleanup(); + } + } finally { + mutex.unlock(); + } + } + + private void cleanup() { + assert mutex.isOwner(); + assert hasDisposedEnvs; + + JvmtiEnv cur = headEnv; + JvmtiEnv prev = WordFactory.nullPointer(); + while (cur.isNonNull()) { + if (JvmtiEnvUtil.isDead(cur)) { + remove(cur, prev); + JvmtiEnvUtil.free(cur); + } + + prev = cur; + cur = cur.getNext(); + } + + hasDisposedEnvs = false; + } + + private void remove(JvmtiEnv cur, JvmtiEnv prev) { + assert mutex.isOwner(); + if (prev.isNull()) { + headEnv = cur.getNext(); + } else { + prev.setNext(cur.getNext()); + } + + if (tailEnv == cur) { + tailEnv = prev; + } + cur.setNext(null); + } + + public void teardown() { + JvmtiEnv cur = headEnv; + while (cur.isNonNull()) { + JvmtiEnv next = cur.getNext(); + JvmtiEnvUtil.free(cur); + cur = next; + } + + headEnv = WordFactory.nullPointer(); + tailEnv = WordFactory.nullPointer(); + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java index 17b3c164d906..bfadc921eafc 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEventCallbacksUtil.java @@ -26,47 +26,22 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.SizeOf; import org.graalvm.word.Pointer; import org.graalvm.word.WordFactory; import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.jvmti.headers.JvmtiEvent; import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; +/** Methods related to {@link JvmtiEventCallbacks}. */ public final class JvmtiEventCallbacksUtil { - @Platforms(Platform.HOSTED_ONLY.class) private JvmtiEventCallbacksUtil() { } - public static long convertCallbacksToBitVector(JvmtiEventCallbacks callbacks) { - - long enabledCallbacks = 0L; - Pointer rawCFunPointer = (Pointer) callbacks; - - for (int i = 0; i < JvmtiEnvEventEnabledUtils.JVMTI_NB_EVENTS; i++) { - CFunctionPointer value = rawCFunPointer.readWord(0); - if (value.isNonNull()) { - enabledCallbacks |= 1L << i; - } - rawCFunPointer = rawCFunPointer.add(ConfigurationValues.getTarget().wordSize); - } - return enabledCallbacks; - } - - private static boolean hasCallback(JvmtiEventCallbacks callbacks, JvmtiEvent event) { - long callBacksBitVector = convertCallbacksToBitVector(callbacks); - long eventIndex = JvmtiEnvEventEnabledUtils.getBitForEvent(event); - return (callBacksBitVector & eventIndex) != 0; - } - public static void setEventCallbacks(JvmtiEventCallbacks envEventCallbacks, JvmtiEventCallbacks newCallbacks, int sizeOfCallbacks) { - int internalStructSize = SizeOf.get(JvmtiEventCallbacks.class); // Clear the whole struct - // (including gaps). + int internalStructSize = SizeOf.get(JvmtiEventCallbacks.class); UnmanagedMemoryUtil.fill((Pointer) envEventCallbacks, WordFactory.unsigned(internalStructSize), (byte) 0); if (newCallbacks.isNonNull()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEvents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEvents.java new file mode 100644 index 000000000000..d53718662365 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiEvents.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import com.oracle.svm.core.jni.JNIObjectHandles; +import com.oracle.svm.core.jni.JNIThreadLocalEnvironment; +import com.oracle.svm.core.jvmti.headers.JThread; +import com.oracle.svm.core.jvmti.headers.JvmtiEvent; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks.JvmtiEventVMDeathFunctionPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks.JvmtiEventVMInitFunctionPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks.JvmtiEventVMStartFunctionPointer; + +/** The methods in this class can be used to trigger JVMTI events. */ +public final class JvmtiEvents { + public static void postVMInit() { + JvmtiEnvs manager = JvmtiEnvs.singleton(); + manager.enterEnvIteration(); + try { + for (JvmtiEnv cur = manager.getHead(); cur.isNonNull(); cur = cur.getNext()) { + if (JvmtiEnvUtil.isEventEnabled(cur, JvmtiEvent.JVMTI_EVENT_VM_INIT)) { + JvmtiEventVMInitFunctionPointer callback = JvmtiEnvUtil.getEventCallbacks(cur).getVMInit(); + if (callback.isNonNull()) { + JThread currentThread = (JThread) JNIObjectHandles.createLocal(Thread.currentThread()); + try { + callback.invoke(JvmtiEnvUtil.toExternal(cur), JNIThreadLocalEnvironment.getAddress(), currentThread); + } finally { + JNIObjectHandles.deleteLocalRef(currentThread); + } + } + } + } + } finally { + manager.leaveEnvIteration(); + } + } + + public static void postVMStart() { + JvmtiEnvs manager = JvmtiEnvs.singleton(); + manager.enterEnvIteration(); + try { + for (JvmtiEnv cur = manager.getHead(); cur.isNonNull(); cur = cur.getNext()) { + if (JvmtiEnvUtil.isEventEnabled(cur, JvmtiEvent.JVMTI_EVENT_VM_START)) { + JvmtiEventVMStartFunctionPointer callback = JvmtiEnvUtil.getEventCallbacks(cur).getVMStart(); + if (callback.isNonNull()) { + callback.invoke(JvmtiEnvUtil.toExternal(cur), JNIThreadLocalEnvironment.getAddress()); + } + } + } + } finally { + manager.leaveEnvIteration(); + } + } + + public static void postVMDeath() { + JvmtiEnvs manager = JvmtiEnvs.singleton(); + manager.enterEnvIteration(); + try { + for (JvmtiEnv cur = manager.getHead(); cur.isNonNull(); cur = cur.getNext()) { + if (JvmtiEnvUtil.isEventEnabled(cur, JvmtiEvent.JVMTI_EVENT_VM_DEATH)) { + JvmtiEventVMDeathFunctionPointer callback = JvmtiEnvUtil.getEventCallbacks(cur).getVMDeath(); + if (callback.isNonNull()) { + callback.invoke(JvmtiEnvUtil.toExternal(cur), JNIThreadLocalEnvironment.getAddress()); + } + } + } + } finally { + manager.leaveEnvIteration(); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java index e9abe8dc2a62..90d57ccc53d2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctionTable.java @@ -24,13 +24,11 @@ */ package com.oracle.svm.core.jvmti; -import jdk.graal.compiler.api.replacements.Fold; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; import org.graalvm.word.Pointer; import org.graalvm.word.UnsignedWord; @@ -39,8 +37,16 @@ import com.oracle.svm.core.c.NonmovableArrays; import com.oracle.svm.core.config.ConfigurationValues; import com.oracle.svm.core.jvmti.headers.JvmtiInterface; +import com.oracle.svm.core.memory.NullableNativeMemory; +import com.oracle.svm.core.nmt.NmtCategory; + +import jdk.graal.compiler.api.replacements.Fold; public final class JvmtiFunctionTable { + /** + * A table with function pointers to all JVMTI entry points (see {@link JvmtiFunctions}). This + * table is filled at image-build-time. + */ private final CFunctionPointer[] readOnlyFunctionTable; @Platforms(Platform.HOSTED_ONLY.class) @@ -73,7 +79,7 @@ public CFunctionPointer[] getReadOnlyFunctionTable() { public static JvmtiInterface allocateFunctionTable() { UnsignedWord size = SizeOf.unsigned(JvmtiInterface.class); - JvmtiInterface result = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(size); + JvmtiInterface result = NullableNativeMemory.malloc(size, NmtCategory.JVMTI); if (result.isNonNull()) { NonmovableArray readOnlyData = NonmovableArrays.fromImageHeap(singleton().readOnlyFunctionTable); assert size.equal(NonmovableArrays.lengthOf(readOnlyData) * ConfigurationValues.getTarget().wordSize); @@ -83,6 +89,6 @@ public static JvmtiInterface allocateFunctionTable() { } public static void freeFunctionTable(JvmtiInterface table) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(table); + NullableNativeMemory.free(table); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java index cfc8ea89e8a1..a06baf29a457 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiFunctions.java @@ -27,21 +27,12 @@ import static com.oracle.svm.core.heap.RestrictHeapAccess.Access.NO_ALLOCATION; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_ACCESS_DENIED; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_ILLEGAL_ARGUMENT; -import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_INTERNAL; -import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_INVALID_ENVIRONMENT; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_INVALID_EVENT_TYPE; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_MUST_POSSESS_CAPABILITY; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NONE; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_NULL_POINTER; import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; -import static com.oracle.svm.core.jvmti.headers.JvmtiError.JVMTI_ERROR_UNATTACHED_THREAD; -import java.nio.charset.StandardCharsets; - -import com.oracle.svm.core.jvmti.headers.BooleanPointer; -import com.oracle.svm.core.jvmti.headers.JThreadGroupPointerPointer; -import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CEntryPoint; @@ -54,14 +45,12 @@ import org.graalvm.nativeimage.c.type.CFloatPointer; import org.graalvm.nativeimage.c.type.CIntPointer; import org.graalvm.nativeimage.c.type.CLongPointer; -import org.graalvm.nativeimage.c.type.CTypeConversion; import org.graalvm.nativeimage.c.type.VoidPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; +import org.graalvm.word.Pointer; import org.graalvm.word.PointerBase; import org.graalvm.word.UnsignedWord; import org.graalvm.word.WordFactory; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.c.function.CEntryPointActions; import com.oracle.svm.core.c.function.CEntryPointErrors; @@ -69,6 +58,7 @@ import com.oracle.svm.core.heap.GCCause; import com.oracle.svm.core.heap.Heap; import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.core.jdk.UninterruptibleUtils; import com.oracle.svm.core.jni.JNIObjectHandles; import com.oracle.svm.core.jni.headers.JNIFieldId; import com.oracle.svm.core.jni.headers.JNIFieldIdPointerPointer; @@ -78,6 +68,7 @@ import com.oracle.svm.core.jni.headers.JNINativeInterface; import com.oracle.svm.core.jni.headers.JNINativeInterfacePointer; import com.oracle.svm.core.jni.headers.JNIObjectHandle; +import com.oracle.svm.core.jvmti.headers.BooleanPointer; import com.oracle.svm.core.jvmti.headers.JClass; import com.oracle.svm.core.jvmti.headers.JClassPointer; import com.oracle.svm.core.jvmti.headers.JClassPointerPointer; @@ -99,7 +90,7 @@ import com.oracle.svm.core.jvmti.headers.JvmtiEventMode; import com.oracle.svm.core.jvmti.headers.JvmtiExtensionFunctionInfoPointer; import com.oracle.svm.core.jvmti.headers.JvmtiExternalEnv; -import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfoPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; import com.oracle.svm.core.jvmti.headers.JvmtiHeapCallbacks; import com.oracle.svm.core.jvmti.headers.JvmtiHeapObjectCallback; import com.oracle.svm.core.jvmti.headers.JvmtiHeapRootCallback; @@ -108,42 +99,35 @@ import com.oracle.svm.core.jvmti.headers.JvmtiMonitorStackDepthInfoPointer; import com.oracle.svm.core.jvmti.headers.JvmtiMonitorUsage; import com.oracle.svm.core.jvmti.headers.JvmtiObjectReferenceCallback; -import com.oracle.svm.core.jvmti.headers.JvmtiPhase; -import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointerPointer; +import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointer; import com.oracle.svm.core.jvmti.headers.JvmtiStackReferenceCallback; import com.oracle.svm.core.jvmti.headers.JvmtiStartFunctionPointer; import com.oracle.svm.core.jvmti.headers.JvmtiThreadGroupInfo; import com.oracle.svm.core.jvmti.headers.JvmtiThreadInfo; import com.oracle.svm.core.jvmti.headers.JvmtiTimerInfo; import com.oracle.svm.core.jvmti.headers.JvmtiVersion; +import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; +import com.oracle.svm.core.memory.NullableNativeMemory; +import com.oracle.svm.core.nmt.NmtCategory; /** - * Defines all JVMTI functions. This class may only contain methods that are annotated with + * Defines all JVMTI entry points. This class may only contain methods that are annotated with * {@link CEntryPoint}. - *

    - * JVMTI functions are annotated with {@link RestrictHeapAccess} because they must not execute any - * code that could trigger JVMTI events (could result in endless recursion). + * + * Each JVMTI function is annotated with {@link RestrictHeapAccess}, to ensure that it does not + * allocate any Java heap memory nor use Java synchronization. This is necessary because: *

      - *
    • they must not trigger (potentially recursive) JVMTI events
    • - *
    • they may be called from certain JVMTI event callbacks where we can't execute normal Java code - * (e.g., out of Java heap memory)
    • + *
    • JVMTI functions may be called from JVMTI event callbacks where we can't execute normal Java + * code (e.g., when the VM is out of Java heap memory)
    • + *
    • JVMTI functions must not execute any code that could trigger JVMTI events (this could result + * in endless recursion otherwise)
    • *
    + * + * Depending on the JVMTI events that we want to support, it may be necessary to mark most of the + * JVMTI infrastructure as {@link Uninterruptible} in the future to prevent that JVMTI events are + * triggered recursively. */ - -// TEMP (chaeubl): -// - Do we need to be uninterruptible? No, because some operations may cause a safepoint. -// - Can we allocate Java heap memory? No, because some operations are called from places where -// allocations are disallowed (e.g., JVMTI_EVENT_RESOURCE_EXHAUSTED). -// - Is Java synchronization allow? No. - -// TEMP (chaeubl): this still doesn't work... -// - JVMTI_EVENT_EXCEPTION and JVMTI_EVENT_EXCEPTION_CATCH - eventually, this code would have to be -// uninterruptible so that exceptions don't break uninterruptible code. But we can't trigger events -// from uninterruptible code... -> we would need to know if uninterruptible code is currently -// running and only trigger the JVMTI event in certain cases? Or we would need to exclude -// SVM-internal code? -// - JVMTI_EVENT_RESOURCE_EXHAUSTED: a lot of JVMTI/JNI code can be triggered, which is problematic -// because we must not allocate any Java heap memory. +@SuppressWarnings("unused") public final class JvmtiFunctions { @Platforms(Platform.HOSTED_ONLY.class) private JvmtiFunctions() { @@ -157,15 +141,15 @@ private JvmtiFunctions() { static int Allocate(JvmtiExternalEnv externalEnv, long size, CCharPointerPointer memPtr) { if (memPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); - } - if (size < 0) { + } else if (size < 0) { memPtr.write(WordFactory.nullPointer()); return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } + if (size == 0) { memPtr.write(WordFactory.nullPointer()); } else { - CCharPointer mem = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(size)); + CCharPointer mem = NullableNativeMemory.malloc(WordFactory.unsigned(size), NmtCategory.JVMTI); memPtr.write(mem); if (mem.isNull()) { return JVMTI_ERROR_OUT_OF_MEMORY.getCValue(); @@ -178,47 +162,45 @@ static int Allocate(JvmtiExternalEnv externalEnv, long size, CCharPointerPointer @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int Deallocate(JvmtiExternalEnv externalEnv, CCharPointer mem) { - if (mem.isNonNull()) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(mem); - } + NullableNativeMemory.free(mem); return JVMTI_ERROR_NONE.getCValue(); } - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadState(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer threadStatePtr) { if (threadStatePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiThreadStateUtil.getThreadState(thread, threadStatePtr); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetCurrentThread(JvmtiExternalEnv externalEnv, JThreadPointer threadPtr) { if (threadPtr.equal(WordFactory.nullPointer())) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiGetThreadsUtil.getCurrentThread(threadPtr); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetAllThreads(JvmtiExternalEnv externalEnv, CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { if (threadsCountPtr.isNull() || threadsPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiGetThreadsUtil.getAllThreads(threadsCountPtr, threadsPtr); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int SuspendThread(JvmtiExternalEnv externalEnv, JThreadPointer thread) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); + static int SuspendThread(JvmtiExternalEnv externalEnv, JThread thread) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -263,24 +245,21 @@ static int StopThread(JvmtiExternalEnv externalEnv, JThread thread, JNIObjectHan return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int InterruptThread(JvmtiExternalEnv externalEnv, JThread thread) { - if (!JvmtiEnvUtil.hasCapability(externalEnv, JvmtiCapabilitiesEnum.CAN_SIGNAL_THREAD)) { - return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); - } - return JvmtiThreadActionsUtil.interruptThread(thread); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadInfo(JvmtiExternalEnv externalEnv, JThread thread, JvmtiThreadInfo infoPtr) { if (infoPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiThreadActionsUtil.getThreadInfo(thread, infoPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -311,107 +290,98 @@ static int RunAgentThread(JvmtiExternalEnv externalEnv, JThread thread, JvmtiSta return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int SetThreadLocalStorage(JvmtiExternalEnv externalEnv, JThread thread, @CConst VoidPointer data) { - return JvmtiThreadLocalStorage.setThreadLocalStorage(thread, data).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadLocalStorage(JvmtiExternalEnv externalEnv, JThread thread, VoidPointerPointer dataPtr) { - if(dataPtr.isNull()){ + if (dataPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiThreadLocalStorage.getThreadLocalStorage(thread, dataPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetTopThreadGroups(JvmtiExternalEnv externalEnv, CIntPointer groupCountPtr, JThreadGroupPointerPointer groupsPtr) { - if(groupsPtr.isNull() || groupCountPtr.isNull()){ + static int GetTopThreadGroups(JvmtiExternalEnv externalEnv, CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { + if (groupsPtr.isNull() || groupCountPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiThreadGroupUtil.getTopThreadGroups(groupCountPtr, groupsPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadGroupInfo(JvmtiExternalEnv externalEnv, JThreadGroup group, JvmtiThreadGroupInfo infoPtr) { - if(infoPtr.isNull()){ + if (infoPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiThreadGroupUtil.getThreadGroupInfo(group, infoPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetThreadGroupChildren(JvmtiExternalEnv externalEnv, JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { - if (threadCountPtr.isNull() || threadsPtr.isNull() ||groupCountPtr.isNull() || groupsPtr.isNull()){ + if (threadCountPtr.isNull() || threadsPtr.isNull() || groupCountPtr.isNull() || groupsPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiThreadGroupUtil.getThreadGroupChildren(group, threadCountPtr, threadsPtr, groupCountPtr, groupsPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetStackTrace(JvmtiExternalEnv externalEnv, JThread thread, int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer, CIntPointer countPtr) { + static int GetStackTrace(JvmtiExternalEnv externalEnv, JThread thread, int startDepth, int maxFrameCount, JvmtiFrameInfo frameBuffer, CIntPointer countPtr) { if (maxFrameCount < 0) { - return JvmtiError.JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); - } - if (frameBuffer.isNull() || countPtr.isNull()) { + return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } else if (frameBuffer.isNull() || countPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - - if (JvmtiStackTraceUtil.startDepthIsOutOfBound(startDepth, SubstrateOptions.maxJavaStackTraceDepth())) { - return JvmtiError.JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); - } - return JvmtiStackTraceUtil.getStackTrace(thread, startDepth, maxFrameCount, frameBuffer, countPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetAllStackTraces(JvmtiExternalEnv externalEnv, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr, CIntPointer threadCountPtr) { + static int GetAllStackTraces(JvmtiExternalEnv externalEnv, int maxFrameCount, JvmtiStackInfoPointer stackInfoPtr, CIntPointer threadCountPtr) { if (stackInfoPtr.isNull() || threadCountPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); - } - if (maxFrameCount < 0) { + } else if (maxFrameCount < 0) { return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } - - return JvmtiMultiStackTracesUtil.getAllStackTraces(maxFrameCount, stackInfoPtr, threadCountPtr); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) - static int GetThreadListStackTraces(JvmtiExternalEnv externalEnv, int threadCount, @CConst JThreadPointer threadList, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr) { + static int GetThreadListStackTraces(JvmtiExternalEnv externalEnv, int threadCount, @CConst JThreadPointer threadList, int maxFrameCount, JvmtiStackInfoPointer stackInfoPtr) { if (stackInfoPtr.isNull() || threadList.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); - } - if (maxFrameCount < 0 || threadCount < 0) { + } else if (maxFrameCount < 0 || threadCount < 0) { return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } - - return JvmtiMultiStackTracesUtil.getListStackTraces(threadCount, threadList, maxFrameCount, stackInfoPtr); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFrameCount(JvmtiExternalEnv externalEnv, JThread thread, CIntPointer countPtr) { - if(countPtr.isNull()){ + if (countPtr.isNull()) { return JvmtiError.JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiStackTraceUtil.getFrameCount(thread, countPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -740,11 +710,11 @@ static int GetClassLoaderClasses(JvmtiExternalEnv externalEnv, JNIObjectHandle i return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassSignature(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return JvmtiClassInfoUtil.getClassSignature(klass, signaturePtr, genericPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -754,55 +724,54 @@ static int GetClassStatus(JvmtiExternalEnv externalEnv, JClass klass, CIntPointe return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetSourceFileName(JvmtiExternalEnv externalEnv, JClass klass, CCharPointerPointer sourceNamePtr) { - if(sourceNamePtr.isNull()){ + if (sourceNamePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getSourceFileName(klass, sourceNamePtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassModifiers(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer modifiersPtr) { - if(modifiersPtr.isNull()){ + if (modifiersPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getClassModifiers(klass, modifiersPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassMethods(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer methodCountPtr, JNIMethodIdPointerPointer methodsPtr) { - if(methodCountPtr.isNull() || methodsPtr.isNull()){ + if (methodCountPtr.isNull() || methodsPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getClassMethods(klass, methodCountPtr, methodsPtr).getCValue(); - + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetClassFields(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer fieldCountPtr, JNIFieldIdPointerPointer fieldsPtr) { - if(fieldCountPtr.isNull() || fieldsPtr.isNull()){ + if (fieldCountPtr.isNull() || fieldsPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getClassFields(klass, fieldCountPtr, fieldsPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetImplementedInterfaces(JvmtiExternalEnv externalEnv, JClass klass, CIntPointer interfaceCountPtr, JClassPointerPointer interfacesPtr) { - if(interfacesPtr.isNull() || interfaceCountPtr.isNull()){ + if (interfacesPtr.isNull() || interfaceCountPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getImplementedInterfaces(klass, interfaceCountPtr, interfacesPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -819,34 +788,34 @@ static int GetConstantPool(JvmtiExternalEnv externalEnv, JClass klass, CIntPoint return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsInterface(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isInterfacePtr) { - if(isInterfacePtr.isNull()){ + if (isInterfacePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.isInterface(klass, isInterfacePtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsArrayClass(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isArrayClassPtr) { - if(isArrayClassPtr.isNull()){ + if (isArrayClassPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.isArrayClass(klass, isArrayClassPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsModifiableClass(JvmtiExternalEnv externalEnv, JClass klass, BooleanPointer isModifiableClassPtr) { - if(isModifiableClassPtr.isNull()){ + if (isModifiableClassPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.isModifiableClass(klass, isModifiableClassPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -877,24 +846,24 @@ static int RedefineClasses(JvmtiExternalEnv externalEnv, int classCount, @CConst return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetObjectSize(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CLongPointer sizePtr) { if (sizePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiObjectInfoUttil.getObjectSize(object, sizePtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetObjectHashCode(JvmtiExternalEnv externalEnv, JNIObjectHandle object, CIntPointer hashCodePtr) { if (hashCodePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiObjectInfoUttil.getHashCode(object, hashCodePtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -904,71 +873,65 @@ static int GetObjectMonitorUsage(JvmtiExternalEnv externalEnv, JNIObjectHandle o return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFieldName(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return JvmtiClassInfoUtil.getFieldName(klass, field, namePtr, signaturePtr, genericPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFieldDeclaringClass(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, JClassPointer declaringClassPtr) { - if (declaringClassPtr.isNull()){ + if (declaringClassPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getFieldDeclaringClass(klass, field, declaringClassPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetFieldModifiers(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, CIntPointer modifiersPtr) { - if (modifiersPtr.isNull()){ + if (modifiersPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getFieldModifiers(klass, field, modifiersPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsFieldSynthetic(JvmtiExternalEnv externalEnv, JClass klass, JNIFieldId field, BooleanPointer isSyntheticPtr) { - if (isSyntheticPtr.isNull()){ - return JVMTI_ERROR_NULL_POINTER.getCValue(); - } - if(!JvmtiEnvUtil.hasCapability(externalEnv, JvmtiCapabilitiesEnum.CAN_GET_SYNTHETIC_ATTRIBUTE)){ - return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); - } - return JvmtiClassInfoUtil.isFieldSynthetic(klass, field, isSyntheticPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetMethodName(JvmtiExternalEnv externalEnv, JNIMethodId method, CCharPointerPointer namePtr, CCharPointerPointer signaturePtr, CCharPointerPointer genericPtr) { - return JvmtiClassInfoUtil.getMethodName(method, namePtr, signaturePtr, genericPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetMethodDeclaringClass(JvmtiExternalEnv externalEnv, JNIMethodId method, JClassPointer declaringClassPtr) { if (declaringClassPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getMethodDeclaringClass(method, declaringClassPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetMethodModifiers(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPointer modifiersPtr) { - if(modifiersPtr.isNull()){ + if (modifiersPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.getMethodModifiers(method, modifiersPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1013,27 +976,21 @@ static int GetBytecodes(JvmtiExternalEnv externalEnv, JNIMethodId method, CIntPo return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsMethodNative(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isNativePtr) { - if(isNativePtr.isNull()){ + if (isNativePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiClassInfoUtil.isMethodNative(method, isNativePtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int IsMethodSynthetic(JvmtiExternalEnv externalEnv, JNIMethodId method, BooleanPointer isSyntheticPtr) { - if(isSyntheticPtr.isNull()){ - return JVMTI_ERROR_NULL_POINTER.getCValue(); - } - if(!JvmtiEnvUtil.hasCapability(externalEnv, JvmtiCapabilitiesEnum.CAN_GET_SYNTHETIC_ATTRIBUTE)){ - return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); - } - return JvmtiClassInfoUtil.isMethodSynthetic(method, isSyntheticPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1057,53 +1014,53 @@ static int SetNativeMethodPrefixes(JvmtiExternalEnv externalEnv, int prefixCount return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int CreateRawMonitor(JvmtiExternalEnv externalEnv, @CConst CCharPointer name, JRawMonitorIdPointer monitorPtr) { - return JvmtiRawMonitorUtil.createRawMonitor(name, monitorPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int DestroyRawMonitor(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JvmtiRawMonitorUtil.destroyRawMonitor(monitor).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorEnter(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JvmtiRawMonitorUtil.rawMonitorEnter(monitor).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorExit(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JvmtiRawMonitorUtil.rawMonitorExit(monitor).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorWait(JvmtiExternalEnv externalEnv, JRawMonitorId monitor, long millis) { - return JvmtiRawMonitorUtil.rawMonitorWait(monitor, millis).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorNotify(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JvmtiRawMonitorUtil.rawMonitorNotify(monitor).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } - //@RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int RawMonitorNotifyAll(JvmtiExternalEnv externalEnv, JRawMonitorId monitor) { - return JvmtiRawMonitorUtil.rawMonitorNotifyAll(monitor).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1130,37 +1087,30 @@ static int SetEventCallbacks(JvmtiExternalEnv externalEnv, @CConst JvmtiEventCal JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); JvmtiEnvUtil.setEventCallbacks(env, callbacks, sizeOfCallbacks); - return JVMTI_ERROR_NONE.getCValue(); } - // TODO dprcci disabled temporarily - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + /** Note that this method uses varargs (the vararg part is reserved for future expansions). */ + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int SetEventNotificationMode(JvmtiExternalEnv externalEnv, int eventMode, JvmtiEvent eventType, JThread eventThread) { - // TEMP (chaeubl): this method uses varargs... do we need a native wrapper to deal with - // that? seems that this is only reserved for future expansion but may still be tricky. - - if (eventType == null || !JvmtiEnvEventEnabledUtils.isInValidEventRange(eventType)) { + if (eventType == null) { return JVMTI_ERROR_INVALID_EVENT_TYPE.getCValue(); - } else if (!eventType.isSupported()) { - return JVMTI_ERROR_ACCESS_DENIED.getCValue(); - } - - if (eventMode != JvmtiEventMode.JVMTI_ENABLE() && eventMode != JvmtiEventMode.JVMTI_DISABLE()) { + } else if (eventMode != JvmtiEventMode.JVMTI_ENABLE() && eventMode != JvmtiEventMode.JVMTI_DISABLE()) { return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); + } else if (!eventType.isSupported() && eventMode == JvmtiEventMode.JVMTI_ENABLE()) { + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } /* Check that the needed capabilities are present. */ boolean enable = (eventMode == JvmtiEventMode.JVMTI_ENABLE()); JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); - if (enable && !JvmtiEnvUtil.hasEventCapability(env, eventType)) { + if (enable && !JvmtiEnvUtil.hasEventCapability()) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY.getCValue(); } - Thread javaEventThread = JNIObjectHandles.getObject(eventThread); - if (javaEventThread == null) { + if (eventThread.equal(JNIObjectHandles.nullHandle())) { /* Change global event status. */ JvmtiEnvUtil.setEventUserEnabled(env, null, eventType, enable); } else { @@ -1169,6 +1119,7 @@ static int SetEventNotificationMode(JvmtiExternalEnv externalEnv, int eventMode, /* Global events cannot be controlled at thread level. */ return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } + /* At the moment, we don't support enabling events for specific threads. */ return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @@ -1213,12 +1164,8 @@ static int GetPotentialCapabilities(JvmtiExternalEnv externalEnv, JvmtiCapabilit return JVMTI_ERROR_NULL_POINTER.getCValue(); } - JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); - JvmtiEnvUtil.getPotentialCapabilities(env, result); - /* We don't support any capabilities at the moment. *//* - * JvmtiCapabilitiesUtil.clear(result) - * ; - */ + /* We don't support any capabilities at the moment. */ + JvmtiCapabilitiesUtil.clear(result); return JVMTI_ERROR_NONE.getCValue(); } @@ -1242,8 +1189,7 @@ static int AddCapabilities(JvmtiExternalEnv externalEnv, @CConst JvmtiCapabiliti if (capabilities.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); - return JvmtiEnvUtil.addCapabilities(env, capabilities).getCValue(); + return JvmtiEnvUtil.addCapabilities(capabilities).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1253,9 +1199,7 @@ static int RelinquishCapabilities(JvmtiExternalEnv externalEnv, @CConst JvmtiCap if (capabilities.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - - JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); - return JvmtiEnvUtil.relinquishCapabilities(env, capabilities).getCValue(); + return JvmtiEnvUtil.relinquishCapabilities(capabilities).getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1353,7 +1297,7 @@ static int GetPhase(JvmtiExternalEnv externalEnv, CIntPointer phasePtr) { if (phasePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - phasePtr.write(JvmtiPhase.JVMTI_PHASE_LIVE()); + phasePtr.write(JvmtiSupport.singleton().getPhase().getCValue()); return JVMTI_ERROR_NONE.getCValue(); } @@ -1362,8 +1306,7 @@ static int GetPhase(JvmtiExternalEnv externalEnv, CIntPointer phasePtr) { @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int DisposeEnvironment(JvmtiExternalEnv externalEnv) { JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); - JvmtiEnvManager manager = JvmtiEnvManager.singleton(); - manager.destroyJvmtiEnv(env); + JvmtiEnvs.singleton().dispose(env); return JVMTI_ERROR_NONE.getCValue(); } @@ -1371,23 +1314,17 @@ static int DisposeEnvironment(JvmtiExternalEnv externalEnv) { @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int SetEnvironmentLocalStorage(JvmtiExternalEnv externalEnv, @CConst VoidPointer data) { - if(JvmtiEnvUtil.isValid(JvmtiEnvUtil.toInternal(externalEnv))){ - return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); - } - return JvmtiEnvStorage.setEnvironmentStorage(externalEnv, data).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetEnvironmentLocalStorage(JvmtiExternalEnv externalEnv, VoidPointerPointer dataPtr) { - if(JvmtiEnvUtil.isValid(JvmtiEnvUtil.toInternal(externalEnv))){ - return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); - } - if(dataPtr.isNull()){ + if (dataPtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); } - return JvmtiEnvStorage.getEnvironmentStorage(externalEnv, dataPtr).getCValue(); + return JVMTI_ERROR_ACCESS_DENIED.getCValue(); } @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @@ -1401,29 +1338,28 @@ static int GetVersionNumber(JvmtiExternalEnv externalEnv, CIntPointer versionPtr return JVMTI_ERROR_NONE.getCValue(); } - // TODO dprcci disabled temporarily - // @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") + @RestrictHeapAccess(access = NO_ALLOCATION, reason = "JVMTI function.") @CEntryPoint(include = CEntryPoint.NotIncludedAutomatically.class, publishAs = CEntryPoint.Publish.NotPublished) @CEntryPointOptions(prologue = JvmtiEnvEnterPrologue.class) static int GetErrorName(JvmtiExternalEnv externalEnv, JvmtiError jvmtiError, CCharPointerPointer namePtr) { if (namePtr.isNull()) { return JVMTI_ERROR_NULL_POINTER.getCValue(); - } - - if (jvmtiError == null) { + } else if (jvmtiError == null) { + namePtr.write(WordFactory.nullPointer()); return JVMTI_ERROR_ILLEGAL_ARGUMENT.getCValue(); } - /* Convert name to ASCII. */ String name = jvmtiError.name(); UnsignedWord bufferSize = WordFactory.unsigned(name.length() + 1); - CCharPointer mem = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); - namePtr.write(mem); + Pointer mem = NullableNativeMemory.malloc(bufferSize, NmtCategory.JVMTI); + namePtr.write((CCharPointer) mem); if (mem.isNull()) { return JVMTI_ERROR_OUT_OF_MEMORY.getCValue(); } - CTypeConversion.toCString(name, StandardCharsets.US_ASCII, mem, bufferSize); + /* Errors are ASCII only. */ + assert bufferSize.equal(UninterruptibleUtils.String.modifiedUTF8Length(name, true)); + UninterruptibleUtils.String.toModifiedUTF8(name, mem, mem.add(bufferSize), true); return JVMTI_ERROR_NONE.getCValue(); } @@ -1451,28 +1387,29 @@ static int SetHeapSamplingInterval(JvmtiExternalEnv externalEnv, int samplingInt // Checkstyle: resume private static class JvmtiEnvEnterPrologue implements CEntryPointOptions.Prologue { + /** + * In the prologue, we need to be careful that we don't access any image heap data before + * the heap base is set up, so we use @CConstant instead of @CEnum. + */ @Uninterruptible(reason = "prologue") public static int enter(JvmtiExternalEnv externalEnv) { - // TEMP (chaeubl): we might need special logic again to avoid objects in the - // reference map before the heap base is set. Or, we make sure that the values are - // constant folded (via @Fold). if (externalEnv.isNull()) { - return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); + return JvmtiError.invalidEnvironment(); } JvmtiEnv env = JvmtiEnvUtil.toInternal(externalEnv); if (!JvmtiEnvUtil.isValid(env)) { - return JVMTI_ERROR_INVALID_ENVIRONMENT.getCValue(); + return JvmtiError.invalidEnvironment(); } int error = CEntryPointActions.enterByIsolate(JvmtiEnvUtil.getIsolate(env)); if (error == CEntryPointErrors.UNATTACHED_THREAD) { - return JVMTI_ERROR_UNATTACHED_THREAD.getCValue(); + return JvmtiError.unattachedThread(); } else if (error != CEntryPointErrors.NO_ERROR) { - return JVMTI_ERROR_INTERNAL.getCValue(); + return JvmtiError.internal(); } - return JVMTI_ERROR_NONE.getCValue(); + return JvmtiError.none(); } } @@ -1483,5 +1420,4 @@ private interface CCharPointerPointerPointer extends PointerBase { @CPointerTo(CLongPointer.class) private interface CLongPointerPointer extends PointerBase { } - } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java deleted file mode 100644 index 83df17b74f2d..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGenericInfoMapFeature.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; - -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.core.feature.InternalFeature; - -//TODO @dprcci not automatically register -@AutomaticallyRegisteredFeature -public final class JvmtiGenericInfoMapFeature implements InternalFeature { - - @Override - public void afterRegistration(AfterRegistrationAccess access) { - ImageSingletons.add(JvmtiClassInfoUtil.JVMTIGenericInfoMap.class, new JvmtiClassInfoUtil.JVMTIGenericInfoMap()); - } - - @Override - public void afterAnalysis(AfterAnalysisAccess access) { - JvmtiClassInfoUtil.JVMTIGenericInfoMap.singleton().discardUnused(); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java deleted file mode 100644 index e01ca2b12932..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiGetThreadsUtil.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.StackValue; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.heap.VMOperationInfos; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JThreadPointer; -import com.oracle.svm.core.jvmti.headers.JThreadPointerPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.utils.JvmtiUtils; -import com.oracle.svm.core.thread.JavaThreads; -import com.oracle.svm.core.thread.NativeVMOperation; -import com.oracle.svm.core.thread.NativeVMOperationData; -import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.VMThreads; - -public final class JvmtiGetThreadsUtil { - - private final JvmtiGetThreadsOperation operation; - private static final int INITIAL_THREAD_BUFFER_CAPACITY = 16; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiGetThreadsUtil() { - this.operation = new JvmtiGetThreadsOperation(); - } - - public static int getAllThreads(CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { - return ImageSingletons.lookup(JvmtiGetThreadsUtil.class).getAllThreadsInternal(threadsCountPtr, threadsPtr); - } - - public static int getCurrentThread(JThreadPointer threadPtr) { - return ImageSingletons.lookup(JvmtiGetThreadsUtil.class).getCurrentThreadsInternal(threadPtr); - } - - @Uninterruptible(reason = "jvmti GetCurrentThread") - private int getCurrentThreadsInternal(JThreadPointer threadPtr) { - Thread currentThread = Thread.currentThread(); - JThread jthread = (JThread) JNIObjectHandles.createLocal(currentThread); - ((Pointer) threadPtr).writeWord(0, jthread); - return JvmtiError.JVMTI_ERROR_NONE.getCValue(); - } - - private int getAllThreadsInternal(CIntPointer threadsCountPtr, JThreadPointerPointer threadsPtr) { - int size = SizeOf.get(JvmtiGetAllThreadsVMOperationData.class); - JvmtiGetAllThreadsVMOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - data.setCIntPointer(threadsCountPtr); - data.setJThreadPointerPointer(threadsPtr.rawValue()); - - operation.enqueue(data); - return data.getJvmtiError(); - } - - // TODO @dprcci Is it better to allocate a bound max memory array in advance and realloc? - - @RawStructure - private interface JvmtiGetAllThreadsVMOperationData extends NativeVMOperationData { - @RawField - void setJThreadPointerPointer(long ptr); - - @RawField - long getJThreadPointerPointer(); - - @RawField - int getJvmtiError(); - - @RawField - void setJvmtiError(int error); - - @RawField - void setCIntPointer(CIntPointer ptr); - - @RawField - CIntPointer getCIntPointer(); - } - - private static class JvmtiGetThreadsOperation extends NativeVMOperation { - JvmtiGetThreadsOperation() { - super(VMOperationInfos.get(JvmtiGetThreadsUtil.JvmtiGetThreadsOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - protected void operate(NativeVMOperationData data) { - getAllThreads((JvmtiGetAllThreadsVMOperationData) data); - } - } - - @Uninterruptible(reason = "jvmti GetAllThreads") - static int getNumberOfThreads() { - int nbOfThreads = 0; - for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { - Thread thread = PlatformThreads.fromVMThread(isolateThread); - // for consistency and clarity - if (thread == null || thread.isVirtual() || !JavaThreads.isAlive(thread)) { - continue; - } - nbOfThreads++; - } - return nbOfThreads; - } - - @Uninterruptible(reason = "jvmti GetAllThreads") - private static void getAllThreads(JvmtiGetAllThreadsVMOperationData data) { - JThreadPointer arrayPtr = JvmtiUtils.allocateWordBuffer(INITIAL_THREAD_BUFFER_CAPACITY); - int currentArraySize = INITIAL_THREAD_BUFFER_CAPACITY; - int nbWritten = 0; - for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { - Thread thread = PlatformThreads.fromVMThread(isolateThread); - // "Get all live platform threads that are attached to the VM" - if (thread == null || thread.isVirtual() || !JavaThreads.isAlive(thread)) { - continue; - } - if (nbWritten == currentArraySize) { - arrayPtr = JvmtiUtils.growWordBuffer(arrayPtr, INITIAL_THREAD_BUFFER_CAPACITY); - currentArraySize += INITIAL_THREAD_BUFFER_CAPACITY; - } - JNIObjectHandle threadHandle = JNIObjectHandles.createLocal(thread); - JvmtiUtils.writeWordAtIdxInBuffer(arrayPtr, nbWritten, threadHandle); - nbWritten++; - } - - JThreadPointerPointer threadsPtr = WordFactory.unsigned(data.getJThreadPointerPointer()); - CIntPointer threadsCountPtr = data.getCIntPointer(); - - ((Pointer) threadsPtr).writeWord(0, arrayPtr); - threadsCountPtr.write(nbWritten); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java deleted file mode 100644 index 02880410ccef..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiManager.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; - -public final class JvmtiManager { - // TODO @dprcci refactor - public static void registerAllJvmtiClasses() { - ImageSingletons.add(JvmtiAgents.class, new JvmtiAgents()); - ImageSingletons.add(JvmtiEnvManager.class, new JvmtiEnvManager()); - ImageSingletons.add(JvmtiStackTraceUtil.class, new JvmtiStackTraceUtil()); - ImageSingletons.add(JvmtiClassInfoUtil.class, new JvmtiClassInfoUtil()); - ImageSingletons.add(JvmtiGetThreadsUtil.class, new JvmtiGetThreadsUtil()); - ImageSingletons.add(JvmtiMultiStackTracesUtil.class, new JvmtiMultiStackTracesUtil()); - ImageSingletons.add(JvmtiThreadStateUtil.class, new JvmtiThreadStateUtil()); - ImageSingletons.add(JvmtiRawMonitorUtil.class, new JvmtiRawMonitorUtil()); - ImageSingletons.add(JvmtiFunctionTable.class, new JvmtiFunctionTable()); - ImageSingletons.add(JvmtiEnvStorage.class, new JvmtiEnvStorage()); - ImageSingletons.add(JvmtiThreadLocalStorage.class, new JvmtiThreadLocalStorage()); - ImageSingletons.add(JvmtiThreadGroupUtil.class, new JvmtiThreadGroupUtil()); - } - - public static void freeAllJvmtiClassesUnmanagedMemory() { - ; - ImageSingletons.lookup(JvmtiRawMonitorUtil.class).releaseAllUnmanagedMemory(); - ImageSingletons.lookup(JvmtiEnvStorage.class).releaseAllUnmanagedMemory(); - ImageSingletons.lookup(JvmtiThreadLocalStorage.class).releaseAllUnmanagedMemory(); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java deleted file mode 100644 index ca8e747d3339..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMemoryManager.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -public interface JvmtiMemoryManager { - default void releaseAllUnmanagedMemory() { - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java deleted file mode 100644 index 51301bee4b5e..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiMultiStackTracesUtil.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import static com.oracle.svm.core.jvmti.JvmtiThreadStateUtil.getThreadState; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.StackValue; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CConst; -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.heap.VMOperationInfos; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JThreadPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; -import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfoPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiStackInfo; -import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiStackInfoPointerPointer; -import com.oracle.svm.core.thread.NativeVMOperation; -import com.oracle.svm.core.thread.NativeVMOperationData; -import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.VMThreads; - -import jdk.graal.compiler.api.replacements.Fold; -import jdk.graal.compiler.core.common.NumUtil; - -//TODO @dprcci Group all those thread related classed at some point (or create sub package ?) -public final class JvmtiMultiStackTracesUtil { - private final JvmtiGetAllStackTracesOperation allStackTracesOperation; - private final JvmtiGetListStackTracesOperation listStackTracesOperation; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiMultiStackTracesUtil() { - this.allStackTracesOperation = new JvmtiGetAllStackTracesOperation(); - this.listStackTracesOperation = new JvmtiGetListStackTracesOperation(); - } - - public static int getAllStackTraces(int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr, CIntPointer threadCountPtr) { - return ImageSingletons.lookup(JvmtiMultiStackTracesUtil.class).getAllStackTracesInternal(maxFrameCount, stackInfoPtr, threadCountPtr); - } - - public static int getListStackTraces(int threadCount, @CConst JThreadPointer threadListHead, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr) { - return ImageSingletons.lookup(JvmtiMultiStackTracesUtil.class).getListStackTracesInternal(threadCount, threadListHead, maxFrameCount, stackInfoPtr); - } - - // TODO @dprcci The problem with reusing the existing code is that a thread list (java) cannot - // be used as no memory can be allocated. - // Using a stack array is not an option as the size must be a compile time constant. The only - // option would be to allocated UnamangedMemory? - private int getListStackTracesInternal(int threadCount, @CConst JThreadPointer threadListHead, int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr) { - - int size = SizeOf.get(JvmtiGetListStackTracesVMOperationData.class); - JvmtiGetListStackTracesVMOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - data.setStackInfoPointerPointer(stackInfoPtr); - data.setMaxFrameCount(maxFrameCount); - data.setNbThreads(threadCount); - data.setThreadListHead(threadListHead); - - listStackTracesOperation.enqueue(data); - return data.getJvmtiError(); - } - - @RawStructure - private interface JvmtiGetListStackTracesVMOperationData extends NativeVMOperationData { - @RawField - void setStackInfoPointerPointer(JvmtiStackInfoPointerPointer ptr); - - @RawField - JvmtiStackInfoPointerPointer getStackInfoPointerPointer(); - - @RawField - int getJvmtiError(); - - @RawField - void setJvmtiError(int error); - - @RawField - void setNbThreads(int nbThreads); - - @RawField - int getNbThreads(); - - @RawField - void setThreadListHead(JThreadPointer head); - - @RawField - JThreadPointer getThreadListHead(); - - @RawField - void setMaxFrameCount(int maxFrameCount); - - @RawField - int getMaxFrameCount(); - } - - // TODO @dprcci cannot allocate memory - private static class JvmtiGetListStackTracesOperation extends NativeVMOperation { - JvmtiGetListStackTracesOperation() { - super(VMOperationInfos.get(JvmtiGetListStackTracesOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - protected void operate(NativeVMOperationData data) { - getListStackTraces((JvmtiGetListStackTracesVMOperationData) data); - } - } - - private static void getListStackTraces(JvmtiGetListStackTracesVMOperationData data) { - int maxFrameCount = data.getMaxFrameCount(); - int nbThreads = data.getNbThreads(); - JThreadPointer threadListHead = data.getThreadListHead(); - - JvmtiStackInfoPointer stackInfoBuffer = allocateStackInfoBuffer(nbThreads, maxFrameCount); - if (stackInfoBuffer.isNull()) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); - return; - } - - int nbWritten = fillStackInfoBuffer(nbThreads, threadListHead, maxFrameCount, stackInfoBuffer); - if (nbWritten != nbThreads) { - cleanup(stackInfoBuffer); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue()); - return; - } - - ((Pointer) data.getStackInfoPointerPointer()).writeWord(0, stackInfoBuffer); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - } - - private static int fillStackInfoBuffer(int nbThreads, JThreadPointer threadListHead, int maxFrameCount, JvmtiStackInfoPointer stackInfoBuffer) { - int nbWritten = 0; - for (int i = 0; i < nbThreads; i++) { - JThread currentJThread = readThreadAtIdx(threadListHead, i); - Thread currentThread; - - Pointer threadPtr = StackValue.get(ConfigurationValues.getTarget().wordSize); - if (getThreadFromHandle(currentJThread, threadPtr) != 0) { - break; - } - currentThread = (Thread) threadPtr.readObject(0); - JvmtiStackInfo currentStackInfo = readStackInfoAt(stackInfoBuffer, i, maxFrameCount); - fillStackInfo(currentStackInfo, currentThread, maxFrameCount); - nbWritten++; - } - return nbWritten; - } - - private static JThread readThreadAtIdx(JThreadPointer head, int index) { - return ((Pointer) head).readWord(index * ConfigurationValues.getTarget().wordSize); - } - - private int getAllStackTracesInternal(int maxFrameCount, JvmtiStackInfoPointerPointer stackInfoPtr, CIntPointer threadCountPtr) { - int size = SizeOf.get(JvmtiGetAllStackTracesVMOperationData.class); - JvmtiGetAllStackTracesVMOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - data.setStackInfoPointerPointer(stackInfoPtr); - data.setMaxFrameCount(maxFrameCount); - data.setCIntPointer(threadCountPtr); - - allStackTracesOperation.enqueue(data); - return data.getJvmtiError(); - } - - @RawStructure - private interface JvmtiGetAllStackTracesVMOperationData extends NativeVMOperationData { - @RawField - void setStackInfoPointerPointer(JvmtiStackInfoPointerPointer ptr); - - @RawField - JvmtiStackInfoPointerPointer getStackInfoPointerPointer(); - - @RawField - int getJvmtiError(); - - @RawField - void setJvmtiError(int error); - - @RawField - void setCIntPointer(CIntPointer ptr); - - @RawField - CIntPointer getCIntPointer(); - - @RawField - void setMaxFrameCount(int maxFrameCount); - - @RawField - int getMaxFrameCount(); - } - - // TODO @dprcci cannot allocate memory - private static class JvmtiGetAllStackTracesOperation extends NativeVMOperation { - JvmtiGetAllStackTracesOperation() { - super(VMOperationInfos.get(JvmtiGetAllStackTracesOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - // @RestrictHeapAccess(reason = "jvmti", access = RestrictHeapAccess.Access.NO_ALLOCATION) - protected void operate(NativeVMOperationData data) { - getAllStackTraces((JvmtiGetAllStackTracesVMOperationData) data); - } - } - - private static void getAllStackTraces(JvmtiGetAllStackTracesVMOperationData data) { - - int maxFrameCount = data.getMaxFrameCount(); - int nbThreads = JvmtiGetThreadsUtil.getNumberOfThreads(); - - JvmtiStackInfoPointer stackInfoBuffer = allocateStackInfoBuffer(nbThreads, maxFrameCount); - if (stackInfoBuffer.isNull()) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); - return; - } - - int nbStackInfo = fillStackInfoBuffer(stackInfoBuffer, nbThreads, maxFrameCount); - if (nbStackInfo != nbThreads) { - // TODO @dprcci if error means more threads are being written to than expected. Only - // "nbThreads" have been allocated - cleanup(stackInfoBuffer); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); - return; - } - - ((Pointer) data.getStackInfoPointerPointer()).writeWord(0, stackInfoBuffer); - ((Pointer) data.getCIntPointer()).writeInt(0, nbStackInfo); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - } - - private static int fillStackInfoBuffer(JvmtiStackInfoPointer stackInfoBuffer, int nbThreads, int maxFrameCount) { - int nbWritten = 0; - for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { - Thread thread = PlatformThreads.fromVMThread(isolateThread); - // "Get all live platform threads that are attached to the VM" - if (thread == null || thread.isVirtual()) { - continue; - } - if (nbWritten >= nbThreads) { - return -1; - } - JvmtiStackInfo currentStackInfo = readStackInfoAt(stackInfoBuffer, nbWritten, maxFrameCount); - fillStackInfo(currentStackInfo, thread, maxFrameCount); - nbWritten++; - } - return nbWritten; - } - - private static void fillStackInfo(JvmtiStackInfo stackInfo, Thread thread, int maxFrameCount) { - JThread jthread = (JThread) JNIObjectHandles.createLocal(thread); - stackInfo.setThread(jthread); - - CIntPointer nbFramesPr = StackValue.get(CIntPointer.class); - JvmtiStackTraceUtil.getStackTrace(jthread, 0, maxFrameCount, stackInfo.getFrameInfo(), nbFramesPr); - stackInfo.setFrameCount(nbFramesPr.read()); - - int threadState = getThreadState(thread); - stackInfo.setState(threadState); - } - - private static JvmtiStackInfoPointer allocateStackInfoBuffer(int bufferSize, int maxFrameCount) { - int totalBufferSize = bufferSize * stackInfoOffsetWithFrameInfoBuffer(maxFrameCount); - JvmtiStackInfoPointer allocatedBufferPtr = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(totalBufferSize)); - if (allocatedBufferPtr.isNull()) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(allocatedBufferPtr); - return WordFactory.nullPointer(); - } - for (int i = 0; i < bufferSize; i++) { - JvmtiStackInfo currentStackInfo = readStackInfoAt(allocatedBufferPtr, i, maxFrameCount); - JvmtiFrameInfoPointer currentFrame = readFrameInfoAt(allocatedBufferPtr, i, maxFrameCount); - currentStackInfo.setFrameInfo(currentFrame); - } - return allocatedBufferPtr; - } - - // free up to (including) the failed allocated FrameInfo - private static void cleanup(JvmtiStackInfoPointer stackInfoBuffer) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(stackInfoBuffer); - } - - private static JvmtiFrameInfoPointer readFrameInfoAt(JvmtiStackInfoPointer arrayPtr, int index, int maxFrameCount) { - return (JvmtiFrameInfoPointer) ((Pointer) arrayPtr).add(index * stackInfoOffsetWithFrameInfoBuffer(maxFrameCount) + stackInfoOffset()); - } - - private static JvmtiStackInfo readStackInfoAt(JvmtiStackInfoPointer arrayPtr, int index, int maxFrameCount) { - return (JvmtiStackInfo) ((Pointer) arrayPtr).add(index * stackInfoOffsetWithFrameInfoBuffer(maxFrameCount)); - } - - @Fold - static int stackInfoOffset() { - return NumUtil.roundUp(SizeOf.get(JvmtiStackInfo.class), ConfigurationValues.getTarget().wordSize); - } - - static int stackInfoOffsetWithFrameInfoBuffer(int maxFrameInfo) { - return NumUtil.roundUp(stackInfoOffset() + (SizeOf.get(JvmtiFrameInfo.class) * maxFrameInfo), ConfigurationValues.getTarget().wordSize); - } - - private static int getThreadFromHandle(JThread handle, Pointer result) { - Thread thread; - try { - Object threadReference = JNIObjectHandles.getObject(handle); - thread = (Thread) threadReference; - } catch (IllegalArgumentException | ClassCastException e) { - return -1; - } - result.writeObject(0, thread); - return 0; - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java deleted file mode 100644 index 11992aa17ab3..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiObjectInfoUttil.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.nativeimage.c.type.CLongPointer; - -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.hub.LayoutEncoding; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.snippets.KnownIntrinsics; - -import jdk.graal.compiler.nodes.java.ArrayLengthNode; - -public final class JvmtiObjectInfoUttil { - - private JvmtiObjectInfoUttil() { - } - - public static JvmtiError getObjectSize(JNIObjectHandle jobject, CLongPointer sizePtr) { - Object object; - try { - object = JNIObjectHandles.getObject(jobject); - } catch (IllegalArgumentException e) { - return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; - } - if (object == null) { - return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; - } - - long size = 0; - int layoutEncoding = KnownIntrinsics.readHub(object).getLayoutEncoding(); - if (LayoutEncoding.isArray(layoutEncoding)) { - int elementSize; - if (LayoutEncoding.isPrimitiveArray(layoutEncoding)) { - elementSize = LayoutEncoding.getArrayIndexScale(layoutEncoding); - } else { - elementSize = ConfigurationValues.getTarget().wordSize; - } - int length = ArrayLengthNode.arrayLength(object); - size = (long) length * elementSize; - } else { - DynamicHub hub = DynamicHub.fromClass(object.getClass()); - int encoding = hub.getLayoutEncoding(); - if (LayoutEncoding.isPureInstance(encoding)) { - /* - * May underestimate the object size if the identity hashcode field is optional. - * This is the best that what can do because the HPROF format does not support that - * instances of one class have different object sizes. - */ - size = (int) LayoutEncoding.getPureInstanceAllocationSize(encoding).rawValue(); - } else if (LayoutEncoding.isHybrid(encoding)) { - /* For hybrid objects, return the size of the fields. */ - size = LayoutEncoding.getArrayBaseOffsetAsInt(encoding); - } - } - sizePtr.write(size); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getHashCode(JNIObjectHandle jobject, CIntPointer hashCodePtr) { - Object object; - try { - object = JNIObjectHandles.getObject(jobject); - } catch (IllegalArgumentException e) { - return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; - } - if (object == null) { - return JvmtiError.JVMTI_ERROR_INVALID_OBJECT; - } - hashCodePtr.write(object.hashCode()); - return JvmtiError.JVMTI_ERROR_NONE; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java deleted file mode 100644 index 64ca679875eb..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiPostEvents.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.JNIThreadLocalEnvironment; -import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JvmtiEvent; -import com.oracle.svm.core.jvmti.headers.JvmtiEventCallbacks; -import com.oracle.svm.core.jvmti.headers.JvmtiPhase; -import com.oracle.svm.core.log.Log; - -public final class JvmtiPostEvents { - - private static final int EVENT_NOT_FOUND = -1; - private static final int NO_CALLBACK_SET = -2; - private static final int ARGUMENT_ERROR = -3; - - public static void postVMInit() { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_VM_INIT); - } - - public static void postVMStart() { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_VM_START); - } - - public static void postVMDeath() { - // TODO @dprcci create and add call to JvmtiTagMap::flush_all_object_free_events(); - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_VM_DEATH); - JvmtiEnvManager.singleton().setPhase(JvmtiPhase.JVMTI_PHASE_DEAD()); - } - - public static void postThreadStart(Thread thread) { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_THREAD_START, thread); - } - - public static void postThreadEnd(Thread thread) { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_THREAD_END, thread); - } - - public static void postGarbageCollectionStart() { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_GARBAGE_COLLECTION_START); - } - - public static void postGarbageCollectionFinish() { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_GARBAGE_COLLECTION_FINISH); - } - - public static void postMonitorWait(Thread thread, Object obj, long timeout) { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_WAIT, thread, obj, timeout); - } - - public static void postMonitorWaited(Thread thread, Object obj, boolean timedout) { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_WAITED, thread, obj, timedout); - } - - public static void postMonitorContendedEnter(Thread thread, Object obj) { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_CONTENDED_ENTER, thread, obj); - } - - public static void postMonitorContendedEntered(Thread thread, Object obj) { - invokeCallbackForEvent(JvmtiEvent.JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, thread, obj); - } - - private static void invokeCallbackForEvent(JvmtiEvent event, Object... args) { - if (!SubstrateOptions.JVMTI.getValue()) { - return; - } - - JvmtiEnvManager manager = JvmtiEnvManager.singleton(); - if (!manager.hasAnyEnvironments()) { - return; - } - for (JvmtiEnv current = manager.getHeadEnvironment(); current.isNonNull(); current = current.getNextEnv()) { - if (JvmtiEnvEventEnabledUtils.isUserEventEnabled(JvmtiEnvUtil.getEnvEventEnabled(current), event)) { - // assert event.getNbParameters() == args.length; - int res = invokeCallbackFunction(current, event, args); - checkError(res, event, args); - } - } - } - - private static int invokeCallbackFunction(JvmtiEnv env, JvmtiEvent event, Object... args) { - switch (event) { - case JVMTI_EVENT_VM_DEATH -> { - JvmtiEventCallbacks.JvmtiEventVMDeathFunctionPointer vmDeathCallback = JvmtiEnvUtil.getEventCallbacks(env).getVMDeath(); - if (vmDeathCallback.isNonNull()) { - return vmDeathCallback.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress()); - } - } - case JVMTI_EVENT_VM_START -> { - JvmtiEventCallbacks.JvmtiEventVMStartFunctionPointer vmStartCallback = JvmtiEnvUtil.getEventCallbacks(env).getVMStart(); - if (vmStartCallback.isNonNull()) { - return vmStartCallback.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress()); - } - } - case JVMTI_EVENT_VM_INIT -> { - JvmtiEventCallbacks.JvmtiEventVMInitFunctionPointer vmInitCallback = JvmtiEnvUtil.getEventCallbacks(env).getVMInit(); - if (vmInitCallback.isNonNull()) { - return vmInitCallback.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), (JThread) JNIObjectHandles.createLocal(Thread.currentThread())); - } - } - case JVMTI_EVENT_GARBAGE_COLLECTION_START -> { - JvmtiEventCallbacks.JvmtiEventGarbageCollectionStartFunctionPointer gcStart = JvmtiEnvUtil.getEventCallbacks(env).getGarbageCollectionStart(); - if (gcStart.isNonNull()) { - return gcStart.invoke(JvmtiEnvUtil.toExternal(env)); - } - } - case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH -> { - JvmtiEventCallbacks.JvmtiEventGarbageCollectionFinishFunctionPointer gcFinish = JvmtiEnvUtil.getEventCallbacks(env).getGarbageCollectionFinish(); - if (gcFinish.isNonNull()) { - return gcFinish.invoke(JvmtiEnvUtil.toExternal(env)); - } - } - case JVMTI_EVENT_THREAD_START -> { - JvmtiEventCallbacks.JvmtiEventThreadStartFunctionPointer threadStart = JvmtiEnvUtil.getEventCallbacks(env).getThreadStart(); - if (threadStart.isNonNull()) { - if (!validArgumentTypes(args[0], Thread.class)) { - return ARGUMENT_ERROR; - } - JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); - return threadStart.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread); - } - } - case JVMTI_EVENT_THREAD_END -> { - JvmtiEventCallbacks.JvmtiEventThreadEndFunctionPointer threadEnd = JvmtiEnvUtil.getEventCallbacks(env).getThreadEnd(); - if (threadEnd.isNonNull()) { - if (!validArgumentTypes(args[0], Thread.class)) { - return ARGUMENT_ERROR; - } - JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); - return threadEnd.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread); - } - } - case JVMTI_EVENT_MONITOR_WAIT -> { - JvmtiEventCallbacks.JvmtiEventMonitorWaitFunctionPointer monitorWait = JvmtiEnvUtil.getEventCallbacks(env).getMonitorWait(); - if (monitorWait.isNonNull()) { - if (!validArgumentTypes(args[0], Thread.class) || !validArgumentTypes(args[2], Long.class)) { - return ARGUMENT_ERROR; - } - JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); - JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); - long timeout = (Long) args[2]; - return monitorWait.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject, timeout); - } - - } - case JVMTI_EVENT_MONITOR_WAITED -> { - JvmtiEventCallbacks.JvmtiEventMonitorWaitedFunctionPointer monitorWaited = JvmtiEnvUtil.getEventCallbacks(env).getMonitorWaited(); - if (monitorWaited.isNonNull()) { - if (!validArgumentTypes(args[0], Thread.class) || !validArgumentTypes(args[2], Boolean.class)) { - return ARGUMENT_ERROR; - } - JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); - JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); - boolean timedout = (Boolean) args[2]; - return monitorWaited.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject, timedout); - } - } - case JVMTI_EVENT_MONITOR_CONTENDED_ENTER -> { - JvmtiEventCallbacks.JvmtiEventMonitorContendedEnterFunctionPointer monitorContendedEnter = JvmtiEnvUtil.getEventCallbacks(env).getMonitorContendedEnter(); - if (monitorContendedEnter.isNonNull()) { - if (!validArgumentTypes(args[0], Thread.class)) { - return ARGUMENT_ERROR; - } - JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); - JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); - return monitorContendedEnter.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject); - } - } - case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED -> { - JvmtiEventCallbacks.JvmtiEventMonitorContendedEnteredFunctionPointer monitorContendedEntered = JvmtiEnvUtil.getEventCallbacks(env).getMonitorContendedEntered(); - if (monitorContendedEntered.isNonNull()) { - if (!validArgumentTypes(args[0], Thread.class)) { - return ARGUMENT_ERROR; - } - JThread jthread = (JThread) JNIObjectHandles.createLocal(args[0]); - JNIObjectHandle jobject = JNIObjectHandles.createLocal(args[1]); - return monitorContendedEntered.invoke(JvmtiEnvUtil.toExternal(env), JNIThreadLocalEnvironment.getAddress(), jthread, jobject); - } - } - default -> { - return EVENT_NOT_FOUND; - } - } - return NO_CALLBACK_SET; - } - - private static boolean validArgumentTypes(Object arg, Class type) { - return type.isInstance(arg); - } - - private static void checkError(int error, JvmtiEvent event, Object... args) { - if (error == EVENT_NOT_FOUND) { - Log.log().string("Event: " + event + " is not implemented yet"); - } else if (error == NO_CALLBACK_SET) { - Log.log().string("Event: " + event + " has no callback set"); - } - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java deleted file mode 100644 index bd180a4b1c79..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiRawMonitorUtil.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.type.CCharPointer; -import org.graalvm.word.Pointer; - -import com.oracle.svm.core.c.NonmovableArray; -import com.oracle.svm.core.c.NonmovableArrays; -import com.oracle.svm.core.c.NonmovableObjectArray; -import com.oracle.svm.core.jvmti.headers.JRawMonitorId; -import com.oracle.svm.core.jvmti.headers.JRawMonitorIdPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.locks.VMMutex; -import com.oracle.svm.core.monitor.JvmtiRawMonitorHelper; -import com.oracle.svm.core.monitor.MonitorInflationCause; -import com.oracle.svm.core.monitor.MultiThreadedMonitorSupport; -import com.oracle.svm.core.nmt.NmtCategory; - -import jdk.graal.compiler.api.replacements.Fold; - -public final class JvmtiRawMonitorUtil implements JvmtiMemoryManager { - - // TODO @dprcci Lots of copy pasted code because 2 values would need to be returned when - // refactored into a function. - // Current best idea is group the code and use a StackValue to write the error - - private final VMMutex mutex; - private static final int INITIAL_NB_AVAILABLE_SLOTS = 4; - private static final int ARRAY_GROWTH_FACTOR = 2; - private NonmovableObjectArray monitorObjectsArray; - private NonmovableArray freeIndicesList; - private int nextAvailableIndex; - private int monitorArraySize; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiRawMonitorUtil() { - mutex = new VMMutex("Jvmti RawMonitor"); - nextAvailableIndex = 0; - monitorArraySize = INITIAL_NB_AVAILABLE_SLOTS; - } - - public void initialize() { - monitorObjectsArray = NonmovableArrays.createObjectArray(Object[].class, INITIAL_NB_AVAILABLE_SLOTS, NmtCategory.JVMTI); - freeIndicesList = NonmovableArrays.createIntArray(INITIAL_NB_AVAILABLE_SLOTS, NmtCategory.JVMTI); - initFreeList(freeIndicesList); - } - - @Override - public void releaseAllUnmanagedMemory() { - tearDown(); - } - - @Fold - public static JvmtiRawMonitorUtil singleton() { - return ImageSingletons.lookup(JvmtiRawMonitorUtil.class); - } - - public static JvmtiError createRawMonitor(CCharPointer name, JRawMonitorIdPointer monitorPtr) { - return singleton().createRawMonitorInternal(monitorPtr); - } - - public static JvmtiError destroyRawMonitor(JRawMonitorId monitorId) { - return singleton().destroyRawMonitorInternal(monitorId); - } - - public static JvmtiError rawMonitorEnter(JRawMonitorId monitorId) { - return singleton().rawMonitorEnterInternal(monitorId); - } - - public static JvmtiError rawMonitorExit(JRawMonitorId monitorId) { - return singleton().rawMonitorExitInternal(monitorId); - } - - public static JvmtiError rawMonitorWait(JRawMonitorId monitorId, long millis) { - return singleton().rawMonitorWaitInternal(monitorId, millis); - } - - public static JvmtiError rawMonitorNotify(JRawMonitorId monitorId) { - return singleton().rawMonitorNotifyInternal(monitorId, false); - } - - public static JvmtiError rawMonitorNotifyAll(JRawMonitorId monitorId) { - return singleton().rawMonitorNotifyInternal(monitorId, true); - } - - private JvmtiError rawMonitorNotifyInternal(JRawMonitorId monitorId, boolean notifyAll) { - int monitorIdx = (int) monitorId.rawValue(); - if (isInvalidMonitorIdx(monitorIdx)) { - return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; - } - Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); - if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { - return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; - } - MultiThreadedMonitorSupport.singleton().notify(monitor, notifyAll); - return JvmtiError.JVMTI_ERROR_NONE; - } - - private JvmtiError rawMonitorWaitInternal(JRawMonitorId monitorId, long millis) { - int monitorIdx = (int) monitorId.rawValue(); - if (isInvalidMonitorIdx(monitorIdx)) { - return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; - } - Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); - if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { - return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; - } - // exception is thrown by wait(), but JVM TI does not specify behaviour in that case - if (millis < 0) { - millis = 0L; - } - // TODO @dprcci hard to get rid of the thrown exceptions without reimplementation - try { - MultiThreadedMonitorSupport.singleton().wait(monitor, millis); - } catch (InterruptedException e) { - return JvmtiError.JVMTI_ERROR_INTERRUPT; - } - return JvmtiError.JVMTI_ERROR_NONE; - } - - private JvmtiError rawMonitorExitInternal(JRawMonitorId monitorId) { - int monitorIdx = (int) monitorId.rawValue(); - if (isInvalidMonitorIdx(monitorIdx)) { - return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; - } - // TODO @dprcci handle entering during Agent_OnLoad - Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); - if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { - return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; - } - MultiThreadedMonitorSupport.singleton().monitorExit(monitor, MonitorInflationCause.JVMTI_ENTER); - return JvmtiError.JVMTI_ERROR_NONE; - } - - private JvmtiError rawMonitorEnterInternal(JRawMonitorId monitorId) { - int monitorIdx = (int) monitorId.rawValue(); - if (isInvalidMonitorIdx(monitorIdx)) { - return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; - } - // TODO @dprcci handle entering during Agent_OnLoad - Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); - MultiThreadedMonitorSupport.singleton().monitorEnter(monitor, MonitorInflationCause.JVMTI_ENTER); - return JvmtiError.JVMTI_ERROR_NONE; - } - - private JvmtiError createRawMonitorInternal(JRawMonitorIdPointer monitorPtr) { - try { - mutex.lock(); - // TODO @dprcci probably reimplement monitors without java Objects? - Object obj = new Object(); - JvmtiError err = JvmtiRawMonitorHelper.getOrCreateRawMonitor(obj); - if (err != JvmtiError.JVMTI_ERROR_NONE) { - return err; - } - int monitorIdx = getNextFreeMonitorIdx(); - NonmovableArrays.setObject(monitorObjectsArray, monitorIdx, obj); - ((Pointer) monitorPtr).writeInt(0, monitorIdx); - return JvmtiError.JVMTI_ERROR_NONE; - } finally { - mutex.unlock(); - } - } - - private JvmtiError destroyRawMonitorInternal(JRawMonitorId monitorId) { - try { - mutex.lock(); - int monitorIdx = (int) monitorId.rawValue(); - if (isInvalidMonitorIdx(monitorIdx)) { - return JvmtiError.JVMTI_ERROR_INVALID_MONITOR; - } - Object monitor = NonmovableArrays.getObject(monitorObjectsArray, monitorIdx); - if (!MultiThreadedMonitorSupport.singleton().isLockedByCurrentThread(monitor)) { - return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; - } - JvmtiError err = JvmtiRawMonitorHelper.exitCompletely(monitor); - if (err != JvmtiError.JVMTI_ERROR_NONE) { - return err; - } - if (!MultiThreadedMonitorSupport.singleton().isLockedByAnyThread(monitor)) { - return JvmtiError.JVMTI_ERROR_NOT_MONITOR_OWNER; - } - NonmovableArrays.setInt(freeIndicesList, --nextAvailableIndex, monitorIdx); - return JvmtiError.JVMTI_ERROR_NONE; - } finally { - mutex.unlock(); - } - } - - private void initFreeList(NonmovableArray freeList) { - for (int i = 0; i < INITIAL_NB_AVAILABLE_SLOTS; i++) { - NonmovableArrays.setInt(freeList, i, i); - } - } - - private void increaseMonitorArraySize() { - int newMonitorArraySize = monitorArraySize * ARRAY_GROWTH_FACTOR; - - NonmovableObjectArray newMonitorArray = NonmovableArrays.createObjectArray(Object[].class, newMonitorArraySize, NmtCategory.JVMTI); - NonmovableArrays.arraycopy(monitorObjectsArray, 0, newMonitorArray, 0, monitorArraySize); - NonmovableArrays.releaseUnmanagedArray(monitorObjectsArray); - monitorObjectsArray = newMonitorArray; - - NonmovableArray newFreeIndicesList = NonmovableArrays.createIntArray(newMonitorArraySize, NmtCategory.JVMTI); - NonmovableArrays.arraycopy(freeIndicesList, 0, newFreeIndicesList, 0, monitorArraySize); - NonmovableArrays.releaseUnmanagedArray(freeIndicesList); - freeIndicesList = newFreeIndicesList; - - monitorArraySize = newMonitorArraySize; - } - - public void tearDown() { - if (monitorObjectsArray.isNonNull()) { - NonmovableArrays.releaseUnmanagedArray(monitorObjectsArray); - } - if (freeIndicesList.isNonNull()) { - NonmovableArrays.releaseUnmanagedArray(freeIndicesList); - } - } - - private int getNextFreeMonitorIdx() { - if (nextAvailableIndex + 1 == monitorArraySize) { - increaseMonitorArraySize(); - } - return NonmovableArrays.getInt(freeIndicesList, nextAvailableIndex++); - } - - private boolean isInvalidMonitorIdx(int monitorIdx) { - if (monitorIdx >= monitorArraySize) { - return true; - } - for (int i = nextAvailableIndex; i < monitorArraySize; i++) { - if (NonmovableArrays.getInt(freeIndicesList, i) == monitorIdx) { - return true; - } - } - return false; - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java deleted file mode 100644 index 6c04cd08172c..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiStackTraceUtil.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import static com.oracle.svm.core.thread.JavaThreads.isVirtual; -import static com.oracle.svm.core.thread.PlatformThreads.getCarrierSPOrElse; - -import org.graalvm.nativeimage.CurrentIsolate; -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.StackValue; -import org.graalvm.nativeimage.c.function.CodePointer; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.FrameAccess; -import com.oracle.svm.core.NeverInline; -import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.code.FrameInfoQueryResult; -import com.oracle.svm.core.heap.VMOperationInfos; -import com.oracle.svm.core.jdk.StackTraceUtils; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.access.JNIReflectionDictionary; -import com.oracle.svm.core.jni.headers.JNIMethodId; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfo; -import com.oracle.svm.core.jvmti.headers.JvmtiFrameInfoPointer; -import com.oracle.svm.core.locks.VMMutex; -import com.oracle.svm.core.snippets.KnownIntrinsics; -import com.oracle.svm.core.stack.JavaStackFrameVisitor; -import com.oracle.svm.core.stack.JavaStackWalker; -import com.oracle.svm.core.thread.JavaThreads; -import com.oracle.svm.core.thread.NativeVMOperation; -import com.oracle.svm.core.thread.NativeVMOperationData; -import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.VMOperation; - -public final class JvmtiStackTraceUtil { - private static final int MAX_TEMP_BUFFER_SIZE = 64; - private static final long NATIVE_METHOD_LOCATION = -1; - private final VMMutex mutex; - private final JvmtiStackTraceVisitor stackTraceVisitor; - private final JvmtiFrameCountVisitor frameCountVisitor; - private final JvmtiStackTraceOperation stackTraceOperation; - private final JvmtiFrameCountOperation frameCountOperation; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiStackTraceUtil() { - this.mutex = new VMMutex("jvmti GetStackTrace Visitor"); - this.stackTraceVisitor = new JvmtiStackTraceVisitor(); - this.frameCountVisitor = new JvmtiFrameCountVisitor(); - this.stackTraceOperation = new JvmtiStackTraceOperation(); - this.frameCountOperation = new JvmtiFrameCountOperation(); - } - - public static JvmtiError getStackTrace(JThread jthread, int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer, CIntPointer countPtr) { - return ImageSingletons.lookup(JvmtiStackTraceUtil.class).getStackTraceInternal(jthread, startDepth, maxFrameCount, frameBuffer, countPtr); - } - - public static JvmtiError getFrameCount(JThread jthread, CIntPointer countPtr) { - return ImageSingletons.lookup(JvmtiStackTraceUtil.class).getFrameCountInternal(jthread, countPtr); - } - - private JvmtiError getStackTraceInternal(JThread jthread, int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer, CIntPointer countPtr) { - try { - mutex.lock(); - - // TODO @dprcci correct that logic? Do we want the program to crash - JvmtiError error = verifyJThreadHandle(jthread); - if (error != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - - if (!stackTraceVisitor.initialize(startDepth, maxFrameCount, frameBuffer)) { - return JvmtiError.JVMTI_ERROR_INTERNAL; - } - - int size = SizeOf.get(JvmtiStackWalkVMOperationData.class); - JvmtiStackWalkVMOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - data.setThreadHandle(jthread); - // JNIReflectionDictionary.singleton().dump(true, "egg"); - stackTraceOperation.enqueue(data); - - if (startDepth < 0) { - stackTraceVisitor.fillResultBuffer(); - } - countPtr.write(stackTraceVisitor.nbCollectedFrames); - return JvmtiError.JVMTI_ERROR_NONE; - } finally { - mutex.unlock(); - } - } - - @RawStructure - private interface JvmtiStackWalkVMOperationData extends NativeVMOperationData { - @RawField - JThread getThreadHandle(); - - @RawField - void setThreadHandle(JThread jthread); - } - - private class JvmtiStackTraceOperation extends NativeVMOperation { - JvmtiStackTraceOperation() { - super(VMOperationInfos.get(JvmtiStackTraceUtil.JvmtiStackTraceOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - protected void operate(NativeVMOperationData data) { - visitStackTrace((JvmtiStackWalkVMOperationData) data, stackTraceVisitor); - } - } - - @NeverInline(value = "jvmti GetStackTrace") - private void visitStackTrace(JvmtiStackWalkVMOperationData data, JavaStackFrameVisitor visitor) { - assert VMOperation.isInProgressAtSafepoint(); - - Thread thread = JNIObjectHandles.getObject(data.getThreadHandle()); - if (isVirtual(thread)) { - return; - } - Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); - IsolateThread isolateThread = PlatformThreads.getIsolateThread(thread); - - Pointer carrierSP = getCarrierSPOrElse(thread, WordFactory.nullPointer()); - if (isolateThread == CurrentIsolate.getCurrentThread()) { - Pointer startSP = carrierSP.isNonNull() ? carrierSP : callerSP; - Pointer endSP = WordFactory.nullPointer(); - JavaStackWalker.walkCurrentThread(startSP, endSP, visitor); - return; - } - - if (carrierSP.isNonNull()) { // mounted virtual thread, skip its frames - CodePointer carrierIP = FrameAccess.singleton().readReturnAddress(carrierSP); - Pointer endSP = WordFactory.nullPointer(); - assert VMOperation.isInProgressAtSafepoint(); - JavaStackWalker.walkThreadAtSafepoint(carrierSP, endSP, carrierIP, visitor); - return; - } - if (isolateThread.isNull()) { // recently launched thread - return; - } - Pointer endSP = WordFactory.nullPointer(); - JavaStackWalker.walkThread(isolateThread, endSP, visitor, null); - } - - public static boolean startDepthIsOutOfBound(int startDepth, int maxBound) { - boolean overOrEqualsMaxSize = startDepth > 0 && startDepth >= maxBound; - boolean belowMinSize = startDepth < 0 && startDepth < -maxBound; - return overOrEqualsMaxSize || belowMinSize; - } - - static class JvmtiStackTraceVisitor extends JavaStackFrameVisitor { - private JvmtiFrameInfoPointer jvmtiFramePtr; - private JvmtiFrameInfoPointer jvmtiFramePtrTemp; - private int nbFramesVisited; - private int startDepth; - private int maxFrameCount; - private int nbCollectedFrames; - - private JvmtiStackTraceVisitor() { - } - - boolean initialize(int startDepth, int maxFrameCount, JvmtiFrameInfoPointer frameBuffer) { - this.jvmtiFramePtr = frameBuffer; - this.startDepth = startDepth; - this.maxFrameCount = maxFrameCount; - this.nbFramesVisited = 0; - this.nbCollectedFrames = 0; - if (startDepth >= 0) { - return true; - } - if (-startDepth > MAX_TEMP_BUFFER_SIZE) { - return false; - } - jvmtiFramePtrTemp = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(SizeOf.get(JvmtiFrameInfo.class) * (-startDepth))); - return true; - } - - @Override - public boolean visitFrame(FrameInfoQueryResult frameInfo) { - if (!StackTraceUtils.shouldShowFrame(frameInfo, false, true, false)) { - /* Always ignore the frame. It is an internal frame of the VM. */ - return true; - - // TODO @dprcci useful? expand? - } else if (Throwable.class.isAssignableFrom(frameInfo.getSourceClass())) { - /* - * We are still in the constructor invocation chain at the beginning of the stack - * trace, which is also filtered by the Java HotSpot VM. - */ - return true; - } - - /* - * if the index is negative, the bottom the stack is the reference point, therefor we - * have to go all the way down. We reuse the same buffer to avoid useless memory - * allocation - */ - if (startDepth < 0) { - int index = nbCollectedFrames % (-startDepth); - assert jvmtiFramePtrTemp.isNonNull(); - nbCollectedFrames += convertToJvmtiFrameInfo(frameInfo, jvmtiFramePtrTemp, index, true); - return true; - } - - // TODO @dprcci What is the expected behaviour? Should a frame not containing a - // registered method be counted when going to startDepth? - if (nbCollectedFrames < maxFrameCount) { - int addedFrame = convertToJvmtiFrameInfo(frameInfo, jvmtiFramePtr, nbCollectedFrames, nbFramesVisited + 1 > startDepth); - nbFramesVisited += addedFrame; - if (nbFramesVisited > startDepth) { - nbCollectedFrames += addedFrame; - } - } - return nbCollectedFrames < maxFrameCount; - } - - private void fillResultBuffer() { - int bufferSize = -startDepth; - int resultSize = Math.min(bufferSize, maxFrameCount); - int oldestIndex = (maxFrameCount > nbCollectedFrames) ? 0 : nbCollectedFrames % bufferSize; - for (int i = 0; i < resultSize; i++) { - JvmtiFrameInfo res = getJvmtiFrameInfoAtIdx(jvmtiFramePtr, i); - JvmtiFrameInfo tmp = getJvmtiFrameInfoAtIdx(jvmtiFramePtrTemp, (oldestIndex + i) % bufferSize); - res.setMethod(tmp.getMethod()); - res.setLocation(tmp.getLocation()); - } - this.nbCollectedFrames = resultSize; - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(jvmtiFramePtrTemp); - } - - private int convertToJvmtiFrameInfo(FrameInfoQueryResult frameInfo, JvmtiFrameInfoPointer jvmtiFrameInfo, int index, boolean fill) { - long location = frameInfo.getBci(); - String methodName = frameInfo.getSourceMethodName(); - Class methodClass = frameInfo.getSourceClass(); - - JNIMethodId jMethodId = JNIReflectionDictionary.singleton().toMethodID(methodClass, methodName); - // JNIMethodId jMethodId = JNIReflectionDictionary.singleton().getRandomMethodID(); - // Method is not (should it be?) exposed to user, do not take it into account - if (jMethodId.isNull()) { - return 0; - } - if (!fill) { - return 1; - } - location = JNIReflectionDictionary.isMethodNative(jMethodId) ? NATIVE_METHOD_LOCATION : location; - JvmtiFrameInfo currentFrame = getJvmtiFrameInfoAtIdx(jvmtiFrameInfo, index); - currentFrame.setLocation(location); - currentFrame.setMethod(jMethodId); - return 1; - } - - private JvmtiFrameInfo getJvmtiFrameInfoAtIdx(JvmtiFrameInfoPointer jvmtiFrameInfo, int index) { - return (JvmtiFrameInfo) ((Pointer) jvmtiFrameInfo).add(index * SizeOf.get(JvmtiFrameInfo.class)); - } - } - - // Frame Count - - private JvmtiError getFrameCountInternal(JThread jthread, CIntPointer countPtr) { - try { - mutex.lock(); - JvmtiError error = verifyJThreadHandle(jthread); - if (error != JvmtiError.JVMTI_ERROR_NONE) { - return error; - } - - int size = SizeOf.get(JvmtiStackWalkVMOperationData.class); - JvmtiStackWalkVMOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - data.setThreadHandle(jthread); - frameCountOperation.enqueue(data); - - countPtr.write(frameCountVisitor.count); - return JvmtiError.JVMTI_ERROR_NONE; - } finally { - mutex.unlock(); - } - } - - private class JvmtiFrameCountOperation extends NativeVMOperation { - JvmtiFrameCountOperation() { - super(VMOperationInfos.get(JvmtiStackTraceUtil.JvmtiFrameCountOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - protected void operate(NativeVMOperationData data) { - frameCountVisitor.count = 0; - visitStackTrace((JvmtiStackWalkVMOperationData) data, frameCountVisitor); - } - } - - static class JvmtiFrameCountVisitor extends JavaStackFrameVisitor { - private int count = 0; - - private JvmtiFrameCountVisitor() { - } - - @Override - public boolean visitFrame(FrameInfoQueryResult frameInfo) { - if (!StackTraceUtils.shouldShowFrame(frameInfo, false, true, false)) { - return true; - } else if (Throwable.class.isAssignableFrom(frameInfo.getSourceClass())) { - return true; - } - // TODO @dprcci collect only frames with contain accessible information? - this.count += 1; - return true; - } - } - - // Helpers - - private static JvmtiError verifyJThreadHandle(JThread jthread) { - Thread thread; - if (jthread.equal(WordFactory.nullPointer())) { - thread = JavaThreads.getCurrentThreadOrNull(); - } else { - try { - Object threadReference = JNIObjectHandles.getObject(jthread); - thread = (Thread) threadReference; - } catch (IllegalArgumentException | ClassCastException e) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD; - } - } - if (thread == null) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD; - } - if (!thread.isAlive()) { - return JvmtiError.JVMTI_ERROR_THREAD_NOT_ALIVE; - } - return JvmtiError.JVMTI_ERROR_NONE; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiSupport.java new file mode 100644 index 000000000000..0b241b4afdf2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiSupport.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, 2024, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package com.oracle.svm.core.jvmti; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.svm.core.jdk.RuntimeSupport; +import com.oracle.svm.core.jvmti.headers.JvmtiPhase; + +import jdk.graal.compiler.api.replacements.Fold; + +/** Handles the JVMTI lifecycle (e.g., startup, phase changes, teardown). */ +public final class JvmtiSupport { + private JvmtiPhase phase = JvmtiPhase.JVMTI_PHASE_LIVE; + + @Platforms(Platform.HOSTED_ONLY.class) + public JvmtiSupport() { + } + + @Fold + public static JvmtiSupport singleton() { + return ImageSingletons.lookup(JvmtiSupport.class); + } + + public JvmtiPhase getPhase() { + return phase; + } + + public void setPhase(JvmtiPhase phase) { + this.phase = phase; + } + + public static RuntimeSupport.Hook initializationHook() { + return (firstIsolate) -> { + JvmtiAgents.singleton().load(); + JvmtiEvents.postVMInit(); + JvmtiEvents.postVMStart(); + }; + } + + public static RuntimeSupport.Hook teardownHook() { + return (firstIsolate) -> { + JvmtiEvents.postVMDeath(); + JvmtiSupport.singleton().setPhase(JvmtiPhase.JVMTI_PHASE_DEAD); + JvmtiAgents.singleton().unload(); + JvmtiEnvs.singleton().teardown(); + }; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java deleted file mode 100644 index 606df137ac13..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadActionsUtil.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.type.CCharPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JThreadGroup; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.headers.JvmtiThreadInfo; -import com.oracle.svm.core.thread.JavaThreads; - -public final class JvmtiThreadActionsUtil { - - private JvmtiThreadActionsUtil() { - } - - public static int interruptThread(JThread jthread) { - // TODO @dprcci refactor - Thread thread; - try { - Object threadReference = JNIObjectHandles.getObject(jthread); - thread = (Thread) threadReference; - } catch (IllegalArgumentException | ClassCastException e) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue(); - } - if (thread == null) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue(); - } - if (!thread.isAlive()) { - return JvmtiError.JVMTI_ERROR_THREAD_NOT_ALIVE.getCValue(); - } - // TODO @dprcci check if works - try { - thread.interrupt(); - } catch (SecurityException e) { - return JvmtiError.JVMTI_ERROR_INTERNAL.getCValue(); - } - return JvmtiError.JVMTI_ERROR_NONE.getCValue(); - } - - public static JvmtiError getThreadInfo(JThread jthread, JvmtiThreadInfo infoPtr) { - Thread thread; - if (jthread.equal(WordFactory.nullPointer())) { - thread = JavaThreads.getCurrentThreadOrNull(); - } else { - try { - Object threadReference = JNIObjectHandles.getObject(jthread); - thread = (Thread) threadReference; - } catch (IllegalArgumentException | ClassCastException e) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD; - } - } - if (thread == null) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD; - } - - String name = thread.getName(); - int priority = thread.getPriority(); - boolean isDaemon = thread.isDaemon(); - ThreadGroup threadGroup = thread.getThreadGroup(); - ClassLoader contextClassLoader = thread.getContextClassLoader(); - - int nameModifiedUTF8Length = UninterruptibleUtils.String.modifiedUTF8Length(name, true); - CCharPointer nameBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(nameModifiedUTF8Length)); - UninterruptibleUtils.String.toModifiedUTF8(name, (Pointer) nameBuffer, ((Pointer) nameBuffer).add(nameModifiedUTF8Length), true); - - JThreadGroup threadGroupHandle = (JThreadGroup) JNIObjectHandles.createLocal(threadGroup); - JNIObjectHandle contextClassLoaderHandle = JNIObjectHandles.createLocal(contextClassLoader); - - infoPtr.setName(nameBuffer); - infoPtr.setPriority(priority); - infoPtr.setIsDaemon(isDaemon); - infoPtr.setThreadGroup(threadGroupHandle); - infoPtr.setContextClassLoader(contextClassLoaderHandle); - - return JvmtiError.JVMTI_ERROR_NONE; - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java deleted file mode 100644 index 51278f3c4d3b..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadGroupUtil.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.IsolateThread; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.StackValue; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CCharPointer; -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.Pointer; -import org.graalvm.word.PointerBase; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.config.ConfigurationValues; -import com.oracle.svm.core.heap.VMOperationInfos; -import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JThreadGroup; -import com.oracle.svm.core.jvmti.headers.JThreadGroupPointer; -import com.oracle.svm.core.jvmti.headers.JThreadGroupPointerPointer; -import com.oracle.svm.core.jvmti.headers.JThreadPointer; -import com.oracle.svm.core.jvmti.headers.JThreadPointerPointer; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.headers.JvmtiThreadGroupInfo; -import com.oracle.svm.core.jvmti.utils.JvmtiUtils; -import com.oracle.svm.core.thread.JavaLangThreadGroupSubstitutions; -import com.oracle.svm.core.thread.JavaThreads; -import com.oracle.svm.core.thread.NativeVMOperation; -import com.oracle.svm.core.thread.NativeVMOperationData; -import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.VMThreads; - -import jdk.graal.compiler.api.replacements.Fold; - -public class JvmtiThreadGroupUtil { - - private final JvmtiGetThreadGroupChildrenOperation getThreadGroupChildrenOperation; - private static final int INITIAL_THREAD_BUFFER_CAPACITY = 50; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiThreadGroupUtil() { - getThreadGroupChildrenOperation = new JvmtiGetThreadGroupChildrenOperation(); - } - - @Fold - public static JvmtiThreadGroupUtil singleton() { - return ImageSingletons.lookup(JvmtiThreadGroupUtil.class); - } - - public static JvmtiError getTopThreadGroups(CIntPointer groupCountPtr, JThreadGroupPointerPointer groupsPtr) { - ThreadGroup top = PlatformThreads.singleton().systemGroup; - JThreadGroup topHandle = (JThreadGroup) JNIObjectHandles.createLocal(top); - - JThreadGroupPointer topArray = JvmtiUtils.allocateWordBuffer(1); - if (topArray.isNull()) { - return JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; - } - - JvmtiUtils.writeWordAtIdxInBuffer(topArray, 0, topHandle); - - ((Pointer) groupsPtr).writeWord(0, topArray); - groupCountPtr.write(1); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getThreadGroupInfo(JThreadGroup group, JvmtiThreadGroupInfo infoPtr) { - CIntPointer errorPtr = StackValue.get(CIntPointer.class); - ThreadGroup threadGroup = getThreadGroupFromHandle(group, errorPtr); - if (JvmtiError.fromValue(errorPtr.read()) != JvmtiError.JVMTI_ERROR_NONE) { - return JvmtiError.fromValue(errorPtr.read()); - } - ThreadGroup parentGroup = threadGroup.getParent(); - String groupName = threadGroup.getName(); - int groupMaxPriority = threadGroup.getMaxPriority(); - // No longer valid - boolean isDeamonGroup = false; - - fillThreadGroupInfo(infoPtr, parentGroup, groupName, groupMaxPriority, isDeamonGroup); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError getThreadGroupChildren(JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, - CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { - return singleton().getThreadGroupChildrenInternal(group, threadCountPtr, threadsPtr, groupCountPtr, groupsPtr); - } - - private JvmtiError getThreadGroupChildrenInternal(JThreadGroup group, CIntPointer threadCountPtr, JThreadPointerPointer threadsPtr, - CIntPointer groupCountPtr, JThreadGroupPointer groupsPtr) { - CIntPointer errorPtr = StackValue.get(CIntPointer.class); - - ThreadGroup threadGroup = getThreadGroupFromHandle(group, errorPtr); - if (JvmtiError.fromValue(errorPtr.read()) != JvmtiError.JVMTI_ERROR_NONE) { - return JvmtiError.fromValue(errorPtr.read()); - } - - int size = SizeOf.get(JvmtiThreadGroupVMOperationData.class); - JvmtiThreadGroupVMOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - int activeCountEstimate = threadGroup.activeCount(); - int activeGroupCountEstimate = threadGroup.activeCount(); - data.setJThreadBufferSize(activeCountEstimate > 0 ? activeCountEstimate : INITIAL_THREAD_BUFFER_CAPACITY); - data.setJThreadGroupBufferSize(activeGroupCountEstimate > 0 ? activeGroupCountEstimate : INITIAL_THREAD_BUFFER_CAPACITY); - - data.setJThreadGroup(group); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - - getThreadGroupChildrenOperation.enqueue(data); - if (JvmtiError.fromValue(data.getJvmtiError()) != JvmtiError.JVMTI_ERROR_NONE) { - return JvmtiError.fromValue(data.getJvmtiError()); - } - - threadCountPtr.write(data.getJThreadBufferSize()); - ((Pointer) threadsPtr).writeWord(0, data.getJThreadBuffer()); - - groupCountPtr.write(data.getJThreadGroupBufferSize()); - ((Pointer) groupsPtr).writeWord(0, data.getJThreadGroupBuffer()); - return JvmtiError.JVMTI_ERROR_NONE; - } - - // Could be refactored - @Uninterruptible(reason = "jvmti getThreadGroupChildren") - private static void getThreadGroupChildren(JvmtiThreadGroupVMOperationData data) { - int threadGroupsBufferSize = data.getJThreadGroupBufferSize(); - int threadsBufferSize = data.getJThreadBufferSize(); - JThreadGroupPointer threadGroupsBuffer = JvmtiUtils.allocateWordBuffer(threadGroupsBufferSize); - JThreadPointer threadsBuffer = JvmtiUtils.allocateWordBuffer(threadsBufferSize); - - ThreadGroup targetThreadGroup = JNIObjectHandles.getObject(data.getJThreadGroup()); - - int nbThreadsWritten = 0; - int nbThreadGroupsWritten = 0; - - for (IsolateThread isolateThread = VMThreads.firstThread(); isolateThread.isNonNull(); isolateThread = VMThreads.nextThread(isolateThread)) { - Thread thread = PlatformThreads.fromVMThread(isolateThread); - // "Get all live platform threads that are attached to the VM" - if (thread == null || thread.isVirtual() || !JavaThreads.isAlive(thread)) { - continue; - } - ThreadGroup currentThreadGroup = JavaThreads.getRawThreadGroup(thread); - // Collect subgroups - if (JavaLangThreadGroupSubstitutions.getParentThreadGroupUnsafe(currentThreadGroup) == targetThreadGroup) { - if (nbThreadGroupsWritten == threadGroupsBufferSize) { - threadGroupsBuffer = JvmtiUtils.growWordBuffer(threadGroupsBuffer, 2 * threadGroupsBufferSize); - threadGroupsBufferSize = 2 * threadGroupsBufferSize; - if (threadGroupsBuffer.isNull()) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY.getCValue()); - JvmtiUtils.freeWordBuffer(threadsBuffer); - return; - } - } - JThreadGroup threadGroupHandle = (JThreadGroup) JNIObjectHandles.createLocal(currentThreadGroup); - JvmtiUtils.writeWordAtIdxInBuffer(threadGroupsBuffer, nbThreadGroupsWritten, threadGroupHandle); - nbThreadGroupsWritten++; - } - // Collect threads belonging to group - if (currentThreadGroup == targetThreadGroup) { - if (nbThreadsWritten == threadsBufferSize) { - threadsBuffer = JvmtiUtils.growWordBuffer(threadsBuffer, 2 * threadsBufferSize); - threadsBufferSize = 2 * threadsBufferSize; - if (threadsBuffer.isNull()) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY.getCValue()); - JvmtiUtils.freeWordBuffer(threadGroupsBuffer); - return; - } - } - JThread threadHandle = (JThread) JNIObjectHandles.createLocal(thread); - JvmtiUtils.writeWordAtIdxInBuffer(threadGroupsBuffer, nbThreadGroupsWritten, threadHandle); - nbThreadsWritten++; - } - } - data.setJThreadGroupBuffer(threadGroupsBuffer); - data.setJThreadGroupBufferSize(nbThreadGroupsWritten); - data.setJThreadBuffer(threadsBuffer); - data.setJThreadBufferSize(nbThreadsWritten); - } - - @RawStructure - private interface JvmtiThreadGroupVMOperationData extends NativeVMOperationData { - @RawField - JThreadGroup getJThreadGroup(); - - @RawField - void setJThreadGroup(JThreadGroup ptr); - - @RawField - void setJvmtiError(int err); - - @RawField - int getJvmtiError(); - - @RawField - void setJThreadBuffer(JThreadPointer ptr); - - @RawField - JThreadPointer getJThreadBuffer(); - - @RawField - void setJThreadBufferSize(int size); - - @RawField - int getJThreadBufferSize(); - - @RawField - void setJThreadGroupBuffer(JThreadGroupPointer ptr); - - @RawField - JThreadGroupPointer getJThreadGroupBuffer(); - - @RawField - void setJThreadGroupBufferSize(int size); - - @RawField - int getJThreadGroupBufferSize(); - } - - private static class JvmtiGetThreadGroupChildrenOperation extends NativeVMOperation { - JvmtiGetThreadGroupChildrenOperation() { - super(VMOperationInfos.get(JvmtiGetThreadGroupChildrenOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - protected void operate(NativeVMOperationData data) { - getThreadGroupChildren((JvmtiThreadGroupVMOperationData) data); - } - } - - private static void fillThreadGroupInfo(JvmtiThreadGroupInfo infoPtr, ThreadGroup parent, String name, int maxPriority, boolean isDaemon) { - JThreadGroup parentHandle = (JThreadGroup) JNIObjectHandles.createLocal(parent); - int nameSize = UninterruptibleUtils.String.modifiedUTF8Length(name, true, null); - CCharPointer nameBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(nameSize)); - UninterruptibleUtils.String.toModifiedUTF8(name, (Pointer) nameBuffer, ((Pointer) nameBuffer).add(nameSize), true); - - infoPtr.setParent(parentHandle); - infoPtr.setName(nameBuffer); - infoPtr.setMaxPriority(maxPriority); - infoPtr.setIsDaemon(isDaemon); - } - - private static ThreadGroup getThreadGroupFromHandle(JThreadGroup handle, CIntPointer error) { - ThreadGroup threadGroup; - try { - threadGroup = JNIObjectHandles.getObject(handle); - } catch (ClassCastException | IllegalArgumentException e) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_THREAD_GROUP.getCValue()); - return null; - } - if (threadGroup == null) { - error.write(JvmtiError.JVMTI_ERROR_INVALID_THREAD_GROUP.getCValue()); - return null; - } - error.write(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - return threadGroup; - } - - private static T allocateReturnArray(int nbElement) { - return ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(nbElement * ConfigurationValues.getTarget().wordSize)); - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java deleted file mode 100644 index 8f43d9821732..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadLocalStorage.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.c.type.VoidPointer; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.jvmti.headers.VoidPointerPointer; -import com.oracle.svm.core.jvmti.utils.JvmtiLocalStorageUtil; - -import jdk.graal.compiler.api.replacements.Fold; - -public final class JvmtiThreadLocalStorage extends JvmtiLocalStorageUtil { - - private static final int INITIAL_CAPACITY = 8; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiThreadLocalStorage() { - super("Jvmti Thread Local Storage"); - } - - public void initialize() { - super.initialize(INITIAL_CAPACITY); - } - - @Fold - public static JvmtiThreadLocalStorage singleton() { - return ImageSingletons.lookup(JvmtiThreadLocalStorage.class); - } - - public static JvmtiError setThreadLocalStorage(JThread thread, VoidPointer data) { - JvmtiError threadError = isValidThread(thread); - if (threadError != JvmtiError.JVMTI_ERROR_NONE) { - return threadError; - } - return singleton().setThreadLocalStorageInternal(thread, data); - } - - public static JvmtiError getThreadLocalStorage(JThread thread, VoidPointerPointer dataPtr) { - JvmtiError threadError = isValidThread(thread); - if (threadError != JvmtiError.JVMTI_ERROR_NONE) { - return threadError; - } - return singleton().getThreadLocalStorageInternal(thread, dataPtr); - } - - private JvmtiError getThreadLocalStorageInternal(JThread thread, VoidPointerPointer dataPtr) { - thread = ensureCorrectJThread(thread); - VoidPointer data = super.contains(thread) ? super.get(thread) : WordFactory.nullPointer(); - ((Pointer) dataPtr).writeWord(0, data); - return JvmtiError.JVMTI_ERROR_NONE; - } - - private JvmtiError setThreadLocalStorageInternal(JThread thread, VoidPointer data) { - thread = ensureCorrectJThread(thread); - super.put(thread, data); - return JvmtiError.JVMTI_ERROR_NONE; - } - - private static JThread ensureCorrectJThread(JThread thread) { - return thread.equal(WordFactory.nullPointer()) ? (JThread) JNIObjectHandles.createLocal(Thread.currentThread()) : thread; - } - - private static JvmtiError isValidThread(JThread jthread) { - Thread thread; - try { - Object threadReference = JNIObjectHandles.getObject(jthread); - thread = (Thread) threadReference; - } catch (IllegalArgumentException | ClassCastException e) { - return JvmtiError.JVMTI_ERROR_INVALID_THREAD; - } - if (thread == null) { - thread = Thread.currentThread(); - } - if (!thread.isAlive()) { - return JvmtiError.JVMTI_ERROR_THREAD_NOT_ALIVE; - } - return JvmtiError.JVMTI_ERROR_NONE; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java deleted file mode 100644 index 4a6343e3b193..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/JvmtiThreadStateUtil.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti; - -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_ALIVE; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_INTERRUPTED; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_IN_NATIVE; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_IN_OBJECT_WAIT; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_PARKED; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_RUNNABLE; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_SLEEPING; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_TERMINATED; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_WAITING; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_WAITING_INDEFINITELY; -import static com.oracle.svm.core.jvmti.headers.JvmtiThreadState.JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.StackValue; -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.c.type.CIntPointer; -import org.graalvm.word.Pointer; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.UnmanagedMemoryUtil; -import com.oracle.svm.core.heap.VMOperationInfos; -import com.oracle.svm.core.jni.JNIObjectHandles; -import com.oracle.svm.core.jvmti.headers.JThread; -import com.oracle.svm.core.jvmti.headers.JvmtiError; -import com.oracle.svm.core.monitor.MonitorSupport; -import com.oracle.svm.core.thread.JavaThreads; -import com.oracle.svm.core.thread.NativeVMOperation; -import com.oracle.svm.core.thread.NativeVMOperationData; -import com.oracle.svm.core.thread.PlatformThreads; -import com.oracle.svm.core.thread.ThreadStatus; -import com.oracle.svm.core.thread.VMThreads; - -public final class JvmtiThreadStateUtil { - private final JvmtiGetThreadStateOperation stateOperation; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiThreadStateUtil() { - this.stateOperation = new JvmtiGetThreadStateOperation(); - } - - public static int getThreadState(JThread jthread, CIntPointer statePtr) { - return ImageSingletons.lookup(JvmtiThreadStateUtil.class).getThreadStateInternal(jthread, statePtr); - } - - private int getThreadStateInternal(JThread jthread, CIntPointer statePtr) { - int size = SizeOf.get(JvmtiGetThreadStateOperationData.class); - JvmtiGetThreadStateOperationData data = StackValue.get(size); - UnmanagedMemoryUtil.fill((Pointer) data, WordFactory.unsigned(size), (byte) 0); - - data.setJThreadPointer(jthread); - data.setThreadStatePointer(statePtr); - stateOperation.enqueue(data); - return data.getJvmtiError(); - } - - @RawStructure - private interface JvmtiGetThreadStateOperationData extends NativeVMOperationData { - @RawField - void setThreadStatePointer(CIntPointer ptr); - - @RawField - CIntPointer getThreadStatePointer(); - - @RawField - int getJvmtiError(); - - @RawField - void setJvmtiError(int error); - - @RawField - void setJThreadPointer(JThread ptr); - - @RawField - JThread getJThreadPointer(); - } - - // TODO @dprcci cannot allocate memory - private static class JvmtiGetThreadStateOperation extends NativeVMOperation { - JvmtiGetThreadStateOperation() { - super(VMOperationInfos.get(JvmtiGetThreadStateOperation.class, "Get stack trace jvmti", SystemEffect.SAFEPOINT)); - } - - @Override - // @RestrictHeapAccess(reason = "jvmti", access = RestrictHeapAccess.Access.NO_ALLOCATION) - protected void operate(NativeVMOperationData data) { - getThreadState((JvmtiGetThreadStateOperationData) data); - } - } - - private static void getThreadState(JvmtiGetThreadStateOperationData data) { - JThread jthread = data.getJThreadPointer(); - Thread thread; - try { - Object threadReference = JNIObjectHandles.getObject(jthread); - thread = (Thread) threadReference; - } catch (IllegalArgumentException | ClassCastException e) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INVALID_THREAD.getCValue()); - return; - } - if (thread == null) { - thread = JavaThreads.getCurrentThreadOrNull(); - if (thread == null) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); - return; - } - } - int result = getThreadState(thread); - // TODO @dprcci better and more consistent error handling - if (result == -1) { - data.setJvmtiError(JvmtiError.JVMTI_ERROR_INTERNAL.getCValue()); - return; - } - data.getThreadStatePointer().write(result); - data.setJvmtiError(JvmtiError.JVMTI_ERROR_NONE.getCValue()); - } - - // TODO @dprcci check - protected static int getThreadState(Thread thread) { - int result = 0; - - Thread.State state = thread.getState(); - if (!thread.isAlive()) { - return (state == Thread.State.TERMINATED) ? JVMTI_THREAD_STATE_TERMINATED.getValue() : 0; - } - - result |= JVMTI_THREAD_STATE_ALIVE.getValue(); - - // threads cannot be suspended - - // Interrupted - if (thread.isInterrupted()) { // if(JavaThreads.isInterrupted(thread)){ - result |= JVMTI_THREAD_STATE_INTERRUPTED.getValue(); - } - // TODO @dprcci Correct IsoalteThread but doesn't work because it is put into safe point - if (VMThreads.StatusSupport.getStatusVolatile(PlatformThreads.getIsolateThread(thread)) == VMThreads.StatusSupport.STATUS_IN_NATIVE) { - result |= JVMTI_THREAD_STATE_IN_NATIVE.getValue(); - } - - if (state == Thread.State.RUNNABLE) { - result |= JVMTI_THREAD_STATE_RUNNABLE.getValue(); - return result; - } - if (state == Thread.State.BLOCKED) { - result |= JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER.getValue(); - return result; - } - - // Waiting - boolean timedWait; - if ((timedWait = (state != Thread.State.WAITING)) && state != Thread.State.TIMED_WAITING) { - return -1; - } - - result |= JVMTI_THREAD_STATE_WAITING.getValue(); - result |= (timedWait) ? JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT.getValue() : JVMTI_THREAD_STATE_WAITING_INDEFINITELY.getValue(); - - // Waiting reason - int waitingStatus = MonitorSupport.singleton().getParkedThreadStatus(thread, timedWait); - if (waitingStatus == ThreadStatus.IN_OBJECT_WAIT) { - result |= JVMTI_THREAD_STATE_IN_OBJECT_WAIT.getValue(); - } else if (waitingStatus == ThreadStatus.PARKED || waitingStatus == ThreadStatus.PARKED_TIMED) { - result |= JVMTI_THREAD_STATE_PARKED.getValue(); - } - // Sleeping - if (PlatformThreads.getThreadStatus(thread) == ThreadStatus.SLEEPING) { - result |= JVMTI_THREAD_STATE_SLEEPING.getValue(); - } - return result; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java index 35cd3804f2ed..b1764ce043b3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/BooleanPointer.java @@ -27,7 +27,9 @@ import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; -// TEMP (chaeubl): should be uint_8 -@CPointerTo(nameOfCType = "char") +@CPointerTo(nameOfCType = "unsigned char") public interface BooleanPointer extends PointerBase { + boolean read(); + + void write(boolean value); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java index 8f2e6c28ea9a..60db4865cf5c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JRawMonitorIdPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jvmti.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JvmtiDirectives.class) @CPointerTo(JRawMonitorId.class) public interface JRawMonitorIdPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java index cd162c4ad0a6..88ebb4ae6085 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiDirectives.java @@ -33,10 +33,11 @@ import com.oracle.svm.core.OS; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.util.BasedOnJDKFile; -// TEMP (chaeubl): copied +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+11/src/hotspot/share/prims/jvmti.xml") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+11/src/hotspot/share/prims/jvmtiH.xsl") class JvmtiDirectives implements CContext.Directives { - private final Path jdkIncludeDir = Paths.get(System.getProperty("java.home")).resolve("include"); @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java index a268002825f8..98dc2d5f56d0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiError.java @@ -25,127 +25,85 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; import org.graalvm.nativeimage.c.constant.CEnum; -import org.graalvm.nativeimage.c.constant.CEnumConstant; import org.graalvm.nativeimage.c.constant.CEnumLookup; import org.graalvm.nativeimage.c.constant.CEnumValue; -@CEnum("jvmtiError") @CContext(JvmtiDirectives.class) +@CEnum("jvmtiError") public enum JvmtiError { /* Universal errors. */ - @CEnumConstant("JVMTI_ERROR_NONE") // JVMTI_ERROR_NONE, - - @CEnumConstant("JVMTI_ERROR_NULL_POINTER") JVMTI_ERROR_NULL_POINTER, - @CEnumConstant("JVMTI_ERROR_OUT_OF_MEMORY") JVMTI_ERROR_OUT_OF_MEMORY, - @CEnumConstant("JVMTI_ERROR_ACCESS_DENIED") JVMTI_ERROR_ACCESS_DENIED, - @CEnumConstant("JVMTI_ERROR_UNATTACHED_THREAD") JVMTI_ERROR_UNATTACHED_THREAD, - @CEnumConstant("JVMTI_ERROR_INVALID_ENVIRONMENT") JVMTI_ERROR_INVALID_ENVIRONMENT, - @CEnumConstant("JVMTI_ERROR_WRONG_PHASE") JVMTI_ERROR_WRONG_PHASE, - @CEnumConstant("JVMTI_ERROR_INTERNAL") JVMTI_ERROR_INTERNAL, /* Function specific errors. */ - @CEnumConstant("JVMTI_ERROR_INVALID_PRIORITY") JVMTI_ERROR_INVALID_PRIORITY, - @CEnumConstant("JVMTI_ERROR_THREAD_NOT_SUSPENDED") JVMTI_ERROR_THREAD_NOT_SUSPENDED, - @CEnumConstant("JVMTI_ERROR_THREAD_SUSPENDED") JVMTI_ERROR_THREAD_SUSPENDED, - @CEnumConstant("JVMTI_ERROR_THREAD_NOT_ALIVE") JVMTI_ERROR_THREAD_NOT_ALIVE, - @CEnumConstant("JVMTI_ERROR_CLASS_NOT_PREPARED") JVMTI_ERROR_CLASS_NOT_PREPARED, - @CEnumConstant("JVMTI_ERROR_NO_MORE_FRAMES") JVMTI_ERROR_NO_MORE_FRAMES, - @CEnumConstant("JVMTI_ERROR_OPAQUE_FRAME") JVMTI_ERROR_OPAQUE_FRAME, - @CEnumConstant("JVMTI_ERROR_DUPLICATE") JVMTI_ERROR_DUPLICATE, - @CEnumConstant("JVMTI_ERROR_NOT_FOUND") JVMTI_ERROR_NOT_FOUND, - @CEnumConstant("JVMTI_ERROR_NOT_MONITOR_OWNER") JVMTI_ERROR_NOT_MONITOR_OWNER, - @CEnumConstant("JVMTI_ERROR_INTERRUPT") JVMTI_ERROR_INTERRUPT, - @CEnumConstant("JVMTI_ERROR_UNMODIFIABLE_CLASS") JVMTI_ERROR_UNMODIFIABLE_CLASS, - @CEnumConstant("JVMTI_ERROR_UNMODIFIABLE_MODULE") JVMTI_ERROR_UNMODIFIABLE_MODULE, - @CEnumConstant("JVMTI_ERROR_NOT_AVAILABLE") JVMTI_ERROR_NOT_AVAILABLE, - @CEnumConstant("JVMTI_ERROR_ABSENT_INFORMATION") JVMTI_ERROR_ABSENT_INFORMATION, - @CEnumConstant("JVMTI_ERROR_INVALID_EVENT_TYPE") JVMTI_ERROR_INVALID_EVENT_TYPE, - @CEnumConstant("JVMTI_ERROR_NATIVE_METHOD") JVMTI_ERROR_NATIVE_METHOD, - @CEnumConstant("JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED") JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED, /* Function specific agent errors. */ - @CEnumConstant("JVMTI_ERROR_INVALID_THREAD") JVMTI_ERROR_INVALID_THREAD, - @CEnumConstant("JVMTI_ERROR_INVALID_FIELDID") JVMTI_ERROR_INVALID_FIELDID, - @CEnumConstant("JVMTI_ERROR_INVALID_MODULE") JVMTI_ERROR_INVALID_MODULE, - @CEnumConstant("JVMTI_ERROR_INVALID_METHODID") JVMTI_ERROR_INVALID_METHODID, - @CEnumConstant("JVMTI_ERROR_INVALID_LOCATION") JVMTI_ERROR_INVALID_LOCATION, - @CEnumConstant("JVMTI_ERROR_INVALID_OBJECT") JVMTI_ERROR_INVALID_OBJECT, - @CEnumConstant("JVMTI_ERROR_INVALID_CLASS") JVMTI_ERROR_INVALID_CLASS, - @CEnumConstant("JVMTI_ERROR_TYPE_MISMATCH") JVMTI_ERROR_TYPE_MISMATCH, - @CEnumConstant("JVMTI_ERROR_INVALID_SLOT") JVMTI_ERROR_INVALID_SLOT, - @CEnumConstant("JVMTI_ERROR_MUST_POSSESS_CAPABILITY") JVMTI_ERROR_MUST_POSSESS_CAPABILITY, - @CEnumConstant("JVMTI_ERROR_INVALID_THREAD_GROUP") JVMTI_ERROR_INVALID_THREAD_GROUP, - @CEnumConstant("JVMTI_ERROR_INVALID_MONITOR") JVMTI_ERROR_INVALID_MONITOR, - @CEnumConstant("JVMTI_ERROR_ILLEGAL_ARGUMENT") JVMTI_ERROR_ILLEGAL_ARGUMENT, - @CEnumConstant("JVMTI_ERROR_INVALID_TYPESTATE") JVMTI_ERROR_INVALID_TYPESTATE, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_VERSION") JVMTI_ERROR_UNSUPPORTED_VERSION, - @CEnumConstant("JVMTI_ERROR_INVALID_CLASS_FORMAT") JVMTI_ERROR_INVALID_CLASS_FORMAT, - @CEnumConstant("JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION") JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED, - @CEnumConstant("JVMTI_ERROR_FAILS_VERIFICATION") JVMTI_ERROR_FAILS_VERIFICATION, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED, - @CEnumConstant("JVMTI_ERROR_NAMES_DONT_MATCH") JVMTI_ERROR_NAMES_DONT_MATCH, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED") JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED, - @CEnumConstant("JVMTI_ERROR_UNSUPPORTED_OPERATION") JVMTI_ERROR_UNSUPPORTED_OPERATION; + @CConstant("JVMTI_ERROR_NONE") + public static native int none(); + + @CConstant("JVMTI_ERROR_UNATTACHED_THREAD") + public static native int unattachedThread(); + + @CConstant("JVMTI_ERROR_INVALID_ENVIRONMENT") + public static native int invalidEnvironment(); + + @CConstant("JVMTI_ERROR_INTERNAL") + public static native int internal(); + @CEnumValue public native int getCValue(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java index b4cafcf6df77..edda8bc5a6ce 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEvent.java @@ -25,56 +25,57 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CConstant; import org.graalvm.nativeimage.c.constant.CEnum; import org.graalvm.nativeimage.c.constant.CEnumLookup; import org.graalvm.nativeimage.c.constant.CEnumValue; -@CEnum("jvmtiEvent") +import com.oracle.svm.core.collections.EnumBitmask; + @CContext(JvmtiDirectives.class) +@CEnum("jvmtiEvent") public enum JvmtiEvent { - JVMTI_EVENT_VM_INIT(true, true, 1), - JVMTI_EVENT_VM_DEATH(true, true, 0), - JVMTI_EVENT_THREAD_START(true, true, 1), - JVMTI_EVENT_THREAD_END(false, true, 1), - JVMTI_EVENT_CLASS_FILE_LOAD_HOOK(false, false, 8), - JVMTI_EVENT_CLASS_LOAD(false, false, 2), - JVMTI_EVENT_CLASS_PREPARE(false, false, 2), - JVMTI_EVENT_VM_START(true, true, 0), - JVMTI_EVENT_EXCEPTION(false, false, 6), - JVMTI_EVENT_EXCEPTION_CATCH(false, false, 4), - JVMTI_EVENT_SINGLE_STEP(false, false, 3), - JVMTI_EVENT_FRAME_POP(false, false, 3), - JVMTI_EVENT_BREAKPOINT(false, false, 3), - JVMTI_EVENT_FIELD_ACCESS(false, false, 6), - JVMTI_EVENT_FIELD_MODIFICATION(false, false, 8), - JVMTI_EVENT_METHOD_ENTRY(true, false, 2), - JVMTI_EVENT_METHOD_EXIT(false, false, 4), - JVMTI_EVENT_NATIVE_METHOD_BIND(false, false, 4), - JVMTI_EVENT_COMPILED_METHOD_LOAD(true, false, 6), - JVMTI_EVENT_COMPILED_METHOD_UNLOAD(true, false, 3), - JVMTI_EVENT_DYNAMIC_CODE_GENERATED(true, false, 3), - JVMTI_EVENT_DATA_DUMP_REQUEST(true, false, 0), - JVMTI_EVENT_MONITOR_WAIT(false, true, 3), - JVMTI_EVENT_MONITOR_WAITED(false, true, 3), - JVMTI_EVENT_MONITOR_CONTENDED_ENTER(false, true, 2), - JVMTI_EVENT_MONITOR_CONTENDED_ENTERED(false, true, 2), - JVMTI_EVENT_RESOURCE_EXHAUSTED(false, false, 3), - JVMTI_EVENT_GARBAGE_COLLECTION_START(false, true, 0), - JVMTI_EVENT_GARBAGE_COLLECTION_FINISH(false, true, 0), - JVMTI_EVENT_OBJECT_FREE(false, false, 1), - JVMTI_EVENT_VM_OBJECT_ALLOC(false, false, 4), - JVMTI_EVENT_SAMPLED_OBJECT_ALLOC(false, false, 4), - JVMTI_EVENT_VIRTUAL_THREAD_START(false, false, 1), - JVMTI_EVENT_VIRTUAL_THREAD_END(false, false, 1); + JVMTI_EVENT_VM_INIT(true, JvmtiEventFlags.Global), + JVMTI_EVENT_VM_DEATH(true, JvmtiEventFlags.Global), + JVMTI_EVENT_THREAD_START(false, JvmtiEventFlags.Global), + JVMTI_EVENT_THREAD_END(false), + JVMTI_EVENT_CLASS_FILE_LOAD_HOOK(false), + JVMTI_EVENT_CLASS_LOAD(false), + JVMTI_EVENT_CLASS_PREPARE(false), + JVMTI_EVENT_VM_START(true, JvmtiEventFlags.Global), + JVMTI_EVENT_EXCEPTION(false), + JVMTI_EVENT_EXCEPTION_CATCH(false), + JVMTI_EVENT_SINGLE_STEP(false), + JVMTI_EVENT_FRAME_POP(false), + JVMTI_EVENT_BREAKPOINT(false), + JVMTI_EVENT_FIELD_ACCESS(false), + JVMTI_EVENT_FIELD_MODIFICATION(false), + JVMTI_EVENT_METHOD_ENTRY(false), + JVMTI_EVENT_METHOD_EXIT(false), + JVMTI_EVENT_NATIVE_METHOD_BIND(false), + JVMTI_EVENT_COMPILED_METHOD_LOAD(false, JvmtiEventFlags.Global), + JVMTI_EVENT_COMPILED_METHOD_UNLOAD(false, JvmtiEventFlags.Global), + JVMTI_EVENT_DYNAMIC_CODE_GENERATED(false, JvmtiEventFlags.Global), + JVMTI_EVENT_DATA_DUMP_REQUEST(false, JvmtiEventFlags.Global), + JVMTI_EVENT_MONITOR_WAIT(false), + JVMTI_EVENT_MONITOR_WAITED(false), + JVMTI_EVENT_MONITOR_CONTENDED_ENTER(false), + JVMTI_EVENT_MONITOR_CONTENDED_ENTERED(false), + JVMTI_EVENT_RESOURCE_EXHAUSTED(false), + JVMTI_EVENT_GARBAGE_COLLECTION_START(false), + JVMTI_EVENT_GARBAGE_COLLECTION_FINISH(false), + JVMTI_EVENT_OBJECT_FREE(false), + JVMTI_EVENT_VM_OBJECT_ALLOC(false), + JVMTI_EVENT_SAMPLED_OBJECT_ALLOC(false), + JVMTI_EVENT_VIRTUAL_THREAD_START(false, JvmtiEventFlags.Global), + JVMTI_EVENT_VIRTUAL_THREAD_END(false); private final boolean isSupported; - private final boolean isGlobal; - private final int nbParameters; + private final int flags; - JvmtiEvent(boolean isGlobal, boolean isSupported, int nbParameters) { - this.isGlobal = isGlobal; + JvmtiEvent(boolean isSupported, JvmtiEventFlags... flags) { this.isSupported = isSupported; - this.nbParameters = nbParameters; + this.flags = EnumBitmask.computeBitmask(flags); } @@ -83,16 +84,25 @@ public boolean isSupported() { } public boolean isGlobal() { - return isGlobal; + return EnumBitmask.hasBit(flags, JvmtiEventFlags.Global); } - public int getNbParameters() { - return nbParameters; + public static long getBit(JvmtiEvent eventType) { + int index = eventType.getCValue() - JvmtiEvent.getMinEventType(); + assert index < 64; + return 1L << index; } + @CConstant("JVMTI_MIN_EVENT_TYPE_VAL") + public static native int getMinEventType(); + @CEnumValue public native int getCValue(); @CEnumLookup public static native JvmtiEvent fromValue(int value); + + private enum JvmtiEventFlags { + Global + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java index 8c0b1bafb384..3ae06a91fdac 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventCallbacks.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.core.jvmti.headers; -import com.oracle.svm.core.jni.headers.JNIObjectHandle; import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; @@ -33,6 +32,7 @@ import org.graalvm.word.PointerBase; import com.oracle.svm.core.jni.headers.JNIEnvironment; +import com.oracle.svm.core.jni.headers.JNIObjectHandle; /** * Only a small subset of the callbacks is supported at the moment. All unsupported callbacks use @@ -160,56 +160,56 @@ public interface JvmtiEventCallbacks extends PointerBase { interface JvmtiEventVMInitFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread); } interface JvmtiEventVMDeathFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); } interface JvmtiEventVMStartFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv); } interface JvmtiEventGarbageCollectionFinishFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv); + void invoke(JvmtiExternalEnv jvmtiEnv); } interface JvmtiEventGarbageCollectionStartFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv); + void invoke(JvmtiExternalEnv jvmtiEnv); } interface JvmtiEventThreadStartFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread); } interface JvmtiEventThreadEndFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread); } interface JvmtiEventMonitorWaitFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread, JNIObjectHandle obj, long timeout); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread, JNIObjectHandle obj, long timeout); } interface JvmtiEventMonitorWaitedFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread, JNIObjectHandle obj, boolean timedOut); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread jthread, JNIObjectHandle obj, boolean timedOut); } interface JvmtiEventMonitorContendedEnterFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread, JNIObjectHandle obj); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread, JNIObjectHandle obj); } interface JvmtiEventMonitorContendedEnteredFunctionPointer extends CFunctionPointer { @InvokeCFunctionPointer - int invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread, JNIObjectHandle obj); + void invoke(JvmtiExternalEnv jvmtiEnv, JNIEnvironment jniEnv, JThread thread, JNIObjectHandle obj); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java index af838468b647..730c147f9b72 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiEventMode.java @@ -29,9 +29,13 @@ @CContext(JvmtiDirectives.class) public final class JvmtiEventMode { + // Checkstyle: stop: MethodName + @CConstant public static native int JVMTI_ENABLE(); @CConstant public static native int JVMTI_DISABLE(); + + // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java index 100123ee74dd..7f657bd00d24 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiExtensionFunctionInfoPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jvmti.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JvmtiDirectives.class) @CPointerTo(JvmtiExtensionFunctionInfo.class) public interface JvmtiExtensionFunctionInfoPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java index 72796c0d3f38..f6c1c9847f05 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfo.java @@ -33,7 +33,7 @@ @CContext(JvmtiDirectives.class) @CStruct(value = "jvmtiFrameInfo", addStructKeyword = true) -public interface JvmtiFrameInfo extends PointerBase { +public interface JvmtiFrameInfo extends PointerBase { @CField("method") JNIMethodId getMethod(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java deleted file mode 100644 index d96a2d2827a9..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiFrameInfoPointer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.headers; - -import org.graalvm.nativeimage.c.struct.CPointerTo; -import org.graalvm.word.PointerBase; - -//TODO @dprcci REMOVE -@CPointerTo(JvmtiFrameInfo.class) -public interface JvmtiFrameInfoPointer extends PointerBase { -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java index 368eb3909c0d..8e22effb53f3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapObjectFilter.java @@ -29,6 +29,8 @@ @CContext(JvmtiDirectives.class) public final class JvmtiHeapObjectFilter { + // Checkstyle: stop: MethodName + @CConstant public static native int JVMTI_HEAP_OBJECT_TAGGED(); @@ -37,4 +39,6 @@ public final class JvmtiHeapObjectFilter { @CConstant public static native int JVMTI_HEAP_OBJECT_EITHER(); + + // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java index 66093d61609e..1300b932d0cf 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiHeapRootKind.java @@ -29,6 +29,8 @@ @CContext(JvmtiDirectives.class) public final class JvmtiHeapRootKind { + // Checkstyle: stop: MethodName + @CConstant public static native int JVMTI_HEAP_ROOT_JNI_GLOBAL(); @@ -49,4 +51,6 @@ public final class JvmtiHeapRootKind { @CConstant public static native int JVMTI_HEAP_ROOT_OTHER(); + + // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java index ed4f59e09f51..a8040229aa8f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiIterationControl.java @@ -29,6 +29,8 @@ @CContext(JvmtiDirectives.class) public final class JvmtiIterationControl { + // Checkstyle: stop: MethodName + @CConstant public static native int JVMTI_ITERATION_CONTINUE(); @@ -37,4 +39,6 @@ public final class JvmtiIterationControl { @CConstant public static native int JVMTI_ITERATION_ABORT(); + + // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java index 9f6cba611ffc..e1492de581c7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLineNumberEntryPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jvmti.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JvmtiDirectives.class) @CPointerTo(JvmtiLineNumberEntry.class) public interface JvmtiLineNumberEntryPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java index 1b73cc288526..8a52962b9e05 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiLocalVariableEntryPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jvmti.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JvmtiDirectives.class) @CPointerTo(JvmtiLocalVariableEntry.class) public interface JvmtiLocalVariableEntryPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java index 32e261e02259..3766c8f686bb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiMonitorStackDepthInfoPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jvmti.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JvmtiDirectives.class) @CPointerTo(JvmtiMonitorStackDepthInfo.class) public interface JvmtiMonitorStackDepthInfoPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java index 4fe89a2771e9..ca6cb54937ff 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiObjectReferenceKind.java @@ -29,6 +29,8 @@ @CContext(JvmtiDirectives.class) public final class JvmtiObjectReferenceKind { + // Checkstyle: stop: MethodName + @CConstant public static native int JVMTI_REFERENCE_CLASS(); @@ -55,4 +57,6 @@ public final class JvmtiObjectReferenceKind { @CConstant public static native int JVMTI_REFERENCE_CONSTANT_POOL(); + + // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java index 11dbdaef775f..9b82a1f24c5f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiPhase.java @@ -25,22 +25,22 @@ package com.oracle.svm.core.jvmti.headers; import org.graalvm.nativeimage.c.CContext; -import org.graalvm.nativeimage.c.constant.CConstant; +import org.graalvm.nativeimage.c.constant.CEnum; +import org.graalvm.nativeimage.c.constant.CEnumLookup; +import org.graalvm.nativeimage.c.constant.CEnumValue; @CContext(JvmtiDirectives.class) -public final class JvmtiPhase { - @CConstant - public static native int JVMTI_PHASE_ONLOAD(); +@CEnum("jvmtiPhase") +public enum JvmtiPhase { + JVMTI_PHASE_ONLOAD, + JVMTI_PHASE_PRIMORDIAL, + JVMTI_PHASE_START, + JVMTI_PHASE_LIVE, + JVMTI_PHASE_DEAD; - @CConstant - public static native int JVMTI_PHASE_PRIMORDIAL(); + @CEnumValue + public native int getCValue(); - @CConstant - public static native int JVMTI_PHASE_START(); - - @CConstant - public static native int JVMTI_PHASE_LIVE(); - - @CConstant - public static native int JVMTI_PHASE_DEAD(); + @CEnumLookup + public static native JvmtiPhase fromValue(int value); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java index 2ab061c8c911..c58a93f7013f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfo.java @@ -45,10 +45,10 @@ public interface JvmtiStackInfo extends PointerBase { int getState(); @CField("frame_buffer") - void setFrameInfo(JvmtiFrameInfoPointer frameInfo); + void setFrameInfo(JvmtiFrameInfo frameInfo); @CField("frame_buffer") - JvmtiFrameInfoPointer getFrameInfo(); + JvmtiFrameInfo getFrameInfo(); @CField("frame_count") void setFrameCount(int frameCount); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java index 86a506e8139b..6e7fe9ce3a84 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointer.java @@ -24,9 +24,11 @@ */ package com.oracle.svm.core.jvmti.headers; +import org.graalvm.nativeimage.c.CContext; import org.graalvm.nativeimage.c.struct.CPointerTo; import org.graalvm.word.PointerBase; +@CContext(JvmtiDirectives.class) @CPointerTo(JvmtiStackInfo.class) public interface JvmtiStackInfoPointer extends PointerBase { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java deleted file mode 100644 index 0775cc655966..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiStackInfoPointerPointer.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.headers; - -import org.graalvm.nativeimage.c.struct.CPointerTo; -import org.graalvm.word.PointerBase; - -@CPointerTo(JvmtiStackInfoPointer.class) -public interface JvmtiStackInfoPointerPointer extends PointerBase { -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java index 808f292619ff..c87b884b5485 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiThreadState.java @@ -24,28 +24,31 @@ */ package com.oracle.svm.core.jvmti.headers; -public enum JvmtiThreadState { - JVMTI_THREAD_STATE_ALIVE(0x0001), - JVMTI_THREAD_STATE_TERMINATED(0x0002), - JVMTI_THREAD_STATE_RUNNABLE(0x0004), - JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER(0x0400), - JVMTI_THREAD_STATE_WAITING(0x0080), - JVMTI_THREAD_STATE_WAITING_INDEFINITELY(0x0010), - JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT(0x0020), - JVMTI_THREAD_STATE_SLEEPING(0x0040), - JVMTI_THREAD_STATE_IN_OBJECT_WAIT(0x0100), - JVMTI_THREAD_STATE_PARKED(0x0200), - JVMTI_THREAD_STATE_SUSPENDED(0x100000), - JVMTI_THREAD_STATE_INTERRUPTED(0x200000), - JVMTI_THREAD_STATE_IN_NATIVE(0x400000); +import org.graalvm.nativeimage.c.CContext; +import org.graalvm.nativeimage.c.constant.CEnum; +import org.graalvm.nativeimage.c.constant.CEnumLookup; +import org.graalvm.nativeimage.c.constant.CEnumValue; - private final int internalValue; +@CContext(JvmtiDirectives.class) +@CEnum +public enum JvmtiThreadState { + JVMTI_THREAD_STATE_ALIVE, + JVMTI_THREAD_STATE_TERMINATED, + JVMTI_THREAD_STATE_RUNNABLE, + JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, + JVMTI_THREAD_STATE_WAITING, + JVMTI_THREAD_STATE_WAITING_INDEFINITELY, + JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT, + JVMTI_THREAD_STATE_SLEEPING, + JVMTI_THREAD_STATE_IN_OBJECT_WAIT, + JVMTI_THREAD_STATE_PARKED, + JVMTI_THREAD_STATE_SUSPENDED, + JVMTI_THREAD_STATE_INTERRUPTED, + JVMTI_THREAD_STATE_IN_NATIVE; - JvmtiThreadState(int internalValue) { - this.internalValue = internalValue; - } + @CEnumValue + public native int getCValue(); - public int getValue() { - return this.internalValue; - } + @CEnumLookup + public static native JvmtiThreadState fromValue(int value); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java index 2bcbc8f5ec0a..d7f907f3478b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/JvmtiVerboseFlag.java @@ -29,6 +29,8 @@ @CContext(JvmtiDirectives.class) public final class JvmtiVerboseFlag { + // Checkstyle: stop: MethodName + @CConstant public static native int JVMTI_VERBOSE_OTHER(); @@ -40,4 +42,6 @@ public final class JvmtiVerboseFlag { @CConstant public static native int JVMTI_VERBOSE_JNI(); + + // Checkstyle: resume } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java index af40e960e3b0..17c4ae4e5cc3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/headers/VoidPointerPointer.java @@ -30,4 +30,4 @@ @CPointerTo(VoidPointer.class) public interface VoidPointerPointer extends PointerBase { -} \ No newline at end of file +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java deleted file mode 100644 index b846b0053d6b..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiLocalStorageUtil.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.utils; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.word.ComparableWord; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.jvmti.JvmtiMemoryManager; -import com.oracle.svm.core.locks.VMMutex; -import com.oracle.svm.core.nmt.NmtCategory; - -public class JvmtiLocalStorageUtil implements JvmtiMemoryManager { - - private final VMMutex mutex; - private NonmovableMap localStorage; - - @Platforms(Platform.HOSTED_ONLY.class) - public JvmtiLocalStorageUtil(String mutexName) { - mutex = new VMMutex(mutexName); - } - - public void initialize(int initialCapacity) { - localStorage = NonmovableMaps.createMap(initialCapacity, NmtCategory.JVMTI); - NonmovableMaps.fillValuesWithDefault(localStorage, WordFactory.nullPointer(), 0, initialCapacity); - } - - public void tearDown() { - NonmovableMaps.releaseMap(localStorage); - } - - public final void put(K key, V value) { - try { - mutex.lock(); - NonmovableMaps.put(localStorage, key, value); - } finally { - mutex.unlock(); - } - } - - public final V get(K externalEnv) { - try { - mutex.lock(); - return NonmovableMaps.get(localStorage, externalEnv); - } finally { - mutex.unlock(); - } - } - - public final boolean contains(K externalEnv) { - try { - mutex.lock(); - return NonmovableMaps.contains(localStorage, externalEnv); - } finally { - mutex.unlock(); - } - } - - @Override - public void releaseAllUnmanagedMemory() { - NonmovableMaps.releaseMap(localStorage); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java deleted file mode 100644 index 08025fd78745..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUninterruptibleUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.utils; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.type.CCharPointer; -import org.graalvm.nativeimage.c.type.CCharPointerPointer; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.Pointer; -import org.graalvm.word.UnsignedWord; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.heap.RestrictHeapAccess; -import com.oracle.svm.core.jvmti.headers.JvmtiError; - -public class JvmtiUninterruptibleUtils { - - private JvmtiUninterruptibleUtils() { - } - - @RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "jvmti") - public static JvmtiError writeStringToCCharArray(char[] buffer, int endIndex, CCharPointerPointer charPtr, ReplaceDotWithSlash replacer) { - if (endIndex <= 0) { - return JvmtiError.JVMTI_ERROR_INTERNAL; - } - UnsignedWord bufferSize = WordFactory.unsigned(com.oracle.svm.core.jdk.UninterruptibleUtils.String.modifiedUTF8LengthCharArray(buffer, endIndex, true, replacer)); - CCharPointer cStringBuffer = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(bufferSize); - if (cStringBuffer.isNull()) { - charPtr.write(WordFactory.nullPointer()); - return JvmtiError.JVMTI_ERROR_OUT_OF_MEMORY; - } - - com.oracle.svm.core.jdk.UninterruptibleUtils.String.toModifiedUTF8FromCharArray(buffer, endIndex, (Pointer) cStringBuffer, ((Pointer) cStringBuffer).add(bufferSize), true, replacer); - charPtr.write(cStringBuffer); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static class ReplaceDotWithSlash implements com.oracle.svm.core.jdk.UninterruptibleUtils.CharReplacer { - @Override - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public char replace(char ch) { - if (ch == '.') { - return '/'; - } - return ch; - } - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java deleted file mode 100644 index 89d43ecfd9db..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/JvmtiUtils.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.utils; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.ComparableWord; -import org.graalvm.word.Pointer; -import org.graalvm.word.PointerBase; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.config.ConfigurationValues; - -public final class JvmtiUtils { - - private JvmtiUtils() { - } - - @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") - public static T allocateWordBuffer(int nbElements) { - int size = nbElements * ConfigurationValues.getTarget().wordSize; - T allocatedPtr = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(WordFactory.unsigned(size)); - if (allocatedPtr.isNull()) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(allocatedPtr); - return WordFactory.nullPointer(); - } - return allocatedPtr; - } - - @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") - public static void writeWordAtIdxInBuffer(T array, int index, P element) { - ((Pointer) array).writeWord(index * ConfigurationValues.getTarget().wordSize, element); - } - - @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") - public static T growWordBuffer(T buffer, int newNbElements) { - return ImageSingletons.lookup(UnmanagedMemorySupport.class).realloc(buffer, WordFactory.unsigned(newNbElements * ConfigurationValues.getTarget().wordSize)); - } - - @Uninterruptible(reason = "jvmti unmanaged memory buffer utils") - public static void freeWordBuffer(T buffer) { - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(buffer); - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java deleted file mode 100644 index a15605fd9e66..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMap.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.utils; - -import org.graalvm.nativeimage.c.struct.RawField; -import org.graalvm.nativeimage.c.struct.RawStructure; -import org.graalvm.word.PointerBase; - -import com.oracle.svm.core.c.NonmovableArray; - -@RawStructure -public interface NonmovableMap extends PointerBase { - @RawField - NonmovableArray getKeyArray(); - - @RawField - void setKeyArray(NonmovableArray keyArray); - - @RawField - NonmovableArray getValueArray(); - - @RawField - void setValueArray(NonmovableArray valueArray); - - @RawField - int getNextAvailableIndex(); - - @RawField - void setNextAvailableIndex(int index); - - @RawField - int getCurrentSize(); - - @RawField - void setCurrentSize(int size); -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java deleted file mode 100644 index 70e958f2912f..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jvmti/utils/NonmovableMaps.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.jvmti.utils; - -import java.util.NoSuchElementException; - -import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.struct.SizeOf; -import org.graalvm.nativeimage.impl.UnmanagedMemorySupport; -import org.graalvm.word.ComparableWord; -import org.graalvm.word.WordFactory; - -import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.c.NonmovableArray; -import com.oracle.svm.core.c.NonmovableArrays; -import com.oracle.svm.core.jdk.UninterruptibleUtils; -import com.oracle.svm.core.nmt.NmtCategory; - -import jdk.graal.compiler.word.Word; - -public final class NonmovableMaps { - private static final UninterruptibleUtils.AtomicLong runtimeArraysInExistence = new UninterruptibleUtils.AtomicLong(0); - private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Could not allocate nonmovable array"); - private static final NoSuchElementException NO_SUCH_ELEMENT_EXCEPTION = new NoSuchElementException("element is not in the map"); - - private static final int ARRAY_FULL = -1; - private static final int ARRAY_GROWTH_FACTOR = 2; - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static NonmovableMap createMap(int initialCapacity, NmtCategory nmtCategory) { - assert initialCapacity > 0; - NonmovableMap map = ImageSingletons.lookup(UnmanagedMemorySupport.class).calloc(WordFactory.unsigned(SizeOf.get(NonmovableMap.class))); - if (map.isNull()) { - throw OUT_OF_MEMORY_ERROR; - } - NonmovableArray keyArray = NonmovableArrays.createWordArray(initialCapacity, nmtCategory); - NonmovableArray valueArray = NonmovableArrays.createWordArray(initialCapacity, nmtCategory); - if (keyArray.isNull() || valueArray.isNull()) { - throw OUT_OF_MEMORY_ERROR; - } - map.setKeyArray(keyArray); - map.setValueArray(valueArray); - map.setNextAvailableIndex(0); - map.setCurrentSize(initialCapacity); - runtimeArraysInExistence.incrementAndGet(); - return map; - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static void releaseMap(NonmovableMap map) { - NonmovableArrays.releaseUnmanagedArray(map.getKeyArray()); - NonmovableArrays.releaseUnmanagedArray(map.getValueArray()); - ImageSingletons.lookup(UnmanagedMemorySupport.class).free(map); - assert map.isNull() || runtimeArraysInExistence.getAndDecrement() > 0; - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static void fillValuesWithDefault(NonmovableMap map, V defaultValue, int start, int end) { - assert map.isNonNull(); - assert map.getCurrentSize() > end; - for (int i = start; i < end; i++) { - NonmovableArrays.setWord(map.getValueArray(), i, defaultValue); - } - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static void put(NonmovableMap map, K key, V value) { - put(map, key, value, true); - } - - // increase the size if at full capacity - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static void put(NonmovableMap map, K key, V value, boolean growIfFull) { - if (map.getCurrentSize() == ARRAY_FULL) { - if (growIfFull) { - growAndFillMap(map, WordFactory.nullPointer()); - } else { - return; - } - } - NonmovableArray keyArray = map.getKeyArray(); - NonmovableArray valueArray = map.getValueArray(); - assert valueArray.isNonNull() && keyArray.isNonNull(); - - int nextAvailableIndex = map.getNextAvailableIndex(); - NonmovableArrays.setWord(keyArray, nextAvailableIndex, key); - NonmovableArrays.setWord(valueArray, nextAvailableIndex, value); - map.setNextAvailableIndex(nextAvailableIndex + 1); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static boolean contains(NonmovableMap map, K key) { - int filledMapSize = map.getNextAvailableIndex(); - int i = 0; - Word current = WordFactory.zero(); - while (i < filledMapSize && current.notEqual(key)) { - current = (Word) NonmovableArrays.getWord(map.getKeyArray(), i); - i++; - } - return !(i == map.getCurrentSize() && current.notEqual(key)); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static V get(NonmovableMap map, K key) { - int filledMapSize = map.getNextAvailableIndex(); - int i = 0; - Word current = WordFactory.zero(); - while (i < filledMapSize && (current = (Word) NonmovableArrays.getWord(map.getKeyArray(), i)).notEqual(key)) { - i++; - } - if (i == map.getCurrentSize() && current.notEqual(key)) { - throw NO_SUCH_ELEMENT_EXCEPTION; - } - return NonmovableArrays.getWord(map.getValueArray(), i); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private static void growAndFillMap(NonmovableMap map, V defaultValue) { - int oldSize = map.getCurrentSize(); - growMap(map, NmtCategory.JVMTI); - fillValuesWithDefault(map, defaultValue, oldSize, map.getCurrentSize()); - } - - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - private static void growMap(NonmovableMap map, NmtCategory nmtCategory) { - int oldSize = map.getCurrentSize(); - int newMapSize = oldSize * ARRAY_GROWTH_FACTOR; - - NonmovableArray keyArray = map.getKeyArray(); - NonmovableArray valueArray = map.getValueArray(); - - assert valueArray.isNonNull() && keyArray.isNonNull(); - - NonmovableArray newKeyArray = NonmovableArrays.createWordArray(newMapSize, nmtCategory); - NonmovableArrays.arraycopy(keyArray, 0, newKeyArray, 0, oldSize); - NonmovableArrays.releaseUnmanagedArray(keyArray); - - NonmovableArray newValueArray = NonmovableArrays.createWordArray(newMapSize, nmtCategory); - NonmovableArrays.arraycopy(valueArray, 0, newValueArray, 0, oldSize); - NonmovableArrays.releaseUnmanagedArray(valueArray); - - map.setKeyArray(keyArray); - map.setValueArray(newValueArray); - map.setNextAvailableIndex(oldSize); - map.setCurrentSize(newMapSize); - } - -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java index dcac6d7dee63..8461d24bc788 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitor.java @@ -32,7 +32,6 @@ import java.util.concurrent.locks.ReentrantLock; -import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.IsolateThread; import com.oracle.svm.core.Uninterruptible; @@ -71,7 +70,7 @@ public JavaMonitor() { public void monitorEnter(Object obj) { if (!tryLock()) { long startTicks = JfrTicks.elapsedTicks(); - acquire(1, obj); + acquire(1); JavaMonitorEnterEvent.emit(obj, latestJfrTid, startTicks); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java index b77e3bdb57a7..2e034ef9b3ba 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JavaMonitorQueuedSynchronizer.java @@ -34,7 +34,6 @@ import com.oracle.svm.core.jfr.JfrTicks; import com.oracle.svm.core.jfr.SubstrateJVM; import com.oracle.svm.core.jfr.events.JavaMonitorWaitEvent; -import com.oracle.svm.core.jvmti.JvmtiPostEvents; import com.oracle.svm.core.thread.JavaThreads; import com.oracle.svm.core.util.BasedOnJDKClass; @@ -433,11 +432,9 @@ private int cancelAcquire(Node node) { protected abstract boolean isHeldExclusively(); // see AbstractQueuedLongSynchronizer.acquire(long) - protected final void acquire(long arg, Object obj) { + protected final void acquire(long arg) { if (!tryAcquire(arg)) { - JvmtiPostEvents.postMonitorContendedEnter(Thread.currentThread(), obj); acquire(null, arg); - JvmtiPostEvents.postMonitorContendedEntered(Thread.currentThread(), obj); } } @@ -647,7 +644,6 @@ public boolean await(Object obj, long time, TimeUnit unit) throws InterruptedExc } node.clearStatus(); // waiting is done, emit wait event - JvmtiPostEvents.postMonitorWaited(Thread.currentThread(), obj, cancelled); JavaMonitorWaitEvent.emit(startTicks, obj, node.notifierJfrTid, time, cancelled); acquire(node, savedAcquisitions); if (cancelled) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java deleted file mode 100644 index ae9c722fd4e0..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/JvmtiRawMonitorHelper.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023, 2023, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package com.oracle.svm.core.monitor; - -import com.oracle.svm.core.jvmti.headers.JvmtiError; - -public class JvmtiRawMonitorHelper { - - public static JvmtiError getOrCreateRawMonitor(Object obj) { - MonitorSupport monitorSupport = MonitorSupport.singleton(); - if (!(monitorSupport instanceof MultiThreadedMonitorSupport multiThreadedMonitorSupport)) { - return JvmtiError.JVMTI_ERROR_INTERNAL; - } - multiThreadedMonitorSupport.getOrCreateMonitor(obj, MonitorInflationCause.JVMTI_CREATE); - return JvmtiError.JVMTI_ERROR_NONE; - } - - public static JvmtiError exitCompletely(Object obj) { - MonitorSupport monitorSupport = MonitorSupport.singleton(); - if (!(monitorSupport instanceof MultiThreadedMonitorSupport multiThreadedMonitorSupport)) { - return JvmtiError.JVMTI_ERROR_INTERNAL; - } - JavaMonitor monitor = multiThreadedMonitorSupport.getMonitor(obj); - boolean done; - try { - done = monitor.tryRelease(monitor.getAcquisitions()); - } catch (IllegalMonitorStateException e) { - return JvmtiError.JVMTI_ERROR_INTERNAL; - } - return done ? JvmtiError.JVMTI_ERROR_NONE : JvmtiError.JVMTI_ERROR_INTERRUPT; - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java index 463007e87a9f..a4ee24912a6d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorInflationCause.java @@ -35,15 +35,7 @@ public enum MonitorInflationCause { WAIT("Monitor Wait"), NOTIFY("Monitor Notify"), JNI_ENTER("JNI Monitor Enter"), - JNI_EXIT("JNI Monitor Exit"), - ///TODO @dprcci add?? - JVMTI_CREATE("JVMTI CreateRawMonitor"), - JVMTI_DESTROY("JVMTI DestroyRawMonitor"), - JVMTI_ENTER("JVMTI RawMonitorEnter"), - JVMTI_EXIT("JVMTI RawMonitorExit"), - JVMTI_WAIT("JVMTI RawMonitorWait"), - JVMTI_NOTIFY("JVMTI RawMonitorNotify"), - JVMTI_NOTIFYALL("JVMTI RawMonitorNotifyAll"); + JNI_EXIT("JNI Monitor Exit"); private final String text; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java index 9a9117656a00..be44935f7757 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Method.java @@ -72,9 +72,6 @@ public final class Target_java_lang_reflect_Method { @RecomputeFieldValue(kind = Kind.Reset) // Target_jdk_internal_reflect_MethodAccessor methodAccessorFromMetadata; - @Alias - public transient String signature; - @Alias @TargetElement(name = CONSTRUCTOR_NAME) @SuppressWarnings("hiding") diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java index b9c9b13600d4..60da2ca7d22e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java @@ -167,7 +167,7 @@ private ThreadGroupThreadsAccessor() { } } -public class JavaLangThreadGroupSubstitutions { +public class JavaLangThreadGroupSubstitutions { @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) public static ThreadGroup getParentThreadGroupUnsafe(ThreadGroup threadGroup) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java index 9743cf8dad60..2b19371ee09e 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java @@ -475,10 +475,4 @@ public static Thread getCurrentThreadOrNull() { Target_java_lang_Thread tjlt = SubstrateUtil.cast(thread, Target_java_lang_Thread.class); return (tjlt.vthread != null) ? tjlt.vthread : thread; } - - //TODO @dprcci might be illegal (check for inline value) - @Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true) - public static boolean isAlive(Thread thread){ - return PlatformThreads.isAlive(thread); - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java index 490aab8cd6d4..e8930ec79a07 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/PlatformThreads.java @@ -47,7 +47,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import com.oracle.svm.core.jvmti.JvmtiPostEvents; import org.graalvm.nativeimage.CurrentIsolate; import org.graalvm.nativeimage.ImageInfo; import org.graalvm.nativeimage.ImageSingletons; @@ -673,7 +672,6 @@ private static boolean isApplicationThread(IsolateThread isolateThread) { @SuppressFBWarnings(value = "NN", justification = "notifyAll is necessary for Java semantics, no shared state needs to be modified beforehand") public static void exit(Thread thread) { - JvmtiPostEvents.postThreadEnd(thread); ThreadListenerSupport.get().afterThreadRun(); /* @@ -787,7 +785,6 @@ protected static void freeStartData(ThreadStartData startData) { } void startThread(Thread thread, long stackSize) { - JvmtiPostEvents.postThreadStart(thread); boolean started = doStartThread(thread, stackSize); if (!started) { throw new OutOfMemoryError("Unable to create native thread: possibly out of memory or process/resource limits reached"); @@ -899,9 +896,7 @@ static StackTraceElement[] getStackTraceAtSafepoint(Thread thread, Pointer calle return StackTraceUtils.getStackTraceAtSafepoint(isolateThread); } - - //TODO @dprcci JVMTI - public static Pointer getCarrierSPOrElse(Thread carrier, Pointer other) { + static Pointer getCarrierSPOrElse(Thread carrier, Pointer other) { Target_jdk_internal_vm_Continuation cont = toTarget(carrier).cont; while (cont != null) { if (cont.getScope() == Target_java_lang_VirtualThread.VTHREAD_SCOPE) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java index ce7239960adb..dfb9325d404a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/HostedDynamicHubFeature.java @@ -24,17 +24,10 @@ */ package com.oracle.svm.hosted.ameta; -import java.util.List; - -import org.graalvm.nativeimage.hosted.Feature; - import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.hub.DynamicHub; -import com.oracle.svm.core.jvmti.JvmtiClassInfoUtil; -import com.oracle.svm.core.jvmti.JvmtiGenericInfoMapFeature; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.SVMHost; @@ -52,21 +45,10 @@ public void duringSetup(DuringSetupAccess a) { access.registerObjectReplacer(this::replace); } - @Override - public List> getRequiredFeatures() { - return List.of(JvmtiGenericInfoMapFeature.class); - } - private Object replace(Object source) { if (source instanceof Class) { Class clazz = (Class) source; DynamicHub dynamicHub = hostVM.dynamicHub(metaAccess.lookupJavaType(clazz)); - if (SubstrateOptions.JVMTI.getValue()) { - String signature = dynamicHub.getSignature(); - if (signature != null && clazz.getTypeParameters().length > 0) { - JvmtiClassInfoUtil.JVMTIGenericInfoMap.singleton().addSignature(clazz, signature); - } - } return dynamicHub; } return source; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java index 465e3403e658..f5ccebf38230 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java @@ -30,7 +30,6 @@ import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; -import org.graalvm.nativeimage.c.constant.CEnumValue; import org.graalvm.nativeimage.c.function.CFunction; import com.oracle.svm.core.AlwaysInline; @@ -220,7 +219,7 @@ private void checkCallees(HostedMethod caller, Uninterruptible callerAnnotation, System.lineSeparator() + invoke.getNodeSourcePosition()); } else { if (directCallerAnnotation.calleeMustBe()) { - if (!Uninterruptible.Utils.isUninterruptible(callee) && !AnnotationAccess.isAnnotationPresent(callee, CEnumValue.class)) { + if (!Uninterruptible.Utils.isUninterruptible(callee)) { violations.add("Unannotated callee: " + callee.format("%H.%n(%p):%r") + " called by annotated caller " + caller.format("%H.%n(%p):%r") + System.lineSeparator() + invoke.getNodeSourcePosition()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java index ae9369922d8b..fffdd5e340f7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java @@ -24,17 +24,6 @@ */ package com.oracle.svm.hosted.jvmti; -import com.oracle.svm.core.jvmti.JvmtiClassInfoUtil; -import com.oracle.svm.core.jvmti.JvmtiEnvManager; -import com.oracle.svm.core.jvmti.JvmtiEnvStorage; -import com.oracle.svm.core.jvmti.JvmtiManager; -import com.oracle.svm.core.jvmti.JvmtiMultiStackTracesUtil; -import com.oracle.svm.core.jvmti.JvmtiRawMonitorUtil; -import com.oracle.svm.core.jvmti.JvmtiThreadGroupUtil; -import com.oracle.svm.core.jvmti.JvmtiThreadLocalStorage; -import com.oracle.svm.core.jvmti.JvmtiThreadStateUtil; -import com.oracle.svm.core.jvmti.JvmtiGetThreadsUtil; -import com.oracle.svm.core.jvmti.JvmtiStackTraceUtil; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CEntryPoint; @@ -46,9 +35,12 @@ import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; +import com.oracle.svm.core.jdk.RuntimeSupport; import com.oracle.svm.core.jvmti.JvmtiAgents; +import com.oracle.svm.core.jvmti.JvmtiEnvs; import com.oracle.svm.core.jvmti.JvmtiFunctionTable; import com.oracle.svm.core.jvmti.JvmtiFunctions; +import com.oracle.svm.core.jvmti.JvmtiSupport; import com.oracle.svm.core.jvmti.headers.JvmtiInterface; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.option.SubstrateOptionsParser; @@ -69,6 +61,11 @@ import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; +/** + * Prepares the JVMTI infrastructure and puts it into the image so that JVMTI support is available + * at run-time. For more information on JVMTI in general, please refer to the + * specification. + */ @AutomaticallyRegisteredFeature public class JvmtiFeature implements InternalFeature { @Override @@ -78,14 +75,21 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public void duringSetup(DuringSetupAccess access) { - UserError.guarantee(SubstrateOptions.JNI.getValue(), "JVMTI needs JNI, so please enable the option " + SubstrateOptionsParser.commandArgument(SubstrateOptions.JNI, "+")); + UserError.guarantee(SubstrateOptions.JNI.getValue(), "JVMTI requires JNI. Please use option '%s' to enable JNI.", SubstrateOptionsParser.commandArgument(SubstrateOptions.JNI, "+")); + + ImageSingletons.add(JvmtiSupport.class, new JvmtiSupport()); + ImageSingletons.add(JvmtiAgents.class, new JvmtiAgents()); + ImageSingletons.add(JvmtiEnvs.class, new JvmtiEnvs()); + ImageSingletons.add(JvmtiFunctionTable.class, new JvmtiFunctionTable()); + + RuntimeSupport.getRuntimeSupport().addInitializationHook(JvmtiSupport.initializationHook()); + RuntimeSupport.getRuntimeSupport().addTearDownHook(JvmtiSupport.teardownHook()); } @Override public void beforeAnalysis(BeforeAnalysisAccess arg) { BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) arg; AnalysisMetaAccess metaAccess = access.getMetaAccess(); - JvmtiManager.registerAllJvmtiClasses(); registerCEntryPoints(metaAccess); }