jdk/src/share/classes/sun/dyn/MethodHandleImpl.java
changeset 5725 16c1792b2ee6
parent 5506 202f599c92aa
parent 5723 a58a0eed34b0
child 7052 963a5baf2ba3
--- a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java	Thu Jun 17 16:28:11 2010 -0700
+++ b/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java	Fri Jun 18 15:23:57 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2010, 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
@@ -127,7 +127,7 @@
 
     public static void initLookup(Access token, Lookup lookup) {
         Access.check(token);
-        if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != null)
+        if (IMPL_LOOKUP_INIT != null)
             throw new InternalError();
         IMPL_LOOKUP_INIT = lookup;
     }
@@ -176,28 +176,164 @@
             boolean doDispatch, Class<?> lookupClass) {
         Access.check(token);  // only trusted calls
         MethodType mtype = method.getMethodType();
-        MethodType rtype = mtype;
-        if (method.isStatic()) {
-            doDispatch = false;
-        } else {
+        if (!method.isStatic()) {
             // adjust the advertised receiver type to be exactly the one requested
             // (in the case of invokespecial, this will be the calling class)
             Class<?> recvType = method.getDeclaringClass();
             mtype = mtype.insertParameterTypes(0, recvType);
-            if (method.isConstructor())
-                doDispatch = true;
-            // FIXME: JVM has trouble building MH.invoke sites for
-            // classes off the boot class path
-            rtype = mtype;
-            if (recvType.getClassLoader() != null)
-                rtype = rtype.changeParameterType(0, Object.class);
         }
         DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
         if (!mh.isValid())
             throw newNoAccessException(method, lookupClass);
-        MethodHandle rmh = AdapterMethodHandle.makePairwiseConvert(token, rtype, mh);
-        if (rmh == null)  throw new InternalError();
-        return rmh;
+        assert(mh.type() == mtype);
+        return mh;
+    }
+
+    public static
+    MethodHandle makeAllocator(Access token, MethodHandle rawConstructor) {
+        Access.check(token);
+        MethodType rawConType = rawConstructor.type();
+        // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
+        MethodHandle allocator
+            = AllocateObject.make(token, rawConType.parameterType(0), rawConstructor);
+        assert(allocator.type()
+               .equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
+        return allocator;
+    }
+
+    static final class AllocateObject<C> extends JavaMethodHandle {
+        private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+        private final Class<C> allocateClass;
+        private final MethodHandle rawConstructor;
+
+        private AllocateObject(MethodHandle invoker,
+                               Class<C> allocateClass, MethodHandle rawConstructor) {
+            super(invoker);
+            this.allocateClass = allocateClass;
+            this.rawConstructor = rawConstructor;
+        }
+        static MethodHandle make(Access token,
+                                 Class<?> allocateClass, MethodHandle rawConstructor) {
+            Access.check(token);
+            MethodType rawConType = rawConstructor.type();
+            assert(rawConType.parameterType(0) == allocateClass);
+            MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
+            int nargs = rawConType.parameterCount() - 1;
+            if (nargs < INVOKES.length) {
+                MethodHandle invoke = INVOKES[nargs];
+                MethodType conType = CON_TYPES[nargs];
+                MethodHandle gcon = convertArguments(token, rawConstructor, conType, rawConType, null);
+                if (gcon == null)  return null;
+                MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
+                assert(galloc.type() == newType.generic());
+                return convertArguments(token, galloc, newType, galloc.type(), null);
+            } else {
+                MethodHandle invoke = VARARGS_INVOKE;
+                MethodType conType = CON_TYPES[nargs];
+                MethodHandle gcon = spreadArguments(token, rawConstructor, conType, 1);
+                if (gcon == null)  return null;
+                MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
+                return collectArguments(token, galloc, newType, 1, null);
+            }
+        }
+        @Override
+        public String toString() {
+            return allocateClass.getSimpleName();
+        }
+        @SuppressWarnings("unchecked")
+        private C allocate() throws InstantiationException {
+            return (C) unsafe.allocateInstance(allocateClass);
+        }
+        private C invoke_V(Object... av) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, av);
+            return obj;
+        }
+        private C invoke_L0() throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj);
+            return obj;
+        }
+        private C invoke_L1(Object a0) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0);
+            return obj;
+        }
+        private C invoke_L2(Object a0, Object a1) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1);
+            return obj;
+        }
+        private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2);
+            return obj;
+        }
+        private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3);
+            return obj;
+        }
+        private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4);
+            return obj;
+        }
+        private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
+            return obj;
+        }
+        private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
+            return obj;
+        }
+        private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
+            C obj = allocate();
+            rawConstructor.<void>invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
+            return obj;
+        }
+        static MethodHandle[] makeInvokes() {
+            ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
+            MethodHandles.Lookup lookup = IMPL_LOOKUP;
+            for (;;) {
+                int nargs = invokes.size();
+                String name = "invoke_L"+nargs;
+                MethodHandle invoke = null;
+                try {
+                    invoke = lookup.findVirtual(AllocateObject.class, name, MethodType.genericMethodType(nargs));
+                } catch (NoAccessException ex) {
+                }
+                if (invoke == null)  break;
+                invokes.add(invoke);
+            }
+            assert(invokes.size() == 9);  // current number of methods
+            return invokes.toArray(new MethodHandle[0]);
+        };
+        static final MethodHandle[] INVOKES = makeInvokes();
+        // For testing use this:
+        //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
+        static final MethodHandle VARARGS_INVOKE;
+        static {
+            try {
+                VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
+            } catch (NoAccessException ex) {
+                throw new InternalError("");
+            }
+        }
+        // Corresponding generic constructor types:
+        static final MethodType[] CON_TYPES = new MethodType[INVOKES.length];
+        static {
+            for (int i = 0; i < INVOKES.length; i++)
+                CON_TYPES[i] = makeConType(INVOKES[i]);
+        }
+        static final MethodType VARARGS_CON_TYPE = makeConType(VARARGS_INVOKE);
+        static MethodType makeConType(MethodHandle invoke) {
+            MethodType invType = invoke.type();
+            return invType.changeParameterType(0, Object.class).changeReturnType(void.class);
+        }
     }
 
     public static
