Skip to content

Commit c6d7061

Browse files
committed
Review comments
1 parent 0d57dfe commit c6d7061

File tree

4 files changed

+93
-30
lines changed

4 files changed

+93
-30
lines changed

src/java.base/share/classes/jdk/internal/reflect/MethodHandleAccessorFactory.java

+11-25
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ static FieldAccessorImpl newFieldAccessor(Field field, boolean isReadOnly) {
210210
}
211211

212212
private static MethodHandle getDirectMethod(Method method, boolean callerSensitive) throws IllegalAccessException {
213-
var mtype = methodType(method.getReturnType(), method.getParameterTypes());
213+
var mtype = methodType(method.getReturnType(), reflectionFactory.getExecutableSharedParameterTypes(method));
214214
var isStatic = Modifier.isStatic(method.getModifiers());
215215
var dmh = isStatic ? JLIA.findStatic(method.getDeclaringClass(), method.getName(), mtype)
216216
: JLIA.findVirtual(method.getDeclaringClass(), method.getName(), mtype);
@@ -232,7 +232,7 @@ private static MethodHandle getDirectMethod(Method method, boolean callerSensiti
232232
private static MethodHandle findCallerSensitiveAdapter(Method method) throws IllegalAccessException {
233233
String name = method.getName();
234234
// append a Class parameter
235-
MethodType mtype = methodType(method.getReturnType(), method.getParameterTypes())
235+
MethodType mtype = methodType(method.getReturnType(), reflectionFactory.getExecutableSharedParameterTypes(method))
236236
.appendParameterTypes(Class.class);
237237
boolean isStatic = Modifier.isStatic(method.getModifiers());
238238

@@ -370,11 +370,15 @@ private static boolean useNativeAccessor(Executable member) {
370370
if (member instanceof Method method && isSignaturePolymorphicMethod(method))
371371
return true;
372372

373-
// java.lang.invoke fails to create MH for bad ACC_VARARGS methods with no
374-
// trailing array, but core reflection ignores ACC_VARARGS flag like the JVM does.
375-
// Fall back to use the native implementation instead.
376-
if (isInvalidVarArgs(member))
373+
// Lookup always calls MethodHandle::setVarargs on a member with ACC_VARARGS
374+
// bit set, which verifies that the last parameter of the member must be
375+
// an array type. Such restriction does not exist in core reflection
376+
// and the JVM. Fall back to use the native implementation instead.
377+
int paramCount = member.getParameterCount();
378+
if (member.isVarArgs() &&
379+
(paramCount == 0 || !(reflectionFactory.getExecutableSharedParameterTypes(member)[paramCount-1].isArray()))) {
377380
return true;
381+
}
378382

379383
// A method handle cannot be created if its type has an arity >= 255
380384
// as the method handle's invoke method consumes an extra argument
@@ -395,7 +399,7 @@ private static boolean useNativeAccessor(Executable member) {
395399
*/
396400
private static int slotCount(Executable member) {
397401
int slots = 0;
398-
Class<?>[] ptypes = member.getParameterTypes();
402+
Class<?>[] ptypes = reflectionFactory.getExecutableSharedParameterTypes(member);
399403
for (Class<?> ptype : ptypes) {
400404
if (ptype == double.class || ptype == long.class) {
401405
slots++;
@@ -430,24 +434,6 @@ public static boolean isSignaturePolymorphicMethod(Method method) {
430434
return parameters.length == 1 && parameters[0] == Object[].class;
431435
}
432436

433-
/**
434-
* Lookup always calls MethodHandle::setVarargs on a member with varargs modifier
435-
* bit set, which verifies that the last parameter of the member must be an array type.
436-
* Thus, Lookup cannot create MethodHandle for such methods or constructors.
437-
* The JVMS does not require that the last parameter descriptor of the method descriptor
438-
* is an array type if the ACC_VARARGS flag is set in the access_flags item.
439-
* Core reflection also has no variable arity support and ignores the ACC_VARARGS flag,
440-
* treating them as regular arguments.
441-
*/
442-
private static boolean isInvalidVarArgs(Executable member) {
443-
if (!member.isVarArgs())
444-
return false;
445-
446-
Class<?>[] parameters = reflectionFactory.getExecutableSharedParameterTypes(member);
447-
var count = parameters.length;
448-
return count == 0 || !parameters[count - 1].isArray();
449-
}
450-
451437
/*
452438
* Delay initializing these static fields until java.lang.invoke is fully initialized.
453439
*/

test/jdk/java/lang/invoke/MethodHandleInvokeUOE.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -21,16 +21,15 @@
2121
* questions.
2222
*/
2323

24-
/*
25-
* @test
26-
* @bug 8343377
24+
/* @test
2725
* @summary Test MethodHandle::invokeExact and MethodHandle::invoke throws
2826
* UnsupportedOperationException when called via Method::invoke
2927
* @run testng test.java.lang.invoke.MethodHandleInvokeUOE
3028
*/
3129

3230
package test.java.lang.invoke;
3331

32+
import org.testng.*;
3433
import org.testng.annotations.*;
3534

3635
import java.lang.invoke.MethodHandle;

test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
/*
2525
* @test
26-
* @bug 8335638 8343377
2726
* @run testng VarHandleTestReflection
2827
*/
2928

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package org.openjdk.bench.java.lang.reflect;
24+
25+
import org.openjdk.jmh.annotations.Benchmark;
26+
import org.openjdk.jmh.annotations.BenchmarkMode;
27+
import org.openjdk.jmh.annotations.Fork;
28+
import org.openjdk.jmh.annotations.Measurement;
29+
import org.openjdk.jmh.annotations.Mode;
30+
import org.openjdk.jmh.annotations.OutputTimeUnit;
31+
import org.openjdk.jmh.annotations.Scope;
32+
import org.openjdk.jmh.annotations.Setup;
33+
import org.openjdk.jmh.annotations.State;
34+
import org.openjdk.jmh.annotations.Warmup;
35+
import org.openjdk.jmh.infra.Blackhole;
36+
37+
import java.lang.reflect.Method;
38+
import java.util.concurrent.TimeUnit;
39+
40+
/**
41+
* Benchmark for regression in native method invocation.
42+
*/
43+
@BenchmarkMode(Mode.AverageTime)
44+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
45+
@State(Scope.Thread)
46+
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
47+
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
48+
@Fork(3)
49+
public class NativeMethodInvoke {
50+
51+
private Method objectHashCode;
52+
private Method threadCurrentThread;
53+
54+
private Object[] objects;
55+
56+
@Setup
57+
public void setup() throws ReflectiveOperationException {
58+
objects = new Object[]{
59+
1, 5L,
60+
5.6d, 23.11f,
61+
Boolean.TRUE, 'd'
62+
};
63+
64+
objectHashCode = Object.class.getDeclaredMethod("hashCode");
65+
threadCurrentThread = Thread.class.getDeclaredMethod("currentThread");
66+
}
67+
68+
@Benchmark
69+
public void objectHashCode(Blackhole bh) throws ReflectiveOperationException {
70+
for (var obj : objects) {
71+
bh.consume(objectHashCode.invoke(obj));
72+
}
73+
}
74+
75+
@Benchmark
76+
public Object threadCurrentThread() throws ReflectiveOperationException {
77+
return threadCurrentThread.invoke(null);
78+
}
79+
}

0 commit comments

Comments
 (0)