163 lines
8.2 KiB
Diff
163 lines
8.2 KiB
Diff
Subject: Backport JDK-8335638 Calling VarHandle.{access-mode} methods reflectively throws wrong exception
|
|
|
|
---
|
|
src/hotspot/share/prims/methodHandles.cpp | 59 ++++++++++++++++++-
|
|
.../VarHandles/VarHandleTestReflection.java | 25 +++++++-
|
|
2 files changed, 78 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp
|
|
index f6412504a..55a6b3286 100644
|
|
--- a/src/hotspot/share/prims/methodHandles.cpp
|
|
+++ b/src/hotspot/share/prims/methodHandles.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2008, 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
|
|
@@ -1362,6 +1362,18 @@ JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv* env, jobject mh, jobjectArray args
|
|
}
|
|
JVM_END
|
|
|
|
+/**
|
|
+ * Throws a java/lang/UnsupportedOperationException unconditionally.
|
|
+ * This is required by the specification of VarHandle.{access-mode} if
|
|
+ * invoked directly.
|
|
+ */
|
|
+JVM_ENTRY(jobject, VH_UOE(JNIEnv* env, jobject vh, jobjectArray args)) {
|
|
+ THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "VarHandle access mode methods cannot be invoked reflectively");
|
|
+ return nullptr;
|
|
+}
|
|
+JVM_END
|
|
+
|
|
+
|
|
/// JVM_RegisterMethodHandleMethods
|
|
|
|
#define LANG "Ljava/lang/"
|
|
@@ -1401,6 +1413,40 @@ static JNINativeMethod MH_methods[] = {
|
|
{CC "invoke", CC "([" OBJ ")" OBJ, FN_PTR(MH_invoke_UOE)},
|
|
{CC "invokeExact", CC "([" OBJ ")" OBJ, FN_PTR(MH_invokeExact_UOE)}
|
|
};
|
|
+static JNINativeMethod VH_methods[] = {
|
|
+ // UnsupportedOperationException throwers
|
|
+ {CC "get", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "set", CC "([" OBJ ")V", FN_PTR(VH_UOE)},
|
|
+ {CC "getVolatile", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "setVolatile", CC "([" OBJ ")V", FN_PTR(VH_UOE)},
|
|
+ {CC "getAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "setRelease", CC "([" OBJ ")V", FN_PTR(VH_UOE)},
|
|
+ {CC "getOpaque", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "setOpaque", CC "([" OBJ ")V", FN_PTR(VH_UOE)},
|
|
+ {CC "compareAndSet", CC "([" OBJ ")Z", FN_PTR(VH_UOE)},
|
|
+ {CC "compareAndExchange", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "compareAndExchangeAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "compareAndExchangeRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "weakCompareAndSetPlain", CC "([" OBJ ")Z", FN_PTR(VH_UOE)},
|
|
+ {CC "weakCompareAndSet", CC "([" OBJ ")Z", FN_PTR(VH_UOE)},
|
|
+ {CC "weakCompareAndSetAcquire", CC "([" OBJ ")Z", FN_PTR(VH_UOE)},
|
|
+ {CC "weakCompareAndSetRelease", CC "([" OBJ ")Z", FN_PTR(VH_UOE)},
|
|
+ {CC "getAndSet", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndSetAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndSetRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndAdd", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndAddAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndAddRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseOr", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseOrAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseOrRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseAnd", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseAndAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseAndRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseXor", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseXorAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)},
|
|
+ {CC "getAndBitwiseXorRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}
|
|
+};
|
|
|
|
/**
|
|
* This one function is exported, used by NativeLookup.
|
|
@@ -1408,9 +1454,12 @@ static JNINativeMethod MH_methods[] = {
|
|
JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
|
|
assert(!MethodHandles::enabled(), "must not be enabled");
|
|
assert(vmClasses::MethodHandle_klass() != nullptr, "should be present");
|
|
+ assert(vmClasses::VarHandle_klass() != nullptr, "should be present");
|
|
|
|
- oop mirror = vmClasses::MethodHandle_klass()->java_mirror();
|
|
- jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mirror);
|
|
+ oop mh_mirror = vmClasses::MethodHandle_klass()->java_mirror();
|
|
+ oop vh_mirror = vmClasses::VarHandle_klass()->java_mirror();
|
|
+ jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mh_mirror);
|
|
+ jclass VH_class = (jclass) JNIHandles::make_local(THREAD, vh_mirror);
|
|
|
|
{
|
|
ThreadToNativeFromVM ttnfv(thread);
|
|
@@ -1422,6 +1471,10 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
|
|
status = env->RegisterNatives(MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod));
|
|
guarantee(status == JNI_OK && !env->ExceptionOccurred(),
|
|
"register java.lang.invoke.MethodHandle natives");
|
|
+
|
|
+ status = env->RegisterNatives(VH_class, VH_methods, sizeof(VH_methods)/sizeof(JNINativeMethod));
|
|
+ guarantee(status == JNI_OK && !env->ExceptionOccurred(),
|
|
+ "register java.lang.invoke.VarHandle natives");
|
|
}
|
|
|
|
log_debug(methodhandles, indy)("MethodHandle support loaded (using LambdaForms)");
|
|
diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java
|
|
index 652272ca8..b20e18d26 100644
|
|
--- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java
|
|
+++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2014, 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
|
|
@@ -33,6 +33,7 @@ import java.lang.invoke.MethodHandle;
|
|
import java.lang.invoke.MethodHandleInfo;
|
|
import java.lang.invoke.MethodHandles;
|
|
import java.lang.invoke.VarHandle;
|
|
+import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.stream.Stream;
|
|
|
|
@@ -52,15 +53,33 @@ public class VarHandleTestReflection extends VarHandleBaseTest {
|
|
}
|
|
|
|
@Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class)
|
|
- public void methodInvocation(VarHandle.AccessMode accessMode) throws Exception {
|
|
+ public void methodInvocationArgumentMismatch(VarHandle.AccessMode accessMode) throws Exception {
|
|
VarHandle v = handle();
|
|
|
|
- // Try a reflective invoke using a Method
|
|
+ // Try a reflective invoke using a Method, with no arguments
|
|
|
|
Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class);
|
|
vhm.invoke(v, new Object[]{});
|
|
}
|
|
|
|
+ @Test(dataProvider = "accessModesProvider")
|
|
+ public void methodInvocationMatchingArguments(VarHandle.AccessMode accessMode) throws Exception {
|
|
+ VarHandle v = handle();
|
|
+
|
|
+ // Try a reflective invoke using a Method, with the minimal required arguments
|
|
+
|
|
+ Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class);
|
|
+ Object arg = new Object[0];
|
|
+ try {
|
|
+ vhm.invoke(v, arg);
|
|
+ } catch (InvocationTargetException e) {
|
|
+ if (!(e.getCause() instanceof UnsupportedOperationException)) {
|
|
+ throw new RuntimeException("expected UnsupportedOperationException but got: "
|
|
+ + e.getCause().getClass().getName(), e);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
@Test(dataProvider = "accessModesProvider", expectedExceptions = UnsupportedOperationException.class)
|
|
public void methodHandleInvoke(VarHandle.AccessMode accessMode) throws Throwable {
|
|
VarHandle v = handle();
|
|
--
|
|
2.33.0
|
|
|