提交 89470114 编写于 作者: J jrose

7054590: (JSR-292) MethodHandleProxies.asInterfaceInstance() accepts...

7054590: (JSR-292) MethodHandleProxies.asInterfaceInstance() accepts private/protected nested interfaces
Summary: fix non-compliant logic in MethodHandleProxies, fix invalid private classes in MethodHandlesTest
Reviewed-by: twisti, never
上级 33464f30
...@@ -27,6 +27,7 @@ package java.lang.invoke; ...@@ -27,6 +27,7 @@ package java.lang.invoke;
import java.lang.reflect.*; import java.lang.reflect.*;
import sun.invoke.WrapperInstance; import sun.invoke.WrapperInstance;
import java.util.ArrayList;
/** /**
* This class consists exclusively of static methods that help adapt * This class consists exclusively of static methods that help adapt
...@@ -134,14 +135,19 @@ public class MethodHandleProxies { ...@@ -134,14 +135,19 @@ public class MethodHandleProxies {
// //
public static public static
<T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) { <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
// POC implementation only; violates the above contract several ways if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
final Method sm = getSingleMethod(intfc); throw new IllegalArgumentException("not a public interface: "+intfc.getName());
if (sm == null) final Method[] methods = getSingleNameMethods(intfc);
if (methods == null)
throw new IllegalArgumentException("not a single-method interface: "+intfc.getName()); throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes()); final MethodHandle[] vaTargets = new MethodHandle[methods.length];
MethodHandle checkTarget = target.asType(smMT); // make throw WMT for (int i = 0; i < methods.length; i++) {
checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class)); Method sm = methods[i];
final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount()); MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
MethodHandle checkTarget = target.asType(smMT); // make throw WMT
checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
}
return intfc.cast(Proxy.newProxyInstance( return intfc.cast(Proxy.newProxyInstance(
intfc.getClassLoader(), intfc.getClassLoader(),
new Class[]{ intfc, WrapperInstance.class }, new Class[]{ intfc, WrapperInstance.class },
...@@ -152,13 +158,15 @@ public class MethodHandleProxies { ...@@ -152,13 +158,15 @@ public class MethodHandleProxies {
throw new AssertionError(); throw new AssertionError();
} }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
for (int i = 0; i < methods.length; i++) {
if (method.equals(methods[i]))
return vaTargets[i].invokeExact(args);
}
if (method.getDeclaringClass() == WrapperInstance.class) if (method.getDeclaringClass() == WrapperInstance.class)
return getArg(method.getName()); return getArg(method.getName());
if (method.equals(sm))
return vaTarget.invokeExact(args);
if (isObjectMethod(method)) if (isObjectMethod(method))
return callObjectMethod(this, method, args); return callObjectMethod(this, method, args);
throw new InternalError(); throw new InternalError("bad proxy method: "+method);
} }
})); }));
} }
...@@ -241,17 +249,20 @@ public class MethodHandleProxies { ...@@ -241,17 +249,20 @@ public class MethodHandleProxies {
} }
private static private static
Method getSingleMethod(Class<?> intfc) { Method[] getSingleNameMethods(Class<?> intfc) {
if (!intfc.isInterface()) return null; ArrayList<Method> methods = new ArrayList<Method>();
Method sm = null; String uniqueName = null;
for (Method m : intfc.getMethods()) { for (Method m : intfc.getMethods()) {
int mod = m.getModifiers(); if (isObjectMethod(m)) continue;
if (Modifier.isAbstract(mod)) { if (!Modifier.isAbstract(m.getModifiers())) continue;
if (sm != null && !isObjectMethod(sm)) String mname = m.getName();
return null; // too many abstract methods if (uniqueName == null)
sm = m; uniqueName = mname;
} else if (!uniqueName.equals(mname))
return null; // too many abstract methods
methods.add(m);
} }
return sm; if (uniqueName == null) return null;
return methods.toArray(new Method[methods.size()]);
} }
} }
...@@ -2234,7 +2234,7 @@ public class MethodHandlesTest { ...@@ -2234,7 +2234,7 @@ public class MethodHandlesTest {
static void runForRunnable() { static void runForRunnable() {
called("runForRunnable"); called("runForRunnable");
} }
private interface Fooable { public interface Fooable {
Object foo(Fooable x, Object y); Object foo(Fooable x, Object y);
// this is for randomArg: // this is for randomArg:
public class Impl implements Fooable { public class Impl implements Fooable {
...@@ -2249,9 +2249,9 @@ public class MethodHandlesTest { ...@@ -2249,9 +2249,9 @@ public class MethodHandlesTest {
static Object fooForFooable(Fooable x, Object y) { static Object fooForFooable(Fooable x, Object y) {
return called("fooForFooable", x, y); return called("fooForFooable", x, y);
} }
private static class MyCheckedException extends Exception { public static class MyCheckedException extends Exception {
} }
private interface WillThrow { public interface WillThrow {
void willThrow() throws MyCheckedException; void willThrow() throws MyCheckedException;
} }
...@@ -2300,8 +2300,11 @@ public class MethodHandlesTest { ...@@ -2300,8 +2300,11 @@ public class MethodHandlesTest {
assertSame("must pass declared exception out without wrapping", ex, ex1); assertSame("must pass declared exception out without wrapping", ex, ex1);
} else { } else {
assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1);
if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) {
ex1.printStackTrace();
}
assertSame(ex, ex1.getCause());
UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1;
assertSame(ex, utex.getCause());
} }
} }
} }
...@@ -2380,8 +2383,7 @@ class ValueConversions { ...@@ -2380,8 +2383,7 @@ class ValueConversions {
public static MethodHandle varargsArray(int nargs) { public static MethodHandle varargsArray(int nargs) {
if (nargs < ARRAYS.length) if (nargs < ARRAYS.length)
return ARRAYS[nargs]; return ARRAYS[nargs];
// else need to spin bytecode or do something else fancy return MethodHandles.identity(Object[].class).asCollector(Object[].class, nargs);
throw new UnsupportedOperationException("NYI: cannot form a varargs array of length "+nargs);
} }
public static MethodHandle varargsArray(Class<?> arrayType, int nargs) { public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
Class<?> elemType = arrayType.getComponentType(); Class<?> elemType = arrayType.getComponentType();
...@@ -2463,6 +2465,12 @@ class ValueConversions { ...@@ -2463,6 +2465,12 @@ class ValueConversions {
return lists.toArray(new MethodHandle[0]); return lists.toArray(new MethodHandle[0]);
} }
static final MethodHandle[] LISTS = makeLists(); static final MethodHandle[] LISTS = makeLists();
static final MethodHandle AS_LIST;
static {
try {
AS_LIST = IMPL_LOOKUP.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class));
} catch (Exception ex) { throw new RuntimeException(ex); }
}
/** Return a method handle that takes the indicated number of Object /** Return a method handle that takes the indicated number of Object
* arguments and returns List. * arguments and returns List.
...@@ -2470,8 +2478,7 @@ class ValueConversions { ...@@ -2470,8 +2478,7 @@ class ValueConversions {
public static MethodHandle varargsList(int nargs) { public static MethodHandle varargsList(int nargs) {
if (nargs < LISTS.length) if (nargs < LISTS.length)
return LISTS[nargs]; return LISTS[nargs];
// else need to spin bytecode or do something else fancy return AS_LIST.asCollector(Object[].class, nargs);
throw new UnsupportedOperationException("NYI");
} }
} }
// This guy tests access from outside the same package member, but inside // This guy tests access from outside the same package member, but inside
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册