--- /dev/null	2009-02-04 23:35:02.000000000 -0800
+++ new/src/share/classes/impl/java/dyn/util/MethodHandleInvoker.java	2009-02-04 23:35:01.000000000 -0800
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package impl.java.dyn.util;
+
+import impl.java.dyn.Access;
+import impl.java.dyn.AdapterMethodHandle;
+import java.dyn.AnonymousClassLoader;
+import java.dyn.ConstantPoolParser;
+import java.dyn.ConstantPoolPatch;
+import java.dyn.ConstantPoolVisitor;
+import java.dyn.InvalidConstantPoolFormatException;
+import java.dyn.MethodHandle;
+import java.dyn.MethodHandles;
+import java.dyn.MethodType;
+import java.dyn.WrongMethodTypeException;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.IdentityHashMap;
+
+/**
+ * Emulation of method handle invocation.
+ * Not needed if javac supports direct invocation of MethodHandle.invoke.
+ * @author jrose
+ */
+public abstract
+class MethodHandleInvoker implements Cloneable {
+    private static final Access IMPL_TOKEN = Access.getToken();
+
+
+    /** Exact type for all handles targeted by this invoker. */
+    protected final MethodType exactType;
+
+    /** Condensed information about the return type, one of "VLIJFDZBSC". */
+    protected final char rtypec;
+
+    /** Adapter which converts the approximate type to the exact exactType. */
+    protected final MethodHandle adapter;
+
+    /** Maximum number of arguments allowed.
+     *  This is an implementation limit.
+     */
+    public static final int ARGUMENT_MAX;
+    /** Maximum number of double or long arguments allowed.
+     *  This is an implementation limit.
+     */
+    public static final int LONG_ARGUMENT_MAX;
+    static {
+        LONG_ARGUMENT_MAX = 3;  // %%% depends on stack headroom
+    }
+
+    public MethodType type() { return exactType; }
+
+    protected MethodHandleInvoker(MethodType exactType, MethodHandle adapter) {
+        this.exactType = exactType;
+        this.rtypec = Wrappers.basicTypeChar(exactType.returnType());
+        this.adapter = adapter;
+    }
+
+    static MethodHandle makeAdapter(MethodType exactType, MethodType approxType) {
+        // For each argument, convert incoming Object to the exact type needed.
+        int len = exactType.parameterCount();
+        assert(len == approxType.parameterCount());
+        if (exactType.parameterSlotCount() > len + LONG_ARGUMENT_MAX)
+            throw new IllegalArgumentException("too many long arguments in "+exactType);
+        MethodHandle invoker = MethodHandles.findVirtual(MethodHandle.class, "invoke", exactType);
+        MethodType adapterType = approxType.insertParameterType(0, MethodHandle.class);
+        return AdapterMethodHandle.makePairwiseConversion(IMPL_TOKEN, adapterType, invoker);
+    }
+
+    public Object invoke_0(MethodHandle mh)
+        {   throw wrongType(mh);  }
+    public Object invoke_1(MethodHandle mh, Object a0)
+        {   throw wrongType(mh);  }
+    public Object invoke_2(MethodHandle mh, Object a0, Object a1)
+        {   throw wrongType(mh);  }
+    public Object invoke_3(MethodHandle mh, Object a0, Object a1, Object a2)
+        {   throw wrongType(mh);  }
+    public Object invoke_4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3)
+        {   throw wrongType(mh);  }
+    public Object invoke_5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4)
+        {   throw wrongType(mh);  }
+    
+    /** Reflective style generic invocation.  This always delegates
+     *  to one of the invoke_X methods.
+     * @param mh method handle to invoke (must be of exactly correct type)
+     * @param args array of arguments to send to method (maybe null if empty)
+     * @return
+     */
+    final // try this...
+    public Object invoke(MethodHandle mh, Object ... args) {
+        switch (args == null ? 0 : args.length) {
+        case 0: return invoke_0(mh);
+        case 1: return invoke_1(mh, args[0]);
+        case 2: return invoke_2(mh, args[0], args[1]);
+        case 3: return invoke_3(mh, args[0], args[1], args[2]);
+        case 4: return invoke_4(mh, args[0], args[1], args[2], args[3]);
+        case 5: return invoke_5(mh, args[0], args[1], args[2], args[3], args[4]);
+        }
+        throw wrongType(mh);
+    }
+
+    // This class is not used after compile time.
+    // It is renamed away to MethodHandle itself, to call the MHI.adapter.
+    // TO DO: Update javac so we can call directly to polymorphic MH.invoke.
+    private static abstract class FakeMethodHandle extends MethodHandle {
+        public FakeMethodHandle() { super(null, null); }
+        // here are all the invokes we need to link against:
+        public abstract void   fake_invoke_V0(MethodHandle mh);
+        public abstract Object fake_invoke_L0(MethodHandle mh);
+        public abstract int    fake_invoke_I0(MethodHandle mh);
+        public abstract long   fake_invoke_J0(MethodHandle mh);
+        public abstract double fake_invoke_F0(MethodHandle mh);
+        public abstract double fake_invoke_D0(MethodHandle mh);
+        public abstract void   fake_invoke_V1(MethodHandle mh, Object a0);
+        public abstract Object fake_invoke_L1(MethodHandle mh, Object a0);
+        public abstract int    fake_invoke_I1(MethodHandle mh, Object a0);
+        public abstract long   fake_invoke_J1(MethodHandle mh, Object a0);
+        public abstract float  fake_invoke_F1(MethodHandle mh, Object a0);
+        public abstract double fake_invoke_D1(MethodHandle mh, Object a0);
+        public abstract void   fake_invoke_V2(MethodHandle mh, Object a0, Object a1);
+        public abstract Object fake_invoke_L2(MethodHandle mh, Object a0, Object a1);
+        public abstract int    fake_invoke_I2(MethodHandle mh, Object a0, Object a1);
+        public abstract long   fake_invoke_J2(MethodHandle mh, Object a0, Object a1);
+        public abstract float  fake_invoke_F2(MethodHandle mh, Object a0, Object a1);
+        public abstract double fake_invoke_D2(MethodHandle mh, Object a0, Object a1);
+        public abstract void   fake_invoke_V3(MethodHandle mh, Object a0, Object a1, Object a2);
+        public abstract Object fake_invoke_L3(MethodHandle mh, Object a0, Object a1, Object a2);
+        public abstract int    fake_invoke_I3(MethodHandle mh, Object a0, Object a1, Object a2);
+        public abstract long   fake_invoke_J3(MethodHandle mh, Object a0, Object a1, Object a2);
+        public abstract float  fake_invoke_F3(MethodHandle mh, Object a0, Object a1, Object a2);
+        public abstract double fake_invoke_D3(MethodHandle mh, Object a0, Object a1, Object a2);
+        public abstract void   fake_invoke_V4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
+        public abstract Object fake_invoke_L4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
+        public abstract int    fake_invoke_I4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
+        public abstract long   fake_invoke_J4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
+        public abstract float  fake_invoke_F4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
+        public abstract double fake_invoke_D4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3);
+        public abstract void   fake_invoke_V5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
+        public abstract Object fake_invoke_L5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
+        public abstract int    fake_invoke_I5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
+        public abstract long   fake_invoke_J5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
+        public abstract float  fake_invoke_F5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
+        public abstract double fake_invoke_D5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4);
+    }
+    private static String FMHInvokeName(MethodType approxType) {
+        assert(isFMHInvokeType(approxType)) : approxType;
+        return "fake_invoke_"
+                + Wrappers.basicTypeChar(approxType.returnType())
+                + approxType.parameterCount();
+    }
+    private static boolean isFMHInvokeType(MethodType approxType) {
+        Class<?> rtype = approxType.returnType();
+        char rtc = Wrappers.basicTypeChar(approxType.returnType());
+        if ("VIJFD".indexOf(rtc) < 0 && rtype != Object.class)
+            return false;
+        int len = approxType.parameterCount();
+        for (int i = 0; i < len; i++)
+            if (approxType.parameterType(i) != Object.class)
+                return false;
+        return true;
+    }
+
+    protected Object wrap(int value) {
+        switch (rtypec) {
+        case 'Z': return (value != 0);
+        case 'B': return (byte)value;
+        case 'S': return (short)value;
+        case 'C': return (char)value;
+        }
+        return value;
+    }
+
+    static class L0 extends MethodHandleInvoker {
+        public L0(MethodType type, MethodHandle adapter) { super(type, adapter); }
+        @Override public Object invoke_0(MethodHandle mh) {
+            checkType(mh);
+            switch (rtypec) {
+            // Note: Could unswitch this into 5 classes, but too messy.
+            case 'L': return      ((FakeMethodHandle)adapter).fake_invoke_L0(mh);
+            default:  return wrap(((FakeMethodHandle)adapter).fake_invoke_I0(mh));
+            case 'J': return      ((FakeMethodHandle)adapter).fake_invoke_J0(mh);
+            case 'F': return      ((FakeMethodHandle)adapter).fake_invoke_F0(mh);
+            case 'D': return      ((FakeMethodHandle)adapter).fake_invoke_D0(mh);
+            case 'V':             ((FakeMethodHandle)adapter).fake_invoke_V0(mh);
+            /* Here is the sort of code we will use when we get javac support:
+            case 'L': return      adapter.invoke(mh);
+            default:  return wrap(adapter.<int>invoke(mh));
+            case 'J': return      adapter.<long>invoke(mh);
+            case 'F': return      adapter.<float>invoke(mh);
+            case 'D': return      adapter.<double>invoke(mh);
+            case 'V':             adapter.<void>invoke(mh);
+             */
+            }
+            return null;
+        }
+    }
+
+    static class L1 extends MethodHandleInvoker {
+        public L1(MethodType type, MethodHandle adapter) { super(type, adapter); }
+        @Override public Object invoke_1(MethodHandle mh, Object a0) {
+            checkType(mh);
+            switch (rtypec) {
+            case 'L': return      ((FakeMethodHandle)adapter).fake_invoke_L1(mh, a0);
+            default:  return wrap(((FakeMethodHandle)adapter).fake_invoke_I1(mh, a0));
+            case 'J': return      ((FakeMethodHandle)adapter).fake_invoke_J1(mh, a0);
+            case 'F': return      ((FakeMethodHandle)adapter).fake_invoke_F1(mh, a0);
+            case 'D': return      ((FakeMethodHandle)adapter).fake_invoke_D1(mh, a0);
+            case 'V':             ((FakeMethodHandle)adapter).fake_invoke_V1(mh, a0);
+            }
+            return null;
+        }
+    }
+
+    static class L2 extends MethodHandleInvoker {
+        public L2(MethodType type, MethodHandle adapter) { super(type, adapter); }
+        @Override public Object invoke_2(MethodHandle mh, Object a0, Object a1) {
+            checkType(mh);
+            switch (rtypec) {
+            case 'L': return      ((FakeMethodHandle)adapter).fake_invoke_L2(mh, a0, a1);
+            default:  return wrap(((FakeMethodHandle)adapter).fake_invoke_I2(mh, a0, a1));
+            case 'J': return      ((FakeMethodHandle)adapter).fake_invoke_J2(mh, a0, a1);
+            case 'F': return      ((FakeMethodHandle)adapter).fake_invoke_F2(mh, a0, a1);
+            case 'D': return      ((FakeMethodHandle)adapter).fake_invoke_D2(mh, a0, a1);
+            case 'V':             ((FakeMethodHandle)adapter).fake_invoke_V2(mh, a0, a1);
+            }
+            return null;
+        }
+    }
+
+    static class L3 extends MethodHandleInvoker {
+        public L3(MethodType type, MethodHandle adapter) { super(type, adapter); }
+        @Override public Object invoke_3(MethodHandle mh, Object a0, Object a1, Object a2) {
+            checkType(mh);
+            switch (rtypec) {
+            case 'L': return      ((FakeMethodHandle)adapter).fake_invoke_L3(mh, a0, a1, a2);
+            default:  return wrap(((FakeMethodHandle)adapter).fake_invoke_I3(mh, a0, a1, a2));
+            case 'J': return      ((FakeMethodHandle)adapter).fake_invoke_J3(mh, a0, a1, a2);
+            case 'F': return      ((FakeMethodHandle)adapter).fake_invoke_F3(mh, a0, a1, a2);
+            case 'D': return      ((FakeMethodHandle)adapter).fake_invoke_D3(mh, a0, a1, a2);
+            case 'V':             ((FakeMethodHandle)adapter).fake_invoke_V3(mh, a0, a1, a2);
+            }
+            return null;
+        }
+    }
+
+    static class L4 extends MethodHandleInvoker {
+        public L4(MethodType type, MethodHandle adapter) { super(type, adapter); }
+        @Override public Object invoke_4(MethodHandle mh, Object a0, Object a1, Object a2, Object a3) {
+            checkType(mh);
+            switch (rtypec) {
+            case 'L': return      ((FakeMethodHandle)adapter).fake_invoke_L4(mh, a0, a1, a2, a3);
+            default:  return wrap(((FakeMethodHandle)adapter).fake_invoke_I4(mh, a0, a1, a2, a3));
+            case 'J': return      ((FakeMethodHandle)adapter).fake_invoke_J4(mh, a0, a1, a2, a3);
+            case 'F': return      ((FakeMethodHandle)adapter).fake_invoke_F4(mh, a0, a1, a2, a3);
+            case 'D': return      ((FakeMethodHandle)adapter).fake_invoke_D4(mh, a0, a1, a2, a3);
+            case 'V':             ((FakeMethodHandle)adapter).fake_invoke_V4(mh, a0, a1, a2, a3);
+            }
+            return null;
+        }
+    }
+
+    static class L5 extends MethodHandleInvoker {
+        public L5(MethodType type, MethodHandle adapter) { super(type, adapter); }
+        @Override public Object invoke_5(MethodHandle mh, Object a0, Object a1, Object a2, Object a3, Object a4) {
+            checkType(mh);
+            switch (rtypec) {
+            case 'L': return      ((FakeMethodHandle)adapter).fake_invoke_L5(mh, a0, a1, a2, a3, a4);
+            default:  return wrap(((FakeMethodHandle)adapter).fake_invoke_I5(mh, a0, a1, a2, a3, a4));
+            case 'J': return      ((FakeMethodHandle)adapter).fake_invoke_J5(mh, a0, a1, a2, a3, a4);
+            case 'F': return      ((FakeMethodHandle)adapter).fake_invoke_F5(mh, a0, a1, a2, a3, a4);
+            case 'D': return      ((FakeMethodHandle)adapter).fake_invoke_D5(mh, a0, a1, a2, a3, a4);
+            case 'V':             ((FakeMethodHandle)adapter).fake_invoke_V5(mh, a0, a1, a2, a3, a4);
+            }
+            return null;
+        }
+    }
+
+    private static Class<?>[] L_CLASSES
+        = { L0.class, L1.class, L2.class, L3.class, L4.class, L5.class };
+    static { ARGUMENT_MAX = L_CLASSES.length + 1; }
+
+    public static MethodHandleInvoker make(MethodType type) {
+        MethodHandleInvoker inv = null;
+        synchronized (invokers) {
+            inv = invokers.get(type);
+        }
+        if (inv != null)  return inv;
+        inv = makeNew(type);
+        synchronized (invokers) {
+            MethodHandleInvoker inv2 = invokers.get(type);
+            if (inv2 == null)
+                invokers.put(type, inv);
+            else
+                inv = inv2;
+        }
+        System.out.println("new invoker: "+inv);
+        return inv;
+    }
+
+    static MethodType approxType(MethodType exactType) {
+        int len = exactType.parameterCount();
+        if (len > ARGUMENT_MAX)
+            throw new IllegalArgumentException("too many arguments for invoker: "+exactType);
+        // The JVM can insert casts and unboxing for us in a native adapter.
+        MethodType approxType = MethodType.makeGeneric(len);
+        // But the return type must be exact, except for subword types.
+        // Convert subwords to int, since the JVM an narrow them back down.
+        Class<?> rtype = exactType.returnType();
+        switch (Wrappers.basicTypeChar(rtype)) {
+        case 'L':
+            rtype = Object.class; break;
+        case 'Z': case 'B': case 'S': case 'C':
+            rtype = int.class; break;
+        }
+        approxType = approxType.changeReturnType(rtype);
+        return approxType;
+    }
+
+    private static MethodHandleInvoker makeNew(MethodType exactType) {
+        MethodHandleInvoker inv = null;
+        Exception ex1 = null;
+        MethodType approxType = approxType(exactType);
+        MethodHandle adapter = makeAdapter(exactType, approxType);
+        Class<? extends MethodHandleInvoker> template = null;
+        Class<? extends MethodHandleInvoker> instance = null;
+        Constructor<? extends MethodHandleInvoker> constr = null;
+        template = L_CLASSES[approxType.parameterCount()].asSubclass(MethodHandleInvoker.class);
+        {
+            try {
+                instance = expandTemplate(template, approxType, exactType);
+                // When we get rid of the fakery, it will be just
+                // constr = template.getConstructor
+                constr = instance.getConstructor(MethodType.class, MethodHandle.class);
+                inv = constr.newInstance(exactType, adapter);
+            } catch (IOException ex) {
+                ex1 = ex;
+            } catch (InvalidConstantPoolFormatException ex) {
+                ex1 = ex;
+            } catch (InstantiationException ex) {
+                ex1 = ex;
+            } catch (IllegalAccessException ex) {
+                ex1 = ex;
+            } catch (NoSuchMethodException ex) {
+                ex1 = ex;
+            } catch (IllegalArgumentException ex) {
+                ex1 = ex;
+            } catch (InvocationTargetException ex) {
+                ex1 = ex;
+            }
+        }
+        if (inv == null) {
+            printex(ex1);
+            throw new InternalError();
+        }
+        return inv;
+    }
+    private static void printex(Exception ex) {
+        System.out.println("*** Unexpected exception in "+MethodHandleInvoker.class);
+        System.out.println(ex);
+        ex.printStackTrace(System.out);
+    }
+
+    private static final AnonymousClassLoader LOADER
+            = new AnonymousClassLoader(MethodHandleInvoker.class);
+
+    private static String utf8Name(Class<?> cls) {
+        return cls.getName().replace('.', '/');
+    }
+
+    private static class TemplateExpander extends ConstantPoolVisitor {
+        ConstantPoolParser cp;
+        ConstantPoolPatch patch;
+
+        // Pairs of strings to be rewritten:
+        String fakeMHName = utf8Name(FakeMethodHandle.class);
+        String realMHName = utf8Name(MethodHandle.class);
+        boolean didMHName;
+
+        String fakeInvokeName, realInvokeName = "invoke";
+        boolean didInvokeName;
+
+        @Override
+        public void visitUTF8(int index, byte tag, String utf8) {
+            String orig = utf8;
+            if (utf8.equals(fakeMHName)) {
+                utf8 = realMHName; didMHName = true;
+            }
+            if (utf8.equals(fakeInvokeName)) {
+                utf8 = realInvokeName; didInvokeName = true;
+            }
+            if ((Object)utf8 != orig)
+                patch.putUTF8(index, utf8);
+        }
+
+        public TemplateExpander(Class<? extends MethodHandleInvoker> template,
+                                MethodType approxType, MethodType exactType)
+                throws IOException, InvalidConstantPoolFormatException {
+            // construct a descriptor of something like:
+            //   int fake_invoke_I2(MethodHandle, Object, Object);
+            fakeInvokeName = FMHInvokeName(approxType);
+            cp = new ConstantPoolParser(template);
+            patch = cp.createPatch();
+            cp.parse(this);
+            if (!(didMHName && didInvokeName))
+                throw new RuntimeException("utf8 rewrites failed: "
+                    +(!didMHName?"":fakeMHName)+(!didInvokeName?"":fakeInvokeName));
+        }
+    }
+
+    static final IdentityHashMap<MethodType,MethodHandleInvoker> invokers
+            = new IdentityHashMap<MethodType, MethodHandleInvoker>();
+
+    private static Class<? extends MethodHandleInvoker>
+            expandTemplate(Class<? extends MethodHandleInvoker> template,
+                           MethodType approxType, MethodType exactType)
+                           throws IOException, InvalidConstantPoolFormatException {
+        TemplateExpander tex = new TemplateExpander(template, approxType, exactType);
+        return LOADER.loadClass(tex.patch).asSubclass(MethodHandleInvoker.class);
+    }
+
+    /** Throw this if a bad entry point is taken. */
+    protected RuntimeException wrongType(MethodHandle mh) {
+        return new WrongMethodTypeException("wrong call type for "+mh+
+                " should be "+exactType+" in "+this);
+    }
+    protected void checkType(MethodHandle mh) {
+        if (mh.type() != exactType)
+            throw wrongType(mh);
+    }
+}
