--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed May 18 11:31:23 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Thu May 19 11:13:52 2016 +0200
@@ -41,9 +41,15 @@
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
+
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
/**
* Trusted implementation code for MethodHandle.
@@ -1155,6 +1161,8 @@
// Put the whole mess into its own nested class.
// That way we can lazily load the code and set up the constants.
private static class BindCaller {
+ private static MethodType INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
+
static
MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
// Do not use this function to inject calls into system classes.
@@ -1173,38 +1181,15 @@
}
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
- Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null);
- if (hostClass.getClassLoader() != bcc.getClassLoader())
- throw new InternalError(hostClass.getName()+" (CL)");
try {
- if (hostClass.getProtectionDomain() != bcc.getProtectionDomain())
- throw new InternalError(hostClass.getName()+" (PD)");
- } catch (SecurityException ex) {
- // Self-check was blocked by security manager. This is OK.
- // In fact the whole try body could be turned into an assertion.
- }
- try {
- MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class));
- init.invokeExact(); // force initialization of the class
- } catch (Throwable ex) {
- throw uncaughtException(ex);
- }
- MethodHandle bccInvoker;
- try {
- MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
- bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT);
+ Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, INJECTED_INVOKER_TEMPLATE, null);
+ assert checkInjectedInvoker(hostClass, invokerClass);
+ return IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
} catch (ReflectiveOperationException ex) {
throw uncaughtException(ex);
}
- // Test the invoker, to ensure that it really injects into the right place.
- try {
- MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
- Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc});
- } catch (Throwable ex) {
- throw new InternalError(ex);
- }
- return bccInvoker;
}
+
private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() {
@Override protected MethodHandle computeValue(Class<?> hostClass) {
return makeInjectedInvoker(hostClass);
@@ -1235,62 +1220,82 @@
return mh;
}
+ private static boolean checkInjectedInvoker(Class<?> hostClass, Class<?> invokerClass) {
+ assert (hostClass.getClassLoader() == invokerClass.getClassLoader()) : hostClass.getName()+" (CL)";
+ try {
+ assert (hostClass.getProtectionDomain() == invokerClass.getProtectionDomain()) : hostClass.getName()+" (PD)";
+ } catch (SecurityException ex) {
+ // Self-check was blocked by security manager. This is OK.
+ }
+ try {
+ // Test the invoker to ensure that it really injects into the right place.
+ MethodHandle invoker = IMPL_LOOKUP.findStatic(invokerClass, "invoke_V", INVOKER_MT);
+ MethodHandle vamh = prepareForInvoker(MH_checkCallerClass);
+ return (boolean)invoker.invoke(vamh, new Object[]{ invokerClass });
+ } catch (Throwable ex) {
+ throw new InternalError(ex);
+ }
+ }
+
private static final MethodHandle MH_checkCallerClass;
static {
final Class<?> THIS_CLASS = BindCaller.class;
- assert(checkCallerClass(THIS_CLASS, THIS_CLASS));
+ assert(checkCallerClass(THIS_CLASS));
try {
MH_checkCallerClass = IMPL_LOOKUP
.findStatic(THIS_CLASS, "checkCallerClass",
- MethodType.methodType(boolean.class, Class.class, Class.class));
- assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS));
+ MethodType.methodType(boolean.class, Class.class));
+ assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS));
} catch (Throwable ex) {
throw new InternalError(ex);
}
}
@CallerSensitive
- private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) {
- // This method is called via MH_checkCallerClass and so it's
- // correct to ask for the immediate caller here.
+ private static boolean checkCallerClass(Class<?> expected) {
+ // This method is called via MH_checkCallerClass and so it's correct to ask for the immediate caller here.
Class<?> actual = Reflection.getCallerClass();
- if (actual != expected && actual != expected2)
- throw new InternalError("found "+actual.getName()+", expected "+expected.getName()
- +(expected == expected2 ? "" : ", or else "+expected2.getName()));
+ if (actual != expected)
+ throw new InternalError("found " + actual.getName() + ", expected " + expected.getName());
return true;
}
- private static final byte[] T_BYTES;
- static {
- final Object[] values = {null};
- AccessController.doPrivileged(new PrivilegedAction<>() {
- public Void run() {
- try {
- Class<T> tClass = T.class;
- String tName = tClass.getName();
- String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class";
- try (java.io.InputStream in = tClass.getResourceAsStream(tResource)) {
- values[0] = in.readAllBytes();
- }
- } catch (java.io.IOException ex) {
- throw new InternalError(ex);
- }
- return null;
- }
- });
- T_BYTES = (byte[]) values[0];
- }
+ private static final byte[] INJECTED_INVOKER_TEMPLATE = generateInvokerTemplate();
+
+ /** Produces byte code for a class that is used as an injected invoker. */
+ private static byte[] generateInvokerTemplate() {
+ ClassWriter cw = new ClassWriter(0);
+
+ // private static class InjectedInvoker {
+ // @Hidden
+ // static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
+ // return vamh.invokeExact(args);
+ // }
+ // }
+ cw.visit(52, ACC_PRIVATE | ACC_SUPER, "InjectedInvoker", null, "java/lang/Object", null);
- // The following class is used as a template for Unsafe.defineAnonymousClass:
- private static class T {
- static void init() { } // side effect: initializes this class
- static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable {
- return vamh.invokeExact(args);
- }
+ MethodVisitor mv = cw.visitMethod(ACC_STATIC, "invoke_V",
+ "(Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
+ null, null);
+
+ // Suppress invoker method in stack traces.
+ AnnotationVisitor av0 = mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
+ av0.visitEnd();
+
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeExact",
+ "([Ljava/lang/Object;)Ljava/lang/Object;", false);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(2, 2);
+ mv.visitEnd();
+
+ cw.visitEnd();
+ return cw.toByteArray();
}
}
-
/** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
private static final class WrappedMember extends DelegatingMethodHandle {
private final MethodHandle target;