8004937: Improve proxy construction
authormchung
Thu, 24 Jan 2013 16:45:38 -0800
changeset 16110 2ce1c415475b
parent 16109 eb00701a5769
child 16111 5c5fc1d5bb38
8004937: Improve proxy construction Reviewed-by: jrose, ahgross
jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Jan 30 11:33:51 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Jan 24 16:45:38 2013 -0800
@@ -476,6 +476,8 @@
         case "getProxyClass":
         case "newProxyInstance":
             return defc == java.lang.reflect.Proxy.class;
+        case "asInterfaceInstance":
+            return defc == java.lang.invoke.MethodHandleProxies.class;
         case "getBundle":
         case "clearCache":
             return defc == java.util.ResourceBundle.class;
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Wed Jan 30 11:33:51 2013 +0100
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Thu Jan 24 16:45:38 2013 -0800
@@ -141,12 +141,15 @@
     <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
         if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
             throw new IllegalArgumentException("not a public interface: "+intfc.getName());
-        SecurityManager smgr = System.getSecurityManager();
-        if (smgr != null) {
+        final MethodHandle mh;
+        if (System.getSecurityManager() != null) {
             final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller
             final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME);
-            final ClassLoader ccl = caller.getClassLoader();
+            final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
             ReflectUtil.checkProxyPackageAccess(ccl, intfc);
+            mh = ccl != null ? bindCaller(target, caller) : target;
+        } else {
+            mh = target;
         }
         ClassLoader proxyLoader = intfc.getClassLoader();
         if (proxyLoader == null) {
@@ -160,7 +163,7 @@
         for (int i = 0; i < methods.length; i++) {
             Method sm = methods[i];
             MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
-            MethodHandle checkTarget = target.asType(smMT);  // make throw WMT
+            MethodHandle checkTarget = mh.asType(smMT);  // make throw WMT
             checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
             vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
         }
@@ -183,8 +186,8 @@
                 }
             };
 
-        Object proxy;
-        if (smgr != null) {
+        final Object proxy;
+        if (System.getSecurityManager() != null) {
             // sun.invoke.WrapperInstance is a restricted interface not accessible
             // by any non-null class loader.
             final ClassLoader loader = proxyLoader;
@@ -204,6 +207,16 @@
         return intfc.cast(proxy);
     }
 
+    private static MethodHandle bindCaller(MethodHandle target, Class<?> hostClass) {
+        MethodHandle cbmh = MethodHandleImpl.bindCaller(target, hostClass);
+        if (target.isVarargsCollector()) {
+            MethodType type = cbmh.type();
+            int arity = type.parameterCount();
+            return cbmh.asVarargsCollector(type.parameterType(arity-1));
+        }
+        return cbmh;
+    }
+
     /**
      * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
      * @param x any reference