@@ -469,6 +605,7 @@
                                                 MethodType oldType,
                                                 int[] permutationOrNull) {
         Access.check(token);
+        assert(oldType.parameterCount() == target.type().parameterCount());
         if (permutationOrNull != null) {
             int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
             if (permutationOrNull.length != outargs)
@@ -781,69 +918,93 @@
 
     private static class GuardWithTest extends JavaMethodHandle {
         private final MethodHandle test, target, fallback;
-        public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
-            this(INVOKES[target.type().parameterCount()], test, target, fallback);
-        }
-        public GuardWithTest(MethodHandle invoker,
-                             MethodHandle test, MethodHandle target, MethodHandle fallback) {
+        private GuardWithTest(MethodHandle invoker,
+                              MethodHandle test, MethodHandle target, MethodHandle fallback) {
             super(invoker);
             this.test = test;
             this.target = target;
             this.fallback = fallback;
         }
+        static MethodHandle make(Access token,
+                                 MethodHandle test, MethodHandle target, MethodHandle fallback) {
+            Access.check(token);
+            MethodType type = target.type();
+            int nargs = type.parameterCount();
+            if (nargs < INVOKES.length) {
+                MethodHandle invoke = INVOKES[nargs];
+                MethodType gtype = type.generic();
+                assert(invoke.type().dropParameterTypes(0,1) == gtype);
+                MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
+                MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
+                MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
+                if (gtest == null || gtarget == null || gfallback == null)  return null;
+                MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
+                return convertArguments(token, gguard, type, gtype, null);
+            } else {
+                MethodHandle invoke = VARARGS_INVOKE;
+                MethodType gtype = MethodType.genericMethodType(1);
+                assert(invoke.type().dropParameterTypes(0,1) == gtype);
+                MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0);
+                MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
+                MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0);
+                MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
+                if (gtest == null || gtarget == null || gfallback == null)  return null;
+                return collectArguments(token, gguard, type, 0, null);
+            }
+        }
         @Override
         public String toString() {
             return target.toString();
         }
         private Object invoke_V(Object... av) throws Throwable {
-            if (test.<boolean>invoke(av))
-                return target.<Object>invoke(av);
-            return fallback.<Object>invoke(av);
+            if (test.<boolean>invokeExact(av))
+                return target.<Object>invokeExact(av);
+            return fallback.<Object>invokeExact(av);
         }
         private Object invoke_L0() throws Throwable {
-            if (test.<boolean>invoke())
-                return target.<Object>invoke();
-            return fallback.<Object>invoke();
+            if (test.<boolean>invokeExact())
+                return target.<Object>invokeExact();
+            return fallback.<Object>invokeExact();
         }
         private Object invoke_L1(Object a0) throws Throwable {
-            if (test.<boolean>invoke(a0))
-                return target.<Object>invoke(a0);
-            return fallback.<Object>invoke(a0);
+            if (test.<boolean>invokeExact(a0))
+                return target.<Object>invokeExact(a0);
+            return fallback.<Object>invokeExact(a0);
         }
         private Object invoke_L2(Object a0, Object a1) throws Throwable {
-            if (test.<boolean>invoke(a0, a1))
-                return target.<Object>invoke(a0, a1);
-            return fallback.<Object>invoke(a0, a1);
+            if (test.<boolean>invokeExact(a0, a1))
+                return target.<Object>invokeExact(a0, a1);
+            return fallback.<Object>invokeExact(a0, a1);
         }
         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
-            if (test.<boolean>invoke(a0, a1, a2))
-                return target.<Object>invoke(a0, a1, a2);
-            return fallback.<Object>invoke(a0, a1, a2);
+            if (test.<boolean>invokeExact(a0, a1, a2))
+                return target.<Object>invokeExact(a0, a1, a2);
+            return fallback.<Object>invokeExact(a0, a1, a2);
         }
         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
