From 1a935cb893d3af9a5cb24f85c3ab2fe7b7fa7d17 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Wed, 9 Oct 2024 01:09:15 +0000 Subject: [PATCH] 8341802: Add test coverage for JVMTI function with value classes --- .../ValueForceEarlyReturn.java | 155 ++++++++++++++++++ .../libValueForceEarlyReturn.cpp | 76 +++++++++ .../GetClassFields/ValueGetClassFields.java | 93 +++++++++++ .../GetClassFields/libValueGetClassFields.cpp | 78 +++++++++ .../ValueGetObjectMonitorUsage.java | 94 +++++++++++ .../libValueGetObjectMonitorUsage.cpp | 90 ++++++++++ .../GetObjectSize/ValueGetObjectSize.java | 94 +++++++++++ .../GetObjectSize/libValueGetObjectSize.cpp | 60 +++++++ .../GetSetLocal/ValueGetSetLocal.java | 92 +++++++++++ .../GetSetLocal/libValueGetSetLocal.cpp | 127 ++++++++++++++ 10 files changed, 959 insertions(+) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/ValueForceEarlyReturn.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/libValueForceEarlyReturn.cpp create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/ValueGetClassFields.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/libValueGetClassFields.cpp create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/ValueGetObjectMonitorUsage.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/libValueGetObjectMonitorUsage.cpp create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/ValueGetObjectSize.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/libValueGetObjectSize.cpp create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/ValueGetSetLocal.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/libValueGetSetLocal.cpp diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/ValueForceEarlyReturn.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/ValueForceEarlyReturn.java new file mode 100644 index 00000000000..8e32b1e3b4d --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/ValueForceEarlyReturn.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Sanity test for ForceEarlyReturn with value classes. + * @requires vm.jvmti + * @modules java.base/jdk.internal.vm.annotation + * @enablePreview + * @run main/othervm/native -agentlib:ValueForceEarlyReturn -XX:+EnableValhalla ValueForceEarlyReturn + */ + +import java.util.Objects; +import jdk.internal.vm.annotation.ImplicitlyConstructible; +import jdk.internal.vm.annotation.LooselyConsistentValue; +import jdk.internal.vm.annotation.NullRestricted; + +public class ValueForceEarlyReturn { + + private static final String agentLib = "ValueForceEarlyReturn"; + + @ImplicitlyConstructible + @LooselyConsistentValue + private static value class ValueClass { + public int f1; + public int f2; + + public ValueClass(int v1, int v2) { f1 = v1; f2 = v2; } + } + + private static value class ValueHolder { + public ValueClass f1; + @NullRestricted + public ValueClass f2; + + public static ValueClass s1 = new ValueClass(0, 1); + + public ValueHolder(int v) { + f1 = new ValueClass(v, v + 100); + f2 = new ValueClass(v + 1, v + 200); + } + } + + public static void main(String[] args) throws Exception { + try { + System.loadLibrary(agentLib); + } catch (UnsatisfiedLinkError ex) { + System.err.println("Failed to load " + agentLib + " lib"); + System.err.println("java.library.path: " + System.getProperty("java.library.path")); + throw ex; + } + + ValueClass testObj1 = new ValueClass(4, 5); + ValueHolder testObj2 = new ValueHolder(6); + + testForceEarlyReturn(testObj1); + testForceEarlyReturn(testObj2); + } + + private static void testForceEarlyReturn(Object retObject) throws Exception { + String className = retObject.getClass().getName(); + log(">> Testing ForceEarlyReturn for " + className); + + TestTask task = new TestTask(); + Thread thread = new Thread(task, "testThread"); + thread.start(); + + task.ensureReady(); + + nSuspendThread(thread); + nForceEarlyReturn(thread, retObject); + nResumeThread(thread); + + task.finish(); + thread.join(); + + Object result = task.getResult(); + + if (!Objects.equals(result, retObject)) { + throw new RuntimeException("ERROR: unexpected result (" + result + ", expected " + retObject + ")"); + } + log("<< Testing " + className + " - OK"); + log(""); + } + + private static class TestTask implements Runnable { + + private volatile boolean ready = false; + private volatile boolean doLoop = true; + private volatile Object result = null; + + private static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new RuntimeException("Interruption in TestTask.sleep: " + e); + } + } + + public void ensureReady() { + while (!ready) { + sleep(1); + } + } + + public void finish() { + doLoop = false; + } + + public Object getResult() { + return result; + } + + public void run() { + result = meth(); + } + + // Method is busy in a while loop. + private Object meth() { + ready = true; + while (doLoop) { + } + return null; + } + } + + private static void log(String msg) { + System.out.println(msg); + } + + static native void nSuspendThread(Thread thread); + static native void nResumeThread(Thread thread); + static native void nForceEarlyReturn(Thread thread, Object obj); + +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/libValueForceEarlyReturn.cpp b/test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/libValueForceEarlyReturn.cpp new file mode 100644 index 00000000000..cd0022544fd --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/ForceEarlyReturn/libValueForceEarlyReturn.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = nullptr; + + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == nullptr) { + LOG("GetEnv failed, res = %d", (int)res); + return JNI_ERR; + } + + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_suspend = 1; + caps.can_force_early_return = 1; + jvmtiError err = jvmti->AddCapabilities(&caps); + if (err != JVMTI_ERROR_NONE) { + LOG("AddCapabilities failed: %s (%d)\n", TranslateError(err), err); + return JNI_ERR; + } + + return JNI_OK; +} + +JNIEXPORT void JNICALL +Java_ValueForceEarlyReturn_nSuspendThread(JNIEnv *jni, jclass thisClass, jthread thread) { + suspend_thread(jvmti, jni, thread); +} + +JNIEXPORT void JNICALL +Java_ValueForceEarlyReturn_nResumeThread(JNIEnv *jni, jclass thisClass, jthread thread) { + resume_thread(jvmti, jni, thread); +} + +JNIEXPORT void JNICALL +Java_ValueForceEarlyReturn_nForceEarlyReturn(JNIEnv *jni, jclass thisClass, jthread thread, jobject obj) { + check_jvmti_error(jvmti->ForceEarlyReturnObject(thread, obj), "ForceEarlyReturnObject"); +} + +#ifdef __cplusplus +} +#endif + diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/ValueGetClassFields.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/ValueGetClassFields.java new file mode 100644 index 00000000000..6662cd565b7 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/ValueGetClassFields.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Sanity test for GetClassFields with value classes. + * @requires vm.jvmti + * @modules java.base/jdk.internal.vm.annotation + * @enablePreview + * @run main/othervm/native -agentlib:ValueGetClassFields -XX:+EnableValhalla ValueGetClassFields + */ + +import jdk.internal.vm.annotation.ImplicitlyConstructible; +import jdk.internal.vm.annotation.LooselyConsistentValue; +import jdk.internal.vm.annotation.NullRestricted; + +public class ValueGetClassFields { + + private static final String agentLib = "ValueGetClassFields"; + + @ImplicitlyConstructible + @LooselyConsistentValue + private static value class ValueClass { + public int f1; + public int f2; + + public ValueClass(int v1, int v2) { f1 = v1; f2 = v2; } + } + + private static value class ValueHolder { + public ValueClass f1; + @NullRestricted + public ValueClass f2; + + public static ValueClass s1 = new ValueClass(0, 1); + + public ValueHolder(int v) { + f1 = new ValueClass(v, v + 100); + f2 = new ValueClass(v + 1, v + 200); + } + } + + public static void main(String[] args) throws Exception { + try { + System.loadLibrary(agentLib); + } catch (UnsatisfiedLinkError ex) { + System.err.println("Failed to load " + agentLib + " lib"); + System.err.println("java.library.path: " + System.getProperty("java.library.path")); + throw ex; + } + + testGetClassFields(ValueClass.class, 2); + testGetClassFields(ValueHolder.class, 3); + } + + private static void testGetClassFields(Class cls, int fieldNum) throws Exception { + String className = cls.getName(); + // Ensure the class is prepared. + cls = Class.forName(className); + log(">> Testing GetClassFields for " + className); + if (!nTestGetClassFields(cls, fieldNum)) { + throw new RuntimeException("ERROR: " + className); + } + log("<< Testing " + className + " - OK"); + log(""); + } + + private static void log(String msg) { + System.out.println(msg); + } + + private static native boolean nTestGetClassFields(Class cls, int fieldNum); +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/libValueGetClassFields.cpp b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/libValueGetClassFields.cpp new file mode 100644 index 00000000000..79e1cd513a0 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetClassFields/libValueGetClassFields.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = nullptr; + + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == nullptr) { + LOG("GetEnv failed, res = %d", (int)res); + return JNI_ERR; + } + return JNI_OK; +} + +JNIEXPORT jboolean JNICALL +Java_ValueGetClassFields_nTestGetClassFields(JNIEnv *jni, jclass thisClass, jclass cls, jint fieldNum) { + bool result = true; + jint field_count; + jfieldID* fields = nullptr; + check_jvmti_error(jvmti->GetClassFields(cls, &field_count, &fields), "GetClassFields"); + + if (field_count != fieldNum) { + LOG("ERROR: GetClassFields returned unexpected field count: %d (expected %d)\n", (int)field_count, (int)fieldNum); + result = false; + } else { + // Use GetFieldName to verify correctness of the returned fields. + for (jint i = 0; i < field_count; i++) { + char *name = nullptr; + char *signature = nullptr; + + check_jvmti_error(jvmti->GetFieldName(cls, fields[i], &name, &signature, nullptr), "GetFieldName"); + + LOG(" - field %s, sig = %s\n", name, signature); + jvmti->Deallocate((unsigned char *)name); + jvmti->Deallocate((unsigned char *)signature); + } + } + + jvmti->Deallocate((unsigned char *)fields); + return result ? JNI_TRUE : JNI_FALSE; +} + +#ifdef __cplusplus +} +#endif + diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/ValueGetObjectMonitorUsage.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/ValueGetObjectMonitorUsage.java new file mode 100644 index 00000000000..ce4c9218ca0 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/ValueGetObjectMonitorUsage.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Sanity test for GetObjectMonitorUsage with value classes. + * @requires vm.jvmti + * @modules java.base/jdk.internal.vm.annotation + * @enablePreview + * @run main/othervm/native -agentlib:ValueGetObjectMonitorUsage -XX:+EnableValhalla ValueGetObjectMonitorUsage + */ + +import jdk.internal.vm.annotation.ImplicitlyConstructible; +import jdk.internal.vm.annotation.LooselyConsistentValue; +import jdk.internal.vm.annotation.NullRestricted; + +public class ValueGetObjectMonitorUsage { + + private static final String agentLib = "ValueGetObjectMonitorUsage"; + + @ImplicitlyConstructible + @LooselyConsistentValue + private static value class ValueClass { + public int f1; + public int f2; + + public ValueClass(int v1, int v2) { f1 = v1; f2 = v2; } + } + + private static value class ValueHolder { + public ValueClass f1; + @NullRestricted + public ValueClass f2; + + public static ValueClass s1 = new ValueClass(0, 1); + + public ValueHolder(int v) { + f1 = new ValueClass(v, v + 100); + f2 = new ValueClass(v + 1, v + 200); + } + } + + public static void main(String[] args) throws Exception { + try { + System.loadLibrary(agentLib); + } catch (UnsatisfiedLinkError ex) { + System.err.println("Failed to load " + agentLib + " lib"); + System.err.println("java.library.path: " + System.getProperty("java.library.path")); + throw ex; + } + + ValueClass testObj1 = new ValueClass(4, 5); + ValueHolder testObj2 = new ValueHolder(6); + + testGetObjectMonitorUsage(testObj1); + testGetObjectMonitorUsage(testObj2); + } + + private static void testGetObjectMonitorUsage(Object testObj) { + String className = testObj.getClass().getName(); + log(">> Testing GetObjectMonitorUsage for " + className); + if (!nTestGetObjectMonitorUsage(testObj)) { + throw new RuntimeException("ERROR: " + className); + } + log("<< Testing " + className + " - OK"); + log(""); + } + + private static void log(String msg) { + System.out.println(msg); + } + + private static native boolean nTestGetObjectMonitorUsage(Object obj); +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/libValueGetObjectMonitorUsage.cpp b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/libValueGetObjectMonitorUsage.cpp new file mode 100644 index 00000000000..2b8c434c708 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectMonitorUsage/libValueGetObjectMonitorUsage.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = nullptr; + + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == nullptr) { + LOG("GetEnv failed, res = %d", (int)res); + return JNI_ERR; + } + + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_get_monitor_info = 1; + jvmtiError err = jvmti->AddCapabilities(&caps); + if (err != JVMTI_ERROR_NONE) { + LOG("AddCapabilities failed: %s (%d)\n", TranslateError(err), err); + return JNI_ERR; + } + + return JNI_OK; +} + +JNIEXPORT jboolean JNICALL +Java_ValueGetObjectMonitorUsage_nTestGetObjectMonitorUsage(JNIEnv *jni, jclass thisClass, jobject obj) { + bool result = true; + jvmtiMonitorUsage info; + memset(&info, 0, sizeof(info)); + check_jvmti_error(jvmti->GetObjectMonitorUsage(obj, &info), "GetObjectMonitorUsage"); + + if (info.owner != nullptr) { + LOG("ERROR: owner is not NULL\n"); + result = false; + } + if (info.entry_count != 0) { + LOG("ERROR: entry_count is non-zero: %d\n", (int)info.entry_count); + result = false; + } + if (info.waiter_count != 0) { + LOG("ERROR: waiter_count is no-zero: %d\n", (int)info.waiter_count); + result = false; + } + if (info.notify_waiter_count != 0) { + LOG("ERROR: notify_waiter_count is no-zero: %d\n", (int)info.notify_waiter_count); + result = false; + } + + jvmti->Deallocate((unsigned char *)info.waiters); + jvmti->Deallocate((unsigned char *)info.notify_waiters); + + return result ? JNI_TRUE : JNI_FALSE; +} + +#ifdef __cplusplus +} +#endif + diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/ValueGetObjectSize.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/ValueGetObjectSize.java new file mode 100644 index 00000000000..32c9706956e --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/ValueGetObjectSize.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Sanity test for GetObjectSize with values classes. + * @requires vm.jvmti + * @modules java.base/jdk.internal.vm.annotation + * @enablePreview + * @run main/othervm/native -agentlib:ValueGetObjectSize -XX:+EnableValhalla ValueGetObjectSize + */ + +import jdk.internal.vm.annotation.ImplicitlyConstructible; +import jdk.internal.vm.annotation.LooselyConsistentValue; +import jdk.internal.vm.annotation.NullRestricted; + +public class ValueGetObjectSize { + + private static final String agentLib = "ValueGetObjectSize"; + + @ImplicitlyConstructible + @LooselyConsistentValue + private static value class ValueClass { + public int f1; + public int f2; + + public ValueClass(int v1, int v2) { f1 = v1; f2 = v2; } + } + + private static value class ValueHolder { + public ValueClass f1; + @NullRestricted + public ValueClass f2; + + public static ValueClass s1 = new ValueClass(0, 1); + + public ValueHolder(int v) { + f1 = new ValueClass(v, v + 100); + f2 = new ValueClass(v + 1, v + 200); + } + } + + public static void main(String[] args) throws Exception { + try { + System.loadLibrary(agentLib); + } catch (UnsatisfiedLinkError ex) { + System.err.println("Failed to load " + agentLib + " lib"); + System.err.println("java.library.path: " + System.getProperty("java.library.path")); + throw ex; + } + + ValueClass testObj1 = new ValueClass(4, 5); + ValueHolder testObj2 = new ValueHolder(6); + + testGetObjectSize(testObj1); + testGetObjectSize(testObj2); + } + + private static void testGetObjectSize(Object testObj) { + String className = testObj.getClass().getName(); + log(">> Testing GetObjectSize for " + className); + if (!nTestGetObjectSize(testObj)) { + throw new RuntimeException("ERROR: " + className); + } + log("<< Testing " + className + " - OK"); + log(""); + } + + private static void log(String msg) { + System.out.println(msg); + } + + private static native boolean nTestGetObjectSize(Object obj); +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/libValueGetObjectSize.cpp b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/libValueGetObjectSize.cpp new file mode 100644 index 00000000000..bfd056c9bfe --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectSize/libValueGetObjectSize.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = nullptr; + + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == nullptr) { + LOG("GetEnv failed, res = %d", (int)res); + return JNI_ERR; + } + return JNI_OK; +} + +JNIEXPORT jboolean JNICALL +Java_ValueGetObjectSize_nTestGetObjectSize(JNIEnv *jni, jclass thisClass, jobject obj) { + jlong size = 0; + check_jvmti_error(jvmti->GetObjectSize(obj, &size), "GetObjectSize"); + + LOG(" GetObjectSize returned %d\n", (int)size); + + return JNI_TRUE; +} + +#ifdef __cplusplus +} +#endif + diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/ValueGetSetLocal.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/ValueGetSetLocal.java new file mode 100644 index 00000000000..5c47b177573 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/ValueGetSetLocal.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Sanity tests for GetLocalObject/SetLocalObject/GetLocalInstance with value classes. + * @requires vm.jvmti + * @modules java.base/jdk.internal.vm.annotation + * @enablePreview + * @run main/othervm/native -agentlib:ValueGetSetLocal -XX:+EnableValhalla ValueGetSetLocal + */ + +import java.util.Objects; +import jdk.internal.vm.annotation.ImplicitlyConstructible; +import jdk.internal.vm.annotation.LooselyConsistentValue; +import jdk.internal.vm.annotation.NullRestricted; + +public class ValueGetSetLocal { + + private static final String agentLib = "ValueGetSetLocal"; + + @ImplicitlyConstructible + @LooselyConsistentValue + private static value class ValueClass { + public int f1; + public int f2; + + public ValueClass(int v1, int v2) { f1 = v1; f2 = v2; } + } + + private static value class ValueHolder { + public ValueClass f1; + @NullRestricted + public ValueClass f2; + + public static ValueClass s1 = new ValueClass(0, 1); + + public ValueHolder(int v) { + f1 = new ValueClass(v, v + 100); + f2 = new ValueClass(v + 1, v + 200); + } + + // slot 0 is "this" + public void meth(ValueClass obj1, // slot 1 + ValueHolder obj2) { // slot 2 + Object obj3 = obj2; // slot 3 + if (!nTestLocals(Thread.currentThread())) { + throw new RuntimeException("ERROR: nTestLocals failed"); + } + // nTestLocals sets obj3 = obj1 + if (!Objects.equals(obj3, obj1)) { + throw new RuntimeException("ERROR: obj3 != obj1" + " (obj3 = " + obj3 + ")"); + } + } + } + + public static void main(String[] args) throws Exception { + try { + System.loadLibrary(agentLib); + } catch (UnsatisfiedLinkError ex) { + System.err.println("Failed to load " + agentLib + " lib"); + System.err.println("java.library.path: " + System.getProperty("java.library.path")); + throw ex; + } + + ValueClass testObj1 = new ValueClass(7, 8); + ValueHolder testObj2 = new ValueHolder(9); + testObj2.meth(testObj1, testObj2); + } + + private static native boolean nTestLocals(Thread thread); +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/libValueGetSetLocal.cpp b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/libValueGetSetLocal.cpp new file mode 100644 index 00000000000..254a33e61da --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetSetLocal/libValueGetSetLocal.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jni.h" +#include "jvmti_common.hpp" + +#ifdef __cplusplus +extern "C" { +#endif + +static jvmtiEnv *jvmti = nullptr; + + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + jint res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == nullptr) { + LOG("GetEnv failed, res = %d", (int)res); + return JNI_ERR; + } + + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_access_local_variables = 1; + jvmtiError err = jvmti->AddCapabilities(&caps); + if (err != JVMTI_ERROR_NONE) { + LOG("AddCapabilities failed: %s (%d)\n", TranslateError(err), err); + return JNI_ERR; + } + + return JNI_OK; +} + +static void log_value(JNIEnv *jni, jobject value) { + jclass cls = jni->GetObjectClass(value); + if (cls == nullptr) { + LOG("ERROR: value class is NULL\n"); + return; + } + + char* sig = nullptr; + check_jvmti_error(jvmti->GetClassSignature(cls, &sig, nullptr), "GetClassSignature"); + + LOG(" - the value class: %s\n", sig); + jvmti->Deallocate((unsigned char *)sig); +} + +static jobject get_local(JNIEnv *jni, jthread thread, jint depth, jint slot) { + LOG("GetLocalObject for slot %d...\n", (int)slot); + jobject value = nullptr; + check_jvmti_error(jvmti->GetLocalObject(thread, depth, slot, &value), "GetLocalObject"); + + log_value(jni, value); + + return value; +} + +static void set_local(jthread thread, jint depth, jint slot, jobject value) { + LOG("SetLocalObject for slot %d...\n", (int)slot); + check_jvmti_error(jvmti->SetLocalObject(thread, depth, slot, value), "SetLocalObject"); +} + +static jobject get_this(JNIEnv *jni, jthread thread, jint depth) { + LOG("GetLocalInstance...\n"); + jobject value = nullptr; + check_jvmti_error(jvmti->GetLocalInstance(thread, depth, &value), "GetLocalInstance"); + + log_value(jni, value); + + return value; +} + +JNIEXPORT jboolean JNICALL +Java_ValueGetSetLocal_nTestLocals(JNIEnv *jni, jclass thisClass, jthread thread) { + bool result = true; + const jint depth = 1; + + jobject obj0 = get_local(jni, thread, depth, 0); + jobject obj1 = get_local(jni, thread, depth, 1); + jobject obj2 = get_local(jni, thread, depth, 2); + jobject obj3 = get_local(jni, thread, depth, 3); + jobject obj_this = get_this(jni, thread, depth); + + // obj0 is expected to be equal "this" + if (!jni->IsSameObject(obj0, obj_this)) { + LOG("ERROR: obj0 != obj_this\n"); + result = false; + } + // obj3 is expected to be equal obj2 + if (!jni->IsSameObject(obj3, obj2)) { + LOG("ERROR: obj3 != obj2\n"); + result = false; + } + + // set obj3 = obj1 + set_local(thread, depth, 3, obj1); + + return result ? JNI_TRUE : JNI_FALSE; +} + +#ifdef __cplusplus +} +#endif +