-            if (test.<boolean>invoke(a0, a1, a2, a3))
-                return target.<Object>invoke(a0, a1, a2, a3);
-            return fallback.<Object>invoke(a0, a1, a2, a3);
+            if (test.<boolean>invokeExact(a0, a1, a2, a3))
+                return target.<Object>invokeExact(a0, a1, a2, a3);
+            return fallback.<Object>invokeExact(a0, a1, a2, a3);
         }
         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
-            if (test.<boolean>invoke(a0, a1, a2, a3, a4))
-                return target.<Object>invoke(a0, a1, a2, a3, a4);
-            return fallback.<Object>invoke(a0, a1, a2, a3, a4);
+            if (test.<boolean>invokeExact(a0, a1, a2, a3, a4))
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4);
+            return fallback.<Object>invokeExact(a0, a1, a2, a3, a4);
         }
         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
-            if (test.<boolean>invoke(a0, a1, a2, a3, a4, a5))
-                return target.<Object>invoke(a0, a1, a2, a3, a4, a5);
-            return fallback.<Object>invoke(a0, a1, a2, a3, a4, a5);
+            if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5))
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
+            return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
         }
         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
-            if (test.<boolean>invoke(a0, a1, a2, a3, a4, a5, a6))
-                return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
-            return fallback.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
+            if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6))
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
+            return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
         }
         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
-            if (test.<boolean>invoke(a0, a1, a2, a3, a4, a5, a6, a7))
-                return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
-            return fallback.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
+            if (test.<boolean>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
+            return fallback.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
         }
         static MethodHandle[] makeInvokes() {
             ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
@@ -880,26 +1041,7 @@
                                    MethodHandle test,
                                    MethodHandle target,
                                    MethodHandle fallback) {
-        Access.check(token);
-        MethodType type = target.type();
-        int nargs = type.parameterCount();
-        if (nargs < GuardWithTest.INVOKES.length) {
-            MethodType gtype = type.generic();
-            MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
-            MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
-            MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
-            if (gtest == null || gtarget == null || gfallback == null)  return null;
-            MethodHandle gguard = new GuardWithTest(gtest, gtarget, gfallback);
-            return convertArguments(token, gguard, type, gtype, null);
-        } else {
-            MethodType gtype = MethodType.genericMethodType(0, true);
-            MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0);
-            MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
-            MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0);
-            MethodHandle gguard = new GuardWithTest(GuardWithTest.VARARGS_INVOKE, gtest, gtarget, gfallback);
-            if (gtest == null || gtarget == null || gfallback == null)  return null;
-            return collectArguments(token, gguard, type, 0, null);
-        }
+        return GuardWithTest.make(token, test, target, fallback);
     }
 
     private static class GuardWithCatch extends JavaMethodHandle {
@@ -922,82 +1064,82 @@
         }
         private Object invoke_V(Object... av) throws Throwable {
             try {
-                return target.<Object>invoke(av);
+                return target.<Object>invokeExact(av);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, av);
+                return catcher.<Object>invokeExact(t, av);
             }
         }
         private Object invoke_L0() throws Throwable {
             try {
-                return target.<Object>invoke();
+                return target.<Object>invokeExact();
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t);
+                return catcher.<Object>invokeExact(t);
             }
         }
         private Object invoke_L1(Object a0) throws Throwable {
             try {
-                return target.<Object>invoke(a0);
+                return target.<Object>invokeExact(a0);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0);
+                return catcher.<Object>invokeExact(t, a0);
             }
         }
         private Object invoke_L2(Object a0, Object a1) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1);
+                return target.<Object>invokeExact(a0, a1);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1);
+                return catcher.<Object>invokeExact(t, a0, a1);
             }
         }
         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1, a2);
+                return target.<Object>invokeExact(a0, a1, a2);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1, a2);
+                return catcher.<Object>invokeExact(t, a0, a1, a2);
             }
         }
         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1, a2, a3);
+                return target.<Object>invokeExact(a0, a1, a2, a3);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1, a2, a3);
+                return catcher.<Object>invokeExact(t, a0, a1, a2, a3);
             }
         }
         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1, a2, a3, a4);
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1, a2, a3, a4);
+                return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4);
             }
         }
         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1, a2, a3, a4, a5);
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5);
+                return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5);
             }
         }
         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6);
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5, a6);
+                return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
             }
         }
         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
             try {
-                return target.<Object>invoke(a0, a1, a2, a3, a4, a5, a6, a7);
+                return target.<Object>invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
             } catch (Throwable t) {
                 if (!exType.isInstance(t))  throw t;
-                return catcher.<Object>invoke(t, a0, a1, a2, a3, a4, a5, a6, a7);
+                return catcher.<Object>invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
             }
         }
         static MethodHandle[] makeInvokes() {
@@ -1106,4 +1248,14 @@
             throw new InternalError("unexpected code "+code+": "+message);
         }
     }
+
+    // Linkage support:
+    public static void registerBootstrap(Access token, Class<?> callerClass, MethodHandle bootstrapMethod) {
+        Access.check(token);
+        MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
+    }
+    public static MethodHandle getBootstrap(Access token, Class<?> callerClass) {
+        Access.check(token);
+        return MethodHandleNatives.getBootstrap(callerClass);
+    }
